CXMLDocument - [CXMLNode nodeForXPath] problem? - iphone

I'm developing epub reader program.
To get contents of the epub file, I wanted to parse container.xml.
Here it is.
<?xml version="1.0"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
<rootfiles>
<rootfile full-path="OPS/content.opf"
media-type="application/oebps-package+xml"/>
</rootfiles>
</container>
I wanted to get element, so I used following code.
CXMLDocument* manifestFile = [[[CXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:manifestFilePath] options:0 error:nil] autorelease];
NSArray* nodes = [manifestFile nodesForXPath:#"//rootfiles" error:nil];
NSLog(#"Nodes count is %d\n", [nodes count]);
And I get the following result.
Nodes count is 0
Why do I got this result?
Please help me.
Thanks.

The problem is that your XML has a namespace. You need to explicitly define the namespaces to use when querying with XPath.
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
#"urn:oasis:names:tc:opendocument:xmlns:container",
#"oasis",
nil];
NSArray* nodes = [manifestFile nodesForXPath:#"//oasis:rootfiles" namespaceMappings:dict error:nil];
NSLog(#"Nodes count is %d\n", [nodes count]); // --> Nodes count is 1

Related

Xpath problem in iPhone

In GdataXML I can only use nodesforXpath from the root of XML, but I want that once I have the inferenceMembers I would like to apply Xpath to rest of this node, but not whole DOM tree, is that possible?
Example below works wrong in for loop, brings all the varibles in the DOM, but I want to work only on the variableElement not whole the DOM once I have the variableElement.
NSArray *inferenceMembers = [doc nodesForXPath:#"//inferenceresponse/state/variable[not(valuedefinition/variablevalue)]" error:nil];
for (GDataXMLElement *variableElement in inferenceMembers) {
Variable *variable=[[Variable alloc] init];
NSArray *items = [variableElement nodesForXPath:#"//variable/domaindefinition/domain/enumType/domainitem" error:nil];
}
The reason I want this not because it is hard to do, but I guess it would be slower if I xpath query to whole XML to reach the same element's children each time. I have read that I can do some magic with namespaces and NSDictionary but do not know how to do
Try this:
NSArray *inferenceMembers = [doc nodesForXPath:#"//inferenceresponse/state/variable[not(valuedefinition/variablevalue)]" error:nil];
for (GDataXMLElement *variableElement in inferenceMembers) {
Variable *variable=[[Variable alloc] init];
NSArray *items = [variableElement nodesForXPath:#"domaindefinition/domain/enumType/domainitem" error:nil];
}
It'd be useful to see the XML structure to be able to help fully.

iPhone NSXMLParse for .asx files

I'm totally new to XML.
Does anyone have a sample code to help me build a custom class that would parse Microsoft .asx files to play mms streams in sequence on the iPhone?
Some Googling revealed to me that .xml and .asx are somewhat related, though the second one is very limited if compared to the first.
I need to play three streams in sequence, inside an .asx container like this:
<asx version="3.0">
<TITLE>MYSONGS</TITLE>
<entry>
<TITLE>www.mysite.com</TITLE>
<ref href="mms://mysite.com/musicFolder/song1.wma" />
</entry>
<entry>
<TITLE>MYSONGS</TITLE>
<ref href="mms://mysite.com/musicFolder/song2.wma" />
</entry>
<entry>
<TITLE>www.mysite.com</TITLE>
<ref href="mms://mysite.com/musicFolder/song3.wma" />
</entry>
</asx>
I'm already able to parse the mms stream, decode and play the wma file. I'm just not able yet to parse .asx content, to play the streams in sequence. Thanks!
In my case I've been able to successfully parse .asx files using TouchXML, using this code (that I modified from the original version available at http://foobarpig.com/iphone/parsing-xml-element-attributes-with-touchxml.html):
// we will put parsed data in an a array
NSMutableArray *res = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString: #"http://www.yoursite.com/WindowsMediaDotCom/theFileToParse.asx"];
/* have TouchXML parse it into a CXMLDocument */
CXMLDocument *document = [[[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil] autorelease];
NSArray *nodes = NULL;
// searching for piglet nodes
nodes = [document nodesForXPath:#"//ref" error:nil];
for (CXMLElement *node in nodes) {
NSMutableDictionary *item = [[NSMutableDictionary alloc] init];
int counter;
for(counter = 0; counter < [node childCount]; counter++) {
// common procedure: dictionary with keys/values from XML node
[item setObject:[[node childAtIndex:counter] stringValue] forKey:[[node childAtIndex:counter] name]];
}
// and here it is - attributeForName! Simple as that.
[item setObject:[[node attributeForName:#"href"] stringValue] forKey:#"href"]; // <------ this magical arrow is pointing to the area of interest
[res addObject:item];
[item release];
}
// and we print our results
NSLog(#"%#", res);

Parsing SOAP result using TouchXML in iOS SDK (iPad)

I'm working on an iPad project that is using functions in a WebService.
Handling webservice connection, data etc works find. But i'm not able to parse the result SOAP using TouchXML. Getting the nodes out of the xml always returns 0 length.
The output xml:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <LogOnResponse xmlns="http://coreservices.org/v1"> <LogOnResult> <Id>1c0e9ad0-a3be-4cd0-8f0d-0616a63a4e28</Id> <userId>2</userId> <user> <ID>2 <Name>Beheerder <emailAddress /> <cultureName>nl-NL</cultureName> </user> </LogOnResult> </LogOnResponse> </soap:Body></soap:Envelope>
parser code:
NSData *aData = [[NSData alloc] initWithBytes:[webData mutableBytes] length:[webData length]];
NSString *xmlData = [[NSString alloc] initWithData:aData encoding:NSASCIIStringEncoding];
NSLog(#"%#", xmlData);
[xmlData release];
CXMLDocument *domUserIdentity = [[[CXMLDocument alloc] initWithData:aData options:0 error:nil] autorelease];
[aData release];
NSArray *nodesList = [domUserIdentity nodesForXPath:#"//LogOnResult" error:nil]; // 0 length
for (CXMLElement *resultElement in nodesList) {
for (int counter = 0; counter
NSString *elemName = [[resultElement childAtIndex:counter] name];
NSString * elemValue = [[[resultElement childAtIndex:counter] stringValue] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
[elemName release];
[elemValue release];
}
}
[nodesList release];
Any idea what did i do wrong?
Thank's alot in advance.
Inoel
Try using the NSXMLDocument, it should work as well as CXMLDocument. Here are some docs:
link
I recommend using an XPath Parser. You aren't doing anything too heavy, so the speed hit is well worth it. My personal choice is TFHpple. There are slightly faster and more precise solutions out there, but I find TFHpple's simplicity hard to beat.
Example:
NSData *data = [[NSData alloc] initWithContentsOfFile:#"example.html"];
// Create parser
xpathParser = [[TFHpple alloc] initWithXMLData:data];
NSArray *elements = [xpathParser search:#"//LogOnResult"];
TFHppleElement *element = [elements objectAtIndex:0];
// Get the text within the cell tag
NSString *content = [element content];
[xpathParser release];
[data release];
Obviously you'd have to write some code to save the parts you want. Looking at this data, I'd probably make a custom data holder class that you can access with properties. You can parse your XML into that and then save it as a property in the view controller that will be accessing it.
Happy coding!

Parse youtube playlist on iphone sdk/ iOS

Since Days i'm trying to parse a YOUTUBE-XML-Feed by using GDATA-API for iOS.
http://code.google.com/intl/de-DE/apis/youtube/2.0/developers_guide_protocol_channel_search.html
NSDictionary *namespaces = [NSDictionary dictionaryWithObjectsAndKeys:
#"http://www.w3.org/2005/Atom", #"",
#"http://schemas.google.com/g/2005", #"gd",
#"http://a9.com/-/spec/opensearch/1.1/",#"opensearch",
#"http://gdata.youtube.com/schemas/2007",#"yt",
#"W/"DkYGRH48fCp7ImA9Wx5WFEw."",#"gd:etag",
nil];
NSError *error = [[NSError alloc] init];
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:receivedData options:0 error:nil];
NSArray *elements = [doc nodesForXPath:#"//entry" namespaces:namespaces error:&error];
I don't get any results. Does anyone got an solution to this? Thanks in advance!
this is how I use this API
NSArray *entries = [doc.rootElement elementsForName:#"entry"];
for (GDataXMLElement *e in entries) {
// do something..
}
There is documentation on the GData Objective-C API, and a sample application for using the YouTube GData API is here.
I encountered a similar problem, it doesn't seem to deal well with a prefixless namespace.
Try changing:
#"http://www.w3.org/2005/Atom", #"",
to
#"http://www.w3.org/2005/Atom", #"atom",
and your xpath:
#"//entry"
to
#"//atom:entry"

Parsing SO RSS feed using TouchXML, no <entry> tags found

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?