Xml Namespace brisant mon xpath!

J’ai le XML suivant:

      

Il s’agit d’une version allégée de XML renvoyée par un service Web SharePoint. J’ai aussi le xPath suivant:

 /List/Fields/Field 

Lorsque je supprime les fichiers XML de mon fichier XML, xPath fonctionne correctement. Quand il y est, mon xPath ne trouve rien. Y a-t-il quelque chose que je devrais faire différemment avec mon xPath? La modification du XML n’est pas une option.

J’ai aussi le xPath suivant:

 /List/Fields/Field 

Lorsque je supprime les fichiers XML de mon fichier XML, xPath fonctionne correctement. Quand il y est, mon xPath ne trouve rien

Si vous ne pouvez pas enregistrer une liaison d’espace de noms et ne pouvez pas utiliser (en supposant que le préfixe enregistré est “x”):

 /x:List/x:Fields/x:Field 

alors il y a une autre façon :

 /*[name()='List']/*[name()='Fields']/*[name()='Field'] 

L’élément List a été défini avec un espace de nommage par défaut et il est adopté par tous les éléments à l’intérieur.

Vous devez donc ignorer l’espace de noms des éléments comme suit:

 /*[local-name()='List']/*[local-name()='Fields]/*[local-name()='Field] 

mais cela signifie que le xpath récupérera tout autre élément avec List – Fields – Field

Vous pouvez faire une vérification de l’espace de noms ainsi qu’une vérification du nom local comme suit:

 /*[local-name()='List' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']/*[local-name()='Fields' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']/*[local-name()='Field' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/'] 

Ou vous pouvez enregistrer l’espace de noms avec la bibliothèque, puis spécifier explicitement le préfixe de cet espace de noms et l’append à l’expression xpath, dont la méthode dépend de la bibliothèque que vous utilisez.

Vous devrez probablement enregistrer cet espace de noms avec votre bibliothèque xpath. Selon la bibliothèque, vous pouvez utiliser le préfixe «default» ou vous devez lui donner un préfixe nommé et l’utiliser dans vos requêtes xpath.

Par exemple, dans php (puisque vous n’avez pas spécifié de langue) en utilisant DOMXPath, vous pouvez faire quelque chose comme ceci:

 $xpath = new DOMXPath($document); $xpath->registerNamespace('x', 'http://schemas.microsoft.com/sharepoint/soap/'); $xpath->query('/x:List/x:Fields/x:Field'); 

Je viens d’avoir ce problème en utilisant Xalan-c

Le peu que je n’ai pas tout à fait compris au début est que les alias / préfixes d’espace de noms XPath ou XSLT peuvent être différents de ceux du document – en fonction de votre résolveur d’espace de noms.

Il semble que s’il y a un espace de noms sur le document, il ne réussit pas à faire correspondre un élément de chemin à moins qu’un espace de noms ne soit utilisé. (standard mais pas toujours suivi?)

Le XalanDocumentPrefixResolver mappera les espaces de noms XPath ou XSLT en URI et essayera de leur donner un identifiant en obtenant le préfixe – là où il n’y a pas de préfixe il a utilisé le nom qui est devenu xmlns

/xmlns:List/xmlns:Fields/xmlns:Field

Sinon, vous pouvez créer votre propre résolveur, mais il nécessite toujours un espace de noms minimal utilisé dans xpath 🙁

En voici un que j’ai piraté en testant, pas de garantie de mémoire

 // don't care what prefix given, there can only be the one struct NoPrefixResolver : public xalanc::PrefixResolver { NoPrefixResolver(const xalanc::XalanDOMSsortingng& theURI) : m_uri(theURI){} virtual const xalanc::XalanDOMSsortingng* getNamespaceForPrefix(const xalanc::XalanDOMSsortingng& prefix) const { return &m_uri; } virtual const xalanc::XalanDOMSsortingng& getURI() const { return m_uri; } const xalanc::XalanDOMSsortingng m_uri; }; /x:List/x:Fields/x:Field /a:List/b:Fields/c:Field 

Si vous pouvez ignorer l’élément de document, le XPath suivant peut également vous aider:

 //Fields/Field 

Cela fonctionne tant que vous n’avez pas de champs sous un autre nœud et que les sous-nœuds n’ont pas d’espace de noms.