In che modo XPath gestisce i namespace XML?

In che modo XPath gestisce i namespace XML?

Se io uso

/IntuitResponse/QueryResponse/Bill/Id 

per analizzare il documento XML qui sotto ottengo 0 nodes indietro.

     =1    

Tuttavia, non sto specificando lo spazio dei nomi nell’XPath (cioè http://schema.intuit.com/finance/v3 non è un prefisso di ciascun token del percorso). In che modo XPath può sapere quale Id voglio se non lo dico esplicitamente? Suppongo che in questo caso (poiché c’è solo uno spazio dei nomi) XPath potrebbe cavarsela ignorando completamente il xmlns . Ma se ci sono più spazi dei nomi, le cose potrebbero diventare brutte.

Definizione degli spazi dei nomi in XPath (consigliato)

XPath stesso non ha un modo per associare un prefisso dello spazio dei nomi con uno spazio dei nomi. Tali servizi sono forniti dalla biblioteca di hosting.

Si consiglia di utilizzare tali servizi e definire i prefissi dello spazio dei nomi che possono essere utilizzati per qualificare l’elemento XML ei nomi degli attributi come necessario.


Ecco alcuni dei vari meccanismi che gli host XPath forniscono per specificare i bind di prefissi dello spazio dei nomi per gli URI dello spazio dei nomi:

XSLT:

  ... 

Perl ( LibXML ):

 my $xc = XML::LibXML::XPathContext->new($doc); $xc->registerNs('i', 'http://schema.intuit.com/finance/v3'); my @nodes = $xc->findnodes('/i:IntuitResponse/i:QueryResponse'); 

Python ( lxml ):

 from lxml import etree f = StringIO('...') doc = etree.parse(f) r = doc.xpath('/i:IntuitResponse/i:QueryResponse', namespaces={'i':'http://schema.intuit.com/finance/v3'}) 

Python ( ElementTree ):

 namespaces = {'i': 'http://schema.intuit.com/finance/v3'} root.findall('/i:IntuitResponse/i:QueryResponse', namespaces) 

Java (SAX):

 NamespaceSupport support = new NamespaceSupport(); support.pushContext(); support.declarePrefix("i", "http://schema.intuit.com/finance/v3"); 

Java (XPath):

 xpath.setNamespaceContext(new NamespaceContext() { public String getNamespaceURI(String prefix) { switch (prefix) { case "i": return "http://schema.intuit.com/finance/v3"; // ... } }); 
  • Ricordarsi di chiamare DocumentBuilderFactory.setNamespaceAware(true) .
  • Vedi anche: Java XPath: query con namespace predefinito xmlns

C #:

 XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3"); XmlNodeList nodes = el.SelectNodes(@"/i:IntuitResponse/i:QueryResponse", nsmgr); 

xmlstarlet:

 -N i="http://schema.intuit.com/finance/v3" 

JavaScript:

Vedere Implementazione di un resolver dello spazio dei nomi definito dall’utente :

 function nsResolver(prefix) { var ns = { 'i' : 'http://schema.intuit.com/finance/v3' }; return ns[prefix] || null; } document.evaluate( '/i:IntuitResponse/i:QueryResponse', document, nsResolver, XPathResult.ANY_TYPE, null ); 

PHP:

Adattato dalla risposta di @ Tomalak usando DOMDocument :

 $result = new DOMDocument(); $result->loadXML($xml); $xpath = new DOMXpath($result); $xpath->registerNamespace("i", "http://schema.intuit.com/finance/v3"); $result = $xpath->query("/i:IntuitResponse/i:QueryResponse"); 

Vedi anche Q / A canonico di IMSoP su namespace PHP SimpleXML .

VBA:

 xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'" doc.setProperty "SelectionNamespaces", xmlNS Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse") 

Una volta dichiarato il prefisso del namespace, è ansible scrivere XPath per usarlo:

 /i:IntuitResponse/i:QueryResponse 

Sconfiggere namespace in XPath (non consigliato)

Un’alternativa è scrivere predicati che testano contro local-name() :

 /*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition 

Oppure, in XPath 2.0:

 /*:IntuitResponse/*:QueryResponse/@startPosition 

Lo skype degli spazi dei nomi in questo modo funziona ma non è consigliato perché

  • Sotto specifica l’intero nome elemento / attributo.
  • Non riesce a distinguere tra nomi di elementi / attributi in diversi spazi dei nomi (lo stesso scopo dei namespace). Si noti che questa preoccupazione potrebbe essere risolta aggiungendo un predicato aggiuntivo per verificare l’URI dello spazio dei nomi in modo esplicito 1 :

     /*[ namespace-uri()='http://schema.intuit.com/finance/v3' and local-name()='IntuitResponse'] /*[ namespace-uri()='http://schema.intuit.com/finance/v3' and local-name()='QueryResponse'] /@startPosition 

    1 Grazie a Daniel Haley per la nota namespace-uri() .

  • È eccessivamente prolisso.