BluesZhang / gdata-objectivec-client

Automatically exported from code.google.com/p/gdata-objectivec-client
Other
0 stars 0 forks source link

GDataXMLNode not handling default namespaces for xpath queries #31

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
When you parse an XML file with a default namespace like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<gpx 
  version="1.1" 
  xmlns="http://www.topografix.com/GPX/1/1">
<trk></trk>
</gpx>

the following xpath will return no nodes
./gpx/trk

the reason is that in libxml2 all nodes require to have a namespace set:
//the namespace prefix cannot be NULL or empty string//
http://xmlsoft.org/html/libxml-xpathInternals.html#xmlXPathRegisterNs

I have successfully patched GDataXMLNode by doing the following:
- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error {
[…]
WAS: if (prefix == NULL) prefix = (xmlChar*) "";
TO: if (prefix == NULL) prefix = (xmlChar*) "defns";

then, when evaluating the xpath in 
WAS: xpathObj = xmlXPathEval(GDataGetXMLString(xpath), xpathCtx);
TO: xpathObj = xmlXPathEval(GDataGetXMLString(normalizedxpath), xpathCtx);

whereas normalizedxpath is retrieved from a new method that appends a namespace 
to each 
xpath component that does not yet have a namespace set.
therefore
./gpx/trk
becomes
./defns:gpx/defns:trk

this now works as expected and also matches the behaviour of apples 
NSXMLDocument.

--
Mac OS X 10.5.7, XCode iPhoneOS 3.0 release

- berbie

Original issue reported on code.google.com by ber...@gmail.com on 25 Jun 2009 at 8:42

Attachments:

GoogleCodeExporter commented 9 years ago

Original comment by gregrobbins on 30 Jun 2009 at 1:35

GoogleCodeExporter commented 9 years ago
Thanks for pointing out the issue and providing an alternative. You're right 
that the
library is in error in registering the empty-string prefix.

This led to some interesting discussion here about safe XPath expressions. 

While NSXML's XPath does implicitly prefix expression elements with the node's
default namespace, that is not really safe. There is no guarantee that future 
XML
will have the same default namespace, or that prefix-URI mappings will remain 
the
same.  If either of those changes, the XPath expression will give unexpected 
results.

Trying to alter the user's XPath expression is difficult to do correctly.  
Issues
like whitespace, OR operators (|'s), and other compound expressions make trying 
to
insert a prefix automatically in a reliable way quite a difficult task.

I will add to the library an XPath call which takes a dictionary explicitly 
mapping
prefixes (keys) to URIs (values), allowing for reliable XPath expressions that 
can
access nodes on the default namespace.  Using that will look like:

path = @"atom:entry/atom:link"; // four entry link nodes
dict = [NSDictionary dictionaryWithObject:kGDataNamespaceAtom
         forKey:kGDataNamespaceAtomPrefix];
nodes = [root nodesForXPath:path
                 namespaces:dict
                      error:&error];

Additionally, the plain nodesForXPath:error: method will allow _def_ns as a 
prefix
referring to the default namespace.  However, it will safer to use the XPath 
method
which takes the explicit namespace dictionary.

Original comment by gregrobbins on 2 Jul 2009 at 12:41

GoogleCodeExporter commented 9 years ago
Better namespace support is now in top-of-trunk GDataXMLNode.

http://code.google.com/p/gdata-objectivec-client/source/detail?r=288

Original comment by gregrobbins on 3 Jul 2009 at 1:16