XPath es (deliberadamente) no diseñado para el caso en el que desea utilizar la misma expresión XPath para algunos espacios de nombres desconocidos que solo viven en el documento XML. Se espera que conozca el espacio de nombres con anticipación, declare el espacio de nombres en el procesador XPath y use el nombre en su expresión. Las respuestas de Martin y Dan muestran cómo hacer esto en C#.
La razón de esta dificultad se expresa mejor en la XML namespaces especificaciones:
Tenemos la visión de las aplicaciones de lenguaje de marcado extensible (XML) en un único documento XML puede contener elementos y atributos (aquí referido como un " vocabulario de marcado ") que se definen y utilizan por múltiples módulos de software. Una motivación para esto es la modularidad: si existe un vocabulario de marcado que es bien conocido y para el cual hay disponible un software útil, es mejor volver a utilizar este marcado en lugar de reinventarlo.
Dichos documentos, que contienen vocabularios de marcas múltiples, plantean problemas de reconocimiento y colisión. Los módulos de software deben ser capaces de reconocer los elementos y atributos que están diseñados para procesar, incluso frente a las "colisiones" que ocurren cuando el marcado destinado a otro paquete de software utiliza el mismo nombre de elemento o nombre de atributo.
Estas consideraciones requieren que las construcciones de documentos tengan nombres construidos para evitar conflictos entre nombres de diferentes vocabularios de marcado. Esta especificación describe un mecanismo, espacios de nombres XML, que lo logra asignando nombres expandidos a elementos y atributos.
Es decir, se supone que los espacios de nombres que se utiliza para asegurarse de que sabe lo que su documento está hablando: es que <head>
elemento hablando del preámbulo de un documento XHTML o somebodies cabeza en un documento AnatomyML?Nunca se "supone" que sea agnóstico sobre el espacio de nombres y es prácticamente lo primero que debe definir en cualquier vocabulario de XML.
Debería poder hacer lo que quiera, pero no creo que se pueda hacer en una sola expresión XPath. En primer lugar, debe hurgar en el documento y extraer todos los namespaceURI, luego agréguelos al gestor del espacio de nombres y luego ejecute la expresión XPath real que desea (y necesita saber algo sobre la distribución de los espacios de nombres en el documento en este punto, o tienes muchas expresiones para ejecutar). Creo que probablemente sea mejor utilizar algo que no sea XPath (por ejemplo, una API similar a DOM o SAX) para encontrar las URL de espacios de nombres, pero también se puede explorar el eje de espacios de nombres XPath (en XPath 1.0), usar la función (en XPath 2.0) o use expresiones como Oleg's "configuration/*[local-name() = 'MyNode']"
. De todos modos, creo que tu mejor opción es intentar evitar escribir XPath agnóstico en el espacio de nombres. ¿Por qué no conoce su espacio de nombres antes de tiempo? ¿Cómo vas a evitar emparejar cosas que no pretendas igualar?
Editar - saber el namespaceURI?
Así que resulta que su pregunta nos confundió a todos. Aparentemente conoce el URI del espacio de nombres, pero no conoce el prefijo del espacio de nombres que se usa en el documento XML. De hecho, en este caso, no se utiliza ningún prefijo de espacio de nombres y el URI se convierte en el namspace predeterminado donde se define. La clave para saber es que el prefijo elegido (o la falta de un prefijo) es irrelevante para su expresión XPath (y el análisis XML en general). El atributo prefix/xmlns es solo una forma de asociar un nodo con un URI de espacio de nombres cuando el documento se expresa como texto. Es posible que desee echar un vistazo a this answer, donde trato de aclarar los prefijos del espacio de nombres.
Debería tratar de pensar en el documento XML de la misma manera que el analizador lo piensa: cada nodo tiene un URI de espacio de nombres y un nombre local. Las reglas de prefijo/herencia de espacios de nombres simplemente guardan escribir el URI muchas veces. Una forma de escribir esto es en notación Clark: es decir, escribe {http://www.example.com/namespace/example} LocalNodeName, pero esta notación generalmente solo se usa para la documentación: XPath no sabe nada acerca de esta notación.
En su lugar, XPath usa sus propios prefijos de espacio de nombres. Algo así como /ns1:root/ns2:node
. Pero estos están completamente separados y no tienen nada que ver con los prefijos que pueden usarse en el documento XML original. Cualquier implementación de XPath tendrá una forma de mapear sus propios prefijos con URI de espacio de nombres. Para la implementación de C# usted usa un XmlNamespaceManager
, en Perl usted proporciona un hash, xmllint toma argumentos de línea de comando ... Entonces todo lo que necesita hacer es crear algún prefijo arbitrario para el URI de espacio de nombres que conoce, y usar este prefijo en la expresión XPath . No importa qué prefijo use, en XML solo le importa la combinación del URI y el localName.
La otra cosa para recordar (a menudo es una sorpresa) es que XPath no hereda el espacio de nombres. Debe agregar un prefijo para cada uno que tenga un espacio de nombre, independientemente de si el espacio de nombre proviene de la herencia, un atributo xmlns o un prefijo del espacio de nombres. Además, aunque siempre debe pensar en términos de URI y localNames, también hay formas de acceder al prefijo desde un documento XML. Es raro tener que usar estos.
No está claro qué es lo que quiere lograr exactamente. ¿Cuáles son los criterios que determinan qué nodos estás buscando? ¿Estás buscando elementos basados en su espacio de nombres? En ese caso, su código conocería el espacio de nombres. En cuanto a {my uri} es la "sintaxis XPath", ¿en qué parte de la especificación XPath 1.0 cree que se ha definido esa sintaxis? Y si coloca el URI de espacio de nombres entre llaves o si pasa el URI de espacio de nombres al método AddNamespace no debería importarle a su código C#, en ambos casos, el URI de espacio de nombres debe estar disponible como una cadena. –
@Martin: sí quiero especificar el espacio de nombres en XPath, pero solo tengo el URI del espacio de nombres y no hay prefijo del espacio de nombres. Miré más de cerca en donde 'inventé' el {} y podría haber descremado incorrectamente ... Lo obtuve de esta referencia: http://www.jclark.com/xml/xmlns.htm. Gracias por señalar eso. Por supuesto, incluso si no es válido, parece una cosa útil poder hacer fácilmente ...;) –
Scott, tendrá que elegir cualquier prefijo permitido que desee, asociarlo con el URI de espacio de nombres que tiene utilizando AddNamespace (prefix, namespaceURI) y usa el prefijo elegido en tu expresión XPath. Así es como funciona XPath, al menos XPath 1.0. El prefijo no tiene que existir en absoluto en el XML de entrada o puede ser diferente del utilizado en el XML de entrada, la selección del elemento se realizará en función de la coincidencia del espacio de nombres, no del prefijo. –