test namespace examples ejemplo checker xml xpath namespaces

namespace - Cómo recuperar espacios de nombres en archivos XML utilizando Xpath



xpath test (3)

Desafortunadamente, XPath no tiene ningún concepto de "espacio de nombre predeterminado". Necesita registrar espacios de nombres con prefijos con el contexto XPath, y luego usar esos prefijos en sus expresiones XPath. Significa para xpath muy detallado, pero es una deficiencia básica de XPath 1. Aparentemente XPath 2 abordará esto, pero eso no te sirve en este momento.

Sugiero que analice programáticamente su documento XML para el espacio de nombres, asocie ese espacio de nombres con un prefijo en el contexto XPath y luego use el prefijo en las expresiones xpath.

Tengo un archivo XML que comienza así:

<Elements name="Entities" xmlns="XS-GenerationToolElements">

Tendré que abrir muchos de estos archivos. Cada uno de estos tiene un espacio de nombres diferente, pero solo tendrá un espacio de nombres a la vez (nunca encontraré dos espacios de nombres definidos en un archivo xml).

Usando XPath me gustaría tener una manera automática de agregar el espacio de nombres dado al administrador del espacio de nombres. Hasta ahora, solo podía obtener el espacio de nombres analizando el archivo xml, pero tengo una instancia de XPathNavigator y debería tener una forma agradable y limpia de obtener los espacios de nombres, ¿verdad?

- O -

Dado que solo tengo un espacio de nombre, de alguna manera hago que XPath use el único que está presente en el xml, evitando así que el código se atempere al agregar siempre el espacio de nombres.


Hay algunas técnicas que puedes probar; que utilice dependerá exactamente de la información que necesita para salir del documento, cuán rigurosa quiere ser y cuán conforme es la implementación de XPath que está utilizando.

Una forma de obtener el URI de espacio de nombres asociado con un prefijo particular es usar el namespace:: . Esto le dará un nodo de espacio de nombres cuyo nombre es el prefijo y cuyo valor es el URI del espacio de nombres. Por ejemplo, puede obtener el URI del espacio de nombres predeterminado en el elemento del documento utilizando la ruta:

/*/namespace::*[name()='''']

Es posible que pueda usar eso para configurar las asociaciones de espacio de nombres para su XPathNavigator. Tenga en cuenta, sin embargo, que el namespace:: es una de esas esquinas de XPath 1.0 que no siempre se implementa.

Una segunda forma de obtener ese URI de espacio de nombres es usar la función namespace-uri() en el elemento de documento (que, según ha dicho, siempre estará en ese espacio de nombres). La expresion:

namespace-uri(/*)

le dará ese espacio de nombre.

Una alternativa sería olvidarse de asociar un prefijo con ese espacio de nombres, y simplemente hacer su ruta libre de espacio de nombres. Puede hacerlo utilizando la función local-name() siempre que necesite hacer referencia a un elemento cuyo espacio de nombres no conozca. Por ejemplo:

//*[local-name() = ''Element'']

Podrías ir un paso más allá y probar el URI del espacio de nombres del elemento contra el del elemento del documento, si realmente quisieras:

//*[local-name() = ''Element'' and namespace-uri() = namespace-uri(/*)]

Una última opción, dado que el espacio de nombres parece no significar nada para usted, sería ejecutar su XML a través de un filtro que elimine los espacios de nombres. Entonces no tendrás que preocuparte por ellos en tu XPath en absoluto. La forma más sencilla de hacerlo sería simplemente eliminar el atributo xmlns con una expresión regular, pero podría hacer algo más complejo si necesitara hacer otra limpieza al mismo tiempo.


Esta transformación xslt de 40 líneas proporciona toda la información útil sobre los espacios de nombres en un documento XML dado :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext" > <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:key name="kNsByNsUri" match="ns" use="@uri"/> <xsl:variable name="vXmlNS" select="''http://www.w3.org/XML/1998/namespace''"/> <xsl:template match="/"> <xsl:variable name="vrtfNamespaces"> <xsl:for-each select= "//namespace::* [not(. = $vXmlNS) and . = namespace-uri(..) ]"> <ns element="{name(..)}" prefix="{name()}" uri="{.}"/> </xsl:for-each> </xsl:variable> <xsl:variable name="vNamespaces" select="ext:node-set($vrtfNamespaces)/*"/> <namespaces> <xsl:for-each select= "$vNamespaces[generate-id() = generate-id(key(''kNsByNsUri'',@uri)[1]) ]"> <namespace uri="{@uri}"> <xsl:for-each select="key(''kNsByNsUri'',@uri)/@element"> <element name="{.}" prefix="{../@prefix}"/> </xsl:for-each> </namespace> </xsl:for-each> </namespaces> </xsl:template>

Cuando se aplica en el siguiente documento XML:

<a xmlns="my:def1" xmlns:n1="my:n1" xmlns:n2="my:n2" xmlns:n3="my:n3"> <b> <n1:d/> </b> <n1:c> <n2:e> <f/> </n2:e> </n1:c> <n2:g/> </a>

el resultado deseado es producido:

<namespaces> <namespace uri="my:def1"> <element name="a" prefix=""/> <element name="b" prefix=""/> <element name="f" prefix=""/> </namespace> <namespace uri="my:n1"> <element name="n1:d" prefix="n1"/> <element name="n1:c" prefix="n1"/> </namespace> <namespace uri="my:n2"> <element name="n2:e" prefix="n2"/> <element name="n2:g" prefix="n2"/> </namespace> </namespaces>