(Kiss) XML xpath et l'espace de noms par défaut

Je travaille sur un projet iPhone qui a besoin d'parsingr du xml. Le file XML peut inclure ou non un espace de noms par défaut. J'ai besoin de savoir comment parsingr le xml au cas où il utiliserait un espace de noms par défaut. Comme j'ai besoin à la fois de lire un xml en écriture, je penche pour utiliser KissXML, mais je suis ouvert aux suggestions.

C'est mon code:

NSSsortingng *content = [NSSsortingng ssortingngWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"bookstore" ofType:@"xml"] encoding:NSUTF8SsortingngEncoding error:nil]; DDXMLDocument *theDocument = [[DDXMLDocument alloc] initWithXMLSsortingng:content options:0 error:nil]; NSArray *results = [theDocument nodesForXPath:@"//book" error:nil]; NSLog(@"%d", [results count]); 

Cela fonctionne comme prévu sur ce file XML:

 <?xml version="1.0" encoding="UTF-8"?> <bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> </book> <book category="CHILDREN"> <title lang="en">Harry Potter</title> </book> </bookstore> 

Mais quand le XML a un espace de noms, comme ça, il arrête de fonctionner:

 <?xml version="1.0" encoding="UTF-8"?> <bookstore xmlns="[INSERT RANDOM NAMESPACE]"> <book category="COOKING"> <title lang="en">Everyday Italian</title> </book> <book category="CHILDREN"> <title lang="en">Harry Potter</title> </book> </bookstore> 

Bien sûr, je pourrais juste pré-traiter la string et supprimer les xmlns, bien que cela ressemble à une sorte de hack laid. Quelle est la bonne façon de gérer cela?

La voie propre: interroger l'espace de noms

Vous pouvez utiliser deux requêtes XPath, une pour récupérer l'espace de noms, puis l'save; en deuxième requête, utilisez celle que vous avez déjà, y compris les namespaces. Je ne peux que vous aider avec la requête, mais il semble que vous connaissiez bien les namespaces et comment les save dans l'infrastructure KissXML:

 namespace-uri(/*) 

Cette expression récupère tous les nœuds enfants à partir de la racine du document, qui est un élément racine unique par définition XML, et renvoie son uri d'espace de nom.

La manière laide: seulement tester pour le nom local

Il semble que KissXML ne supporte que XPath 1.0. Avec cette version linguistique less performante, vous devez utiliser des sélecteurs generics à chaque étape d'axe et comparer le nom local (sans préfixe d'espace de nom) dans le prédicat:

 //*[local-name(.) = 'book'] 

À partir de XPath 2.0, vous pouvez effectuer une requête en utilisant le caractère générique de l'espace de noms, qui est beaucoup plus court:

 //*:book 

D'après ce commentaire, KissXML implémente un comportement "correct" alors que NSXML ne le fait pas. Ce qui n'aide pas vraiment. Il y a un correctif proposé pour cette attente d'être fusionné.

En développant la première solution proposée de la réponse acceptée, la solution de contournement que j'ai trouvée consistait à renommer l'espace de noms par défaut, puis à utiliser ce préfixe dans mes requêtes XPath. Quelque chose comme:

  DDXMLNode *defaultNamespace = [document.rootElement namespaceForPrefix:@""]; defaultNamespace.name = @"default"; NSArray *xmlNodes = [[document rootElement] nodesForXPath:@"//default:foo/default:bar" error:nil]; 

Cela me semble plus propre que le traitement textuel du file. Vous pouvez bien sûr vérifier et gérer les collisions d'namespaces, mais ce qui précède devrait fonctionner dans les cas les plus simples.