¡Espacio de nombre Xml rompiendo mi xpath!

Tengo el siguiente XML:

      

Esta es una versión reducida de XML que se devuelve desde un servicio web de SharePoint. También tengo el siguiente xPath:

 /List/Fields/Field 

Cuando elimino los xmlns de mi XML, xPath funciona bien. Cuando está allí mi xPath no encuentra nada. ¿Hay algo que debería estar haciendo de manera diferente con mi xPath? Modificar el XML no es una opción.

También tengo el siguiente xPath:

 /List/Fields/Field 

Cuando elimino los xmlns de mi XML, xPath funciona bien. Cuando está allí mi xPath no encuentra nada

Si no puede registrar un enlace de espacio de nombre y no puede usar (suponiendo que el prefijo registrado es “x”):

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

entonces hay otra manera :

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

El elemento List se ha definido con un espacio de nombre predeterminado y todos los elementos dentro de él lo adoptan.

Por lo tanto, debe ignorar el espacio de nombres del elemento así:

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

pero esto significa que el xpath recogerá cualquier otro elemento con List – Fields – Field

Puede hacer una verificación de espacio de nombre así como una verificación de nombre local así:

 /*[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/'] 

O puede registrar el espacio de nombres con la biblioteca y luego especificar explícitamente el prefijo para ese espacio de nombres y agregarlo a la expresión xpath, cuyo método depende de la biblioteca que esté utilizando.

Lo más probable es que tenga que registrar ese espacio de nombres uri con su biblioteca xpath. Dependiendo de la biblioteca, puede usar el prefijo ‘predeterminado’ o puede necesitar darle un prefijo con nombre y usarlo en sus consultas xpath.

Por ejemplo, en php (ya que no especificaste un idioma) usando DOMXPath podrías hacer algo como esto:

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

He estado teniendo este problema mientras uso Xalan-c

El bit que no entendí del todo es que los alias / prefijos del espacio de nombres XPath o XSLT pueden ser diferentes a los del documento, dependiendo de la resolución del espacio de nombres.

Parece que si hay un espacio de nombres en el documento, no puede coincidir con un elemento de ruta a menos que se use un espacio de nombres. (¿estándar pero no siempre seguido?)

XalanDocumentPrefixResolver asignará espacios de nombres XPath o XSLT a URI e intentará darles id obteniendo el prefijo, donde no hay prefijo, utilizó el nombre que se convirtió en xmlns

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

De forma alternativa, podría crear su propia resolución, pero aún así requiere un espacio de nombre mínimo utilizado en xpath 🙁

Aquí hay uno que pirateé mientras probaba, sin garantía de memoria

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

Si puede omitir el elemento del documento, el siguiente XPath también puede ayudar:

 //Fields/Field 

Esto funciona siempre que no tenga ‘Campos’ debajo de ningún otro nodo y mientras los nodos secundarios no tengan espacio de nombre.