¿Cómo trata XPath los espacios de nombres XML?

¿Cómo trata XPath los espacios de nombres XML?

Si uso

/IntuitResponse/QueryResponse/Bill/Id 

para analizar el documento XML a continuación, recupero 0 nodos.

     =1    

Sin embargo, no estoy especificando el espacio de nombres en XPath (es decir, http://schema.intuit.com/finance/v3 no es un prefijo de cada token de la ruta). ¿Cómo puede saber XPath qué Id quiero si no lo cuento explícitamente? Supongo que en este caso (dado que solo hay un espacio de nombres) XPath podría salirse con la suya ignorando los xmlns completo. Pero si hay varios espacios de nombres, las cosas podrían ponerse feas.

Definición de espacios de nombres en XPath (recomendado)

XPath en sí mismo no tiene una forma de enlazar un prefijo de espacio de nombres con un espacio de nombres. Tales instalaciones son provistas por la biblioteca de alojamiento.

Se recomienda que use esas instalaciones y defina prefijos de espacio de nombres que luego se pueden usar para calificar los nombres de elementos y atributos XML según sea necesario.


Estos son algunos de los diversos mecanismos que los hosts XPath proporcionan para especificar enlaces de prefijo de espacio de nombres a URI de espacio de nombres:

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"; // ... } }); 
  • Recuerde llamar a DocumentBuilderFactory.setNamespaceAware(true) .
  • Ver también: Java XPath: consultas con espacio de nombres predeterminado xmlns

DO#:

 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:

Consulte Implementación de un resolutor del espacio de nombres definido por el usuario :

 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:

Adaptado de la respuesta de @ 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"); 

Consulte también Q / A canónica de @IMSoP en espacios de nombres 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 vez que haya declarado un prefijo de espacio de nombre, su XPath se puede escribir para usarlo:

 /i:IntuitResponse/i:QueryResponse 

Derrota de espacios de nombres en XPath (no recomendado)

Una alternativa es escribir predicados que prueben contra local-name() :

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

O, en XPath 2.0:

 /*:IntuitResponse/*:QueryResponse/@startPosition 

Bordear los espacios de nombres de esta manera funciona, pero no se recomienda porque

  • Sub-especifica el nombre completo del elemento / atributo.
  • No puede diferenciar entre los nombres de elementos / atributos en diferentes espacios de nombres (el mismo propósito de los espacios de nombres). Tenga en cuenta que esta preocupación podría abordarse agregando un predicado adicional para verificar el URI del espacio de nombres explícitamente 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 Gracias a Daniel Haley por la nota namespace-uri() .

  • Es excesivamente detallado.