Im using NSXMLParser to dissect a xml package, I'm receiving &apos inside the package text.
I have the following defined for the xmlParser:
[xmlParser setShouldResolveExternalEntities: YES];
The following method is never called
- (void)parser:(NSXMLParser *)parser foundExternalEntityDeclarationWithName:(NSString *)entityName publicID:(NSString *)publicID systemID:(NSString *)systemID
The text in the field before the &apos is not considered by the parser.
Im searching how to solve this, any idea???
Thanks in advance
Alex
XML package portion attached:
<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="urn:appwsdl"><SOAP-ENV:Body><ns1:getObjects2Response xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/"><return xsi:type="tns:objectsResult"><totalRecipes xsi:type="xsd:string">1574</totalObjects><Objects xsi:type="tns:Item"><id xsi:type="xsd:string">4311</id><name xsi:type="xsd:string"> item title 1 </name><procedure xsi:type="xsd:string">item procedure 11......
Here is what I did, after referring a different answer from here.
I replaced all the occurrences of the ' in the xml with "'" when the data is received from NSURLConnection object. Then I give that data to the parser.
So what I do is:
NSData* parserData = [self resolveHTMLEntities: self.receivedData];
NSXMLParser* parser = [[NSXMLaParser alloc] initwithData:parserData];
Here is the resolveHTMLEntitites method:
NSString *xmlCode = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSMutableString *temp = [NSMutableString stringWithString:xmlCode];
// Replace all the entities
[temp replaceOccurrencesOfString:#"'" withString:#"'" options:NSLiteralSearch range:NSMakeRange(0, [temp length])];
NSData *finalData = [temp dataUsingEncoding:NSUTF8StringEncoding];
return finalData;
The catch is that ' gets converted to ' thats why we need to replace that occurrence.
Note: No memory management is performed in the above block of code.
Hope this helps.
The standard entities are <, >, &, and ". ' is an html entity reference. Does your XML refer to the XHTML namespace or some other namespace that has ' defined?
(BTW, would be nice to see a small segment of the XML including the header.)
Related
I am trying to upload images to yFrog which is working just fine, but I want to grab just the URL from the response. When I use the NSURLConnection method
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString* responseString = [[NSString alloc] initWithData:webData
encoding:NSUTF8StringEncoding];
// NSString *url = [webData valueForKey:#"mediaurl"];
NSLog(#"result: %#", responseString);
}
I get this as my response string
result: <?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok">
<mediaid>hszuhsp</mediaid>
<mediaurl>http://yfrog.com/hszuhsp</mediaurl>
</rsp>
As you can see in my blocked out code I tried to give my NSMutableData to give me the value of the key #"mediaurl" which just crashes. I think this should be relatively easy but for some reason I just can not figure out how to just grab the URL out of the response. Any help would be greatly appreciated. Thank you
This is a valid xml response.
If you need to parse only this response, you can iterate the NSString.
But if you have other response in xml format then the best approach is you are going to parse it using any XML parser.. :)
Here is how to choose your xml parser, and then you will search for tutorial accordingly.
you can't use the valueForKey on the instance of NSMutableData class., you should use the XML parser to extract the value.
I'm quite new to programing and have a problem. I have been using touchxml for parsing and there hasn't been any problem before. Now i want to parse an xml string.
I've looked all over the internet but can't find the answer.(i've never done initWithXMLString before maybe i'm doing something wrong here?)
My current code for parsing:
NSArray *resultNodes = NULL;
CXMLDocument *rssParser = [[CXMLDocument alloc] initWithXMLString:str options:0 error:nil];
NSString *strName;
resultNodes = [rssParser nodesForXPath:#"//FictionBook" error:nil];
NSLog(#"RESULT NODE COUNT =%d",[resultNodes count]);
and my string looks like this:
"<?xml version="1.0" encoding="UTF-8"?>
<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>prose_contemporary</genre> <author><first-name>Мария</first-name><last-name>Метлицкая</last-name><id>f97cbf85-bb7c-102b-8639-bb1d5f8374bd</id></author><book-title>Наша маленькая жизнь (сборник)</book-title> <annotation><p>Мария Метлицкая рассказывает о простых людях – они не летают в космос, не блистают на подмостках сцены, их не найдешь в списке Forbеs.</p></annotation></description></title-info></FictionBook>"
xml apears to be valid, I've checked about 10 xml validators.
But i get 0 from [resultNodes count].
Anybody encountered something similar before?
Thanks in advance!
Try to check if there were an error while parsing:
NSError *error;
NSArray *resultNodes = NULL;
CXMLDocument *rssParser = [[CXMLDocument alloc] initWithXMLString:str options:0 error:&error];
NSLog("Error: %#",error);
Also does your XML contains elements with namespaces?
Firstly get you xml validate or not by this http://www.xmlvalidation.com/ and if it validated then you are not getting any response then you should check the error code what the error is thrown by the xml parser and then try to check by error code what is the problem.
I am needing to parse an XML file for my app and I dont have any clue how to do it. I went through one XMLParser tutorial, and it worked fine but the XML file in the tutorial was very simple and my XML file is quite a bit more complex.
here is a snippet of the xml file:
<?xml version="1.0" encoding="UTF-8"?>
<digital_tpp cycle="1003" from_edate="0901Z 03/11/10" to_edate="0901Z 04/08/10">
<state_code ID="AK" state_fullname="Alaska">
<city_name ID="ADAK ISLAND" volume="AK-1">
<airport_name ID="ADAK" military="N" apt_ident="ADK" icao_ident="PADK" alnum="1244">
<record>
<chartseq>10100</chartseq>
<chart_code>MIN</chart_code>
<chart_name>TAKE-OFF MINIMUMS</chart_name>
<useraction></useraction>
<pdf_name>AKTO.PDF</pdf_name>
<cn_flg>N</cn_flg>
<cnsection></cnsection>
<cnpage></cnpage>
<bvsection>C</bvsection>
<bvpage></bvpage>
<procuid></procuid>
<two_colored>N</two_colored>
<civil> </civil>
<faanfd15></faanfd15>
<faanfd18></faanfd18>
<copter></copter>
</record>
<record>
<chartseq>10200</chartseq>
<chart_code>MIN</chart_code>
<chart_name>ALTERNATE MINIMUMS</chart_name>
<useraction></useraction>
<pdf_name>AKALT.PDF</pdf_name>
<cn_flg>N</cn_flg>
<cnsection></cnsection>
<cnpage></cnpage>
<bvsection>E</bvsection>
<bvpage></bvpage>
<procuid></procuid>
<two_colored>N</two_colored>
<civil> </civil>
<faanfd15></faanfd15>
<faanfd18></faanfd18>
<copter></copter>
</record>
</airport_name>
</city_name>
</state_code>
</digital_tpp>
What I'm needing to do is search the XML file for the <...icao_ident> that the user specifies, then create a dictionary containing the <pdf_name> and <chart_name> for each <record> . I will then create a UI that displays the pdf files.
Can someone direct me to a good tutorial or explanation of how XML parser works? Or if I'm going about this the wrong way I'd be open to suggestions too.
(the XML file is about 8MB)
You might find that my blog post about wrapping NSXMLParser gives you what you need - and possibly a higher level alternative (my wrapper).
For example, using my technique, you'd write methods like:
-(void) handleElement_chartname: (NSDictionary*) attributes;
I suggest you to read the Event-Driven XML Programming Guide for Cocoa. In your specific case, what you need to do is:
In the parser:didStartElement: check for the element name: "airport_name", initialize a new array to store all the record elements (or you can define your own data structure to store the record element), a dictionary to store all element in the record, one string variable to store the current text
In the parser:foundCharacters: append the string to the current text
In the parser:didEndElement: save the dictionary to the array, release the array, save the results.
UPDATED
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if ( [elementName isEqualToString:#"airport_name"]) {
if (!airports)
airports = [[NSMutableArray alloc] init];
NSString *str_icao_ident = [attributeDict objectForKey:#"icao_ident"];
//do something
return;
// ... continued ...
}}
i know this isn't the best way...
I struggled for 2 days trying to adapt the XML parser to my situation. I couldnt grasp it, probably because I'm just so used to doing this in C# and obj-c is new to me...
So what I did was parsed the whole thing as a string.
I converted the entire XML file to a NSString, then used substringToIndex and substringFromIndex to isolate the section I needed (the airport). I then used the </record> tag to create an array of <records>, then wrote a for loop that took the values I needed out of the each array object just by getting the range of the tags.
Like I said, it was a crazy solution, but I did it all in 26 lines of code and it works great.
NSString *path = [[NSBundle mainBundle] pathForResource:#"dttps" ofType:#"xml"];
NSData *data = [[NSData alloc]initWithContentsOfFile:path];
NSString *xmlString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSRange range = [xmlString rangeOfString:searchedAirport];
xmlString = [xmlString substringFromIndex:range.location];
range = [xmlString rangeOfString:#"/airport_name"];
xmlString = [xmlString substringToIndex:range.location];
NSMutableArray *chartNames = [[NSMutableArray alloc]initWithCapacity:100] ;
NSMutableArray *pdfNames = [[NSMutableArray alloc]initWithCapacity:100] ;
NSArray *charts = [xmlString componentsSeparatedByString:#"</record>"];
NSString *tempString = [[NSString alloc]initWithFormat:#""];
int chartsCount = [charts count]-1;
int x;
for (x=0; x < chartsCount; x=x+1) {
tempString = [charts objectAtIndex:x];
range = [tempString rangeOfString:#"<chart_name>"];
tempString = [tempString substringFromIndex:range.location+12];
range = [tempString rangeOfString:#"</chart_name>"];
tempString = [tempString substringToIndex:range.location];
[chartNames addObject:tempString];
tempString = [charts objectAtIndex:x];
range = [tempString rangeOfString:#"<pdf_name>"];
tempString = [tempString substringFromIndex:range.location+10];
range = [tempString rangeOfString:#"</pdf_name>"];
tempString = [tempString substringToIndex:range.location-4];
[pdfNames addObject:tempString];
}
followed by cleanup...
The default XML parsing on the iPhone is pretty tragic compared with contemporary scripting languages. If you are doing serious parsing with complex objects with multiple levels of child objects, then god help you with NSXMLParser.
I would recommend checking out TouchXML which offers a much more civilized solution that is closer to what you might see in a language like Python or Actionscript in terms of its implementation within your own source.
I'm trying to parse a Stack Overflow RSS feed of a specific question:
https://stackoverflow.com/feeds/question/2110875
For this I'm using the TouchXML library. There seems to be a problem in the following code:
CXMLDocument *parser = [[CXMLDocument alloc] initWithData:sourceData options:0 error:nil];
NSArray *allEntries = [parser nodesForXPath:#"//entry" error:nil];
NSLog(#"Found entries: %d",[allEntries count]); //Returns 0
The NSLog statement should return the count of all entries in the feed. In this case it should be '3', problem is that it returns 0.
I found that this piece of code does work:
CXMLDocument *preParser = [[CXMLDocument alloc] initWithData:sourceData options:0 error:nil];
NSString *sourceStringUTF8 = [preParser XMLString];
[preParser release];
CXMLDocument *parser = [[CXMLDocument alloc] initWithData:[sourceStringUTF8 dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSArray *allEntries = [parser nodesForXPath:#"//entry" error:nil];
NSLog(#"Found entries: %d",[allEntries count]); //Returns 3, which is ok
But using this seems hacky (it probably is) and introduces a few other sporadic bugs.
As far as I know the Xpath expression is correct. I've checked it using this page as well.
Can anyone help me with this problem, or point me in the right direction.
Thanks.
I had a very similar problem. This has something to do with the xml namespace, which TouchXML doesn't support very well (a known issue).
I believe that in your hack, the namespace wasn't passed into the second parser, that's why it works.
A easier way is just to change
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
replaced with simply
<html>
and xPath now works.
Maybe start by actually using that error argument to nodesForXPath:error to see if it returns an error? And check if allEntries is not nil after making that call?
I am stuck with some TouchXML code. Please help.
I have the following code to get the data from an xml webservice:
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *data = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"String data: %# \n", data);
//Do the parsing
CXMLDocument *document = [[[CXMLDocument alloc] initWithData:urlData encoding:NSUTF8StringEncoding options:0 error:&error] autorelease];
NSLog (#"Document :%# \n",[document stringValue]);
The string data does have the content from the service, but how come the CXMLDocument object does not contain anything? Someone can tell me why?
2009-12-30 18:21:59.467 MyAdvancedBlog[3425:207] String data: <?xml version="1.0" encoding="utf-8"?>
<Post xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<IdPostazione>42</IdPostazione>
<StringID>HOANG</StringID>
<Name>CASSA2</Name>
<TerminalValid>true</TerminalValid>
<NeedSession>false</NeedSession>
</Post>
2009-12-30 18:21:59.469 MyAdvancedBlog[3425:207] Document :(null)
TouchXML's documentation says that CXMLDocument should act just like NSXMLDocument. So, the reference for initWithData:options:error: might help.
It says the result will be nil if it's unsuccessful, and error will then contain more info. Is it nil?
You might consider using NSXMLDocument for the moment, and see if they really do act the same. If they don't, file a bug with TouchXML.
You could also use initWithXMLString:options:error: along with that string you already decoded.
Edit: Even better. Here's example code for using NSXMLDocument. In theory, it should work for CXMLDocument as well.