Currently I am trying to parse an xml string that I already have (no web calls needed). My app is native iPhone in Objective-C. I have set up an NSXMLParser delegate class which uses initWithData:xmlData. For some reason, the first and only callback on my delegate is to parser: parseErrorOccurred with the following text:
"Unable to download content from web site (Error code 5 )"
Obviously, this makes no sense since I don't ask for anything from the web. Might it still be using some private URL property to call out for something?
Here is some code:
Delegate Class XmlParser:
- (void)parseXmlString:(NSString *)xml parseError:(NSError **)error {
DEBUG_NSLog(#"XML Parser: Called with string: %#", xml);
NSData *xmlData = [xml dataUsingEncoding:NSASCIIStringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
if (parser != nil) {
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
NSError *parseError = [parser parserError];
if (parseError && error) {
*error = parseError;
}
[parser release];
}
}
Called from:
XmlParser *parser = [[XmlParser alloc] init];
NSError *error = nil;
[parser parseXmlString:aString parseError:&error];
if (error) {
DEBUG_NSLog(#"ERROR FROM PARSER");
}
where aString is an NSString containing XML (note: without header).
Error callback that is called:
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unable to download content from web site (Error code %i )", [parseError code]];
DEBUG_NSLog(#"XML Parser ERROR: %#", errorString);
[parser abortParsing];
}
When the code is run, the parseErrorOccurred hits immediately after [parser parse], and yes, I have implemented each of the didStartDocument, didEndDocument, etc.
Thanks!
UPDATE:
In debugging it seems that the xmlData object that I create is 0 bytes, even though the xml string I pass in to dataUsingEncoding has plenty of data. Is the encoding the issue?
One of the xml elements contains nested html. I'm thinking that the "s and &'s could be a problem. Hopefully doing a "->\" will fix it.
Neither escaping the quotes or replacing any &s with & fixed the problem. Could there be something wrong with having a tag in the string?
Your error message is hiding the actual error. Your xmlstring appears to be invalid as the error code is "Error code 5". See this other SO question. NSXMLparser errorcode 5
Update
When creating your xmlData instance use NSUTF8StringEncoding instead of NSASCIIStringEncoding
If that stil fails, post the actual string. Passing an empty data object to the parser is causing the error.
I tried above code with a sample XML DATA - it works great. It look like there is some issue with XML data you pass to the function.
Check your XML data or share your xml input for further analysis...
You cannot use <> characters in xml. Replace them with:
< = <
> = >
When dealing with XML the first parsing error is always fatal. If there is a parsing error, its not valid XML.
You should encode the raw HTML into HTML entities. Having raw HTML (from a user or third party source) zipping around in an app is considered a Bad Idea™.
Related
I load XML response from a server and parsed using NSXMLParser. No error in the simulator. But shows NSXMLParserErrorDomain Code=5 in iPhone.
NSString *settings = "http://website.com/settings";
NSURL *url = [NSURL URLWithString:settings];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
xmlParser.delegate = self;
BOOL success = [xmlParser parse];
if(success)
{
NSLog(#"Parse Success");
}else{
NSLog(#"Parse Failure");
NSLog(#"Parse Error: %#",[xmlParser parserError]);
}
XML Response
<?xml version="1.0" encoding="utf-8"?>
<Settings>
<AutoRefereshTime>10</AutoRefereshTime>
<CashierPasswordRequired>Y</CashierPasswordRequired>
<CheckoutTableColor>#FFFF00</CheckoutTableColor>
<CompanyLogo>http://website.com/UCS_WS/Images/Logo/Logo.png</CompanyLogo>
<CompanyName>UnoRestaurant</CompanyName>
<ConfirmedTableColor>008ED5</ConfirmedTableColor>
<Description>The Great Indian Restaurant</Description>
<DevelopedBy>Unipro</DevelopedBy>
<HoldTableColor>A02325</HoldTableColor>
<ImageURL>http://rwebsite.com/UCS_WS/Images/Dish/</ImageURL>
<isCategoryEnabled>Y</isCategoryEnabled>
<isOtherLanguageEnabled>Y</isOtherLanguageEnabled>
<NormalTableColor>#0000FF</NormalTableColor>
<OrderScreenView>POS View</OrderScreenView>
<OtherLanguage>Tamil</OtherLanguage>
<SharedTableColor>#00FFFF</SharedTableColor>
</Settings>
Parse Error:
Error Domain=NSXMLParserErrorDomain Code=5 "The operation couldn’t be completed. (NSXMLParserErrorDomain error 5.)"
Refer the answer given by #mobibob here==> What is the meaning of NSXMLParserErrorDomain error 5.?
According to Dave DeLong,
That means it's having issues parsing your file.
I think it may be the XSLT reference in the XML - as it points to the webserver. I will review and get back to this question with an improved answer.
It was the path of the file. My code wasn't even close to the right location -- and I was missing a trailing letter 's'. The error code definition implies a "premature end of file", which caused me to truncate my file without any success. I then went back to basics and iterated on the file system to look for my file.
I debugged by using the NSFileManager to iterate to my file and then verified that it was loadable with the contentsAtPath method. I was able to dump it with NSLog(). Once I was convinced that the file was well-formed and loaded in raw form, I made certain that my NSURL was constructed with the same syntax and methods. Then it loaded correctly. Now I can load either a network file "full-featured" content or a local "sample" content.
NSDirectoryEnumerator *dirEnumerator = [[NSFileManager defaultManager] enumeratorAtPath: NSHomeDirectory()];
NSString *something;
NSString *f;
while( something = [dirEnumerator nextObject] ) {
f = [[[NSString alloc] initWithFormat: #"%#/%#", NSHomeDirectory(), something] autorelease];
if( [f hasSuffix :#"two_cookies.xml"] ){
NSData *nsData = (NSData*) [[NSFileManager defaultManager] contentsAtPath: f];
NSLog(#"%#", nsData );
}
}
Output
2009-10-22 00:47:40.147 MyApp[13843:20b]
I wanted to do validation of xml in objective c. Is there any provision or way in objective c to check whether the given xml is valid or not ?
Use NSXMLDocument for this:
NSError *err;
NSXMLDocument *xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:furl options:(NSXMLDocumentValidate | NSXMLNodePreserveAll)
error:&err];
BOOL vaildXML = [xmlDoc validateAndReturnError:&err];
NSLog(#"Error : %#",[err description]);
For ios use NSXMLParser
It will not crash, if NSXMLParser finds an error, it will let you know through its delegate, either by invoking parser:validationErrorOccurred: or – parser:parseErrorOccurred:. You can use the - (NSError *)parserError in NSXMLParser to determine the error wich caused the parsing to terminate.
Here is a method , and the library.
You can also validate XML using the following unix command:
xmllint --noout --schema test.xsd test.xml
EDIT:
Try the following code:
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithData:urlData options:0 error:&error];
NSArray* tempArray = [doc nodesForXPath:#"path/to/the/xml" error:&error];
I hope this helps.
I access a RESTFUL url and get back results. The results are in JSON. I turn the response into a string via:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *json = [[NSString alloc] initWithBytes:[self.receivedData mutableBytes] length:[self.receivedData length] encoding:NSUTF8StringEncoding];
The json variable has a value of 0x0. When I mouse over it, I see <Invalid CFStringRef>. How can I debug this to tell why it is invalid? I render the JSON given back through the browser in A JSON parser. That checks out fine.
Results are given back by entering an ID in the URL. Other IDs return results without issue. The result set is fairly large.
First I would use initWithData:encoding: to setup the NSString. Small difference, but that method is there for a reason.
Then, I would do a hexdump of self.receivedData to see what is actually in there. If that data is not properly UTF8 encoded then the initWithData:encoding: will fail.
(Google for NSData hex dump to find other people's utility functions to do this)
I have found that sometimes web services are sloppy with their encoding. So I usually implement a fallback like this:
NSString* html = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
if (html == nil) {
html = [[NSString alloc] initWithData: data encoding: NSISOLatin1StringEncoding];
if (html == nil) {
html = [[NSString alloc] initWithData: data encoding: NSMacOSRomanStringEncoding];
}
}
It is kind of sad that this is required but many web services are not written or configured properly.
Use NSLog to look at the bytes.
I'm parsing an xml from an url, by
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[rssParser parse]
How to NSLog it so as to see the xml in console??? If i use
NSLog ("%#",rssParser);
i'm showed wit 'XMLParser x 4d562' in the console
You should set parser's delegate and process retrieved xml data in its methods. See NSXMLParserDelegate protocol reference.
You can't. The NSXMLParser class never loads the entire contents of the XML stream in memory at once (that's why it's an "NSXMLParser" and not an "NSXMLDocument"). You should download the data from the URL, and use it to instantiate your RSS parser, and also to create an NSString that you log instead:
NSData *data = [NSData dataWithContentsOfURL:xmlURL];
rssParser = [[NSXMLParser alloc] initWithData:data];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"data: %#", string);
[string release];
Please pay attention to the fact that the "initWithContentsOfURL:" methods are synchronous, and will block your UI thread until the data has downloaded. You might want to use ASIHTTPRequest or the NSURLConnection mechanism instead, with asynchronous connections.
What do I need to do to NSXMLParser so it handles entity characters? For example, if I have the following element <anElement>Left & Right</anElement> I am only getting " Right" in the parser:foundCharacters: delegate method.
Thanks.
I threw together a really quick prototype application to test this out. What you are describing is not the behavior I'm seeing:
XML File:
<?xml version="1.0" encoding="UTF-8" ?>
<my_element>Left & Right</my_element>
Implementation:
#import "XMLMeController.h"
#implementation XMLMeController
- (IBAction)parse:(id)sender
{
NSURL *url = [NSURL fileURLWithPath:#"/Users/robertwalker/Desktop/test.xml"];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser parse];
[parser release];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSLog(#"Found: %#", string);
}
#end
Console output:
2008-11-11 20:41:47.805 XMLMe[10941:10b] Found: Left
2008-11-11 20:41:47.807 XMLMe[10941:10b] Found: &
2008-11-11 20:41:47.807 XMLMe[10941:10b] Found: Right
As you can see the parser is finding the "Left" then the "&" and then "Right" as three separate events that are sent to the delegate.
I can't really tell from your posting, but you need to make sure that the proper entity is used in the XML file "&" rather than just "&" character, which of course is invalid in XML files.