I've got the following to work for me pretty well...
- (NSArray *)nodesForXPath:(NSString *)xpath usingNamespaces:
(NSDictionary*)namespaces error:(NSError **)error {
if(genericPtr == nil)
return nil;
// NSAssert(genericPtr != NULL, @"CXMLNode does not have attached
libxml2 _node.");
NSArray *theResult = NULL;
xmlXPathContextPtr theXPathContext = xmlXPathNewContext(((xmlNodePtr)
genericPtr)->doc);
if(theXPathContext == NULL)
return nil;
theXPathContext->node = (xmlNodePtr)genericPtr;
if(namespaces != nil) {
NSString *prefix;
NSEnumerator *namespaceEnumerator = [namespaces keyEnumerator];
while (prefix = [namespaceEnumerator nextObject])
{
NSString *href = [namespaces valueForKey:prefix];
if(xmlXPathRegisterNs(theXPathContext, (const unsigned char*)
[prefix UTF8String], (const unsigned char*)[href UTF8String]) != 0 ) {
NSLog(@"unable to register namespace");
}
}
}
// TODO considering putting xmlChar <-> UTF8 into a NSString category
xmlXPathObjectPtr theXPathObject = xmlXPathEvalExpression((const
xmlChar *)[xpath UTF8String], theXPathContext);
if(theXPathObject!= NULL) {
if (xmlXPathNodeSetIsEmpty(theXPathObject->nodesetval))
theResult = [NSArray array]; // TODO better to return NULL?
else
{
NSMutableArray *theArray = [NSMutableArray array];
int N;
for (N = 0; N < theXPathObject->nodesetval->nodeNr; N++)
{
xmlNodePtr theNode = theXPathObject->nodesetval->nodeTab[N];
[theArray addObject:[DDXMLNode nodeWithPrimitive:(xmlKindPtr)
theNode]];
}
theResult = theArray;
}
}
xmlXPathFreeObject(theXPathObject);
xmlXPathFreeContext(theXPathContext);
return(theResult);
}