ver - xml xslt ejemplo
Cambiar el nombre de los nodos con XSLT (2)
Estoy intentando algo muy simple, pero por alguna razón no funciona. Básicamente, necesito cambiar el nombre de algunos nodos en un documento XML. Por lo tanto, creé un archivo XSLT para hacer la transformación.
Aquí hay un ejemplo del XML:
EDITAR: las direcciones y los elementos de Dirección ocurren en muchos niveles. Esto es lo que me llevó a tener que probar y aplicar un XSLT. La función de conjunto de datos tipeados de Visual Studio, que crea conjuntos de datos tipeados a partir de archivos XSD, no le permite tener referencias anidadas a la misma tabla. Por lo tanto, tener Negocios / Negocios / Direcciones y Negocios / Negocios / Contacto / Direcciones hace que la Carga () falle. Este es un problema conocido, y todo lo que le dicen es algo así como "No tiene referencias de tablas anidadas ... edite su XSD para dejar de tener eso". Desafortunadamente, esto significa que tenemos que aplicar XSLT para hacer que el XML se ajuste al XSD "pirateado", ya que los archivos provienen de un proveedor externo.
Entonces, estamos muy cerca con la ayuda prestada aquí. Las últimas dos cosas son estas:
1.) ¿Cómo puedo usar la referencia del espacio de nombres en el atributo de coincidencia de la plantilla xsl: para especificar que deseo cambiar el nombre de Negocios / Negocios / Direcciones a BusinessAddresses, pero renombrar Businesses / Business / Contacts / Contact / Addresses a ContactAddresses?
2.) ¿Cómo puedo evitar que el XSLT atempere cada nuevo elemento con referencias explícitas al espacio de nombres? Está causando una hinchazón extrema en la salida.
Creé un espacio de nombres llamado "acero" y estaba teniendo éxito con:
<xsl:template match="steel:Addresses>
<xsl:element name="BusinessAddresses>
</xsl:template>
El problema obvio aquí es que cambia el nombre de TODOS los elementos de direcciones a BusinessAddresses, aunque quiero que algunos de ellos se llamen ContactAddresses, y así sucesivamente. La adición innecesaria de referencias de espacio de nombres explícitas a todos los nodos renombrados también es problemática.
Intenté este tipo de cosas, pero tan pronto como agregue barras diagonales al atributo de coincidencia, es un error de sintaxis en el XSLT, así:
<xsl:template match="steel:/Businesses/Business/Addresses">
Me siento muy cerca, pero necesito alguna guía sobre cómo mezclar el uso del espacio de nombres y una forma de usar las barras para seleccionar CUALQUIER nodo bajo rutas específicas.
<?xml version="1.0"?>
<Businesses>
<Business>
<BusinessName>Steel Stretching</BusinessName>
<Addresses>
<Address>
<City>Pittsburgh</City>
</Address>
<Address>
<City>Philadelphia</City>
</Address>
</Addresses>
<Contacts>
<Contact>
<FirstName>Paul</FirstName>
<LastName>Jones</LastName>
<Addresses>
<Address>
<City>Pittsburgh</City>
</Address>
</Addresses>
</Contact>
</Contacts>
</Business>
<Business>
<BusinessName>Iron Works</BusinessName>
<Addresses>
<Address>
<City>Harrisburg</City>
</Address>
<Address>
<City>Lancaster</City>
</Address>
</Addresses>
</Business>
</Businesses>
Necesito cambiar el nombre de las Direcciones a BusinessAddresses, y necesito cambiar el nombre de Dirección a BusinessAddress, para cada instancia de Direcciones y Dirección directamente debajo de un nodo Business. También necesito cambiar el nombre de Direcciones a ContactAddresses, y necesito cambiar el nombre de Dirección a ContactAddress, para cada instancia de Direcciones y Dirección directamente debajo de un Nodo de Contacto.
He intentado varias soluciones, pero ninguna parece funcionar. Todos terminan produciendo el mismo XML que el archivo original.
Aquí hay un ejemplo de lo que he intentado:
<xsl:template match="/">
<xsl:apply-templates select="@*|node()" />
</xsl:template>
<xsl:template match="@*|*">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Addresses">
<BusinessAddresses>
<xsl:apply-templates select="@*|node()" />
</BusinessAddresses>
</xsl:template>
Esto se ha intentado en al menos 6 sabores diferentes, completando con el depurador XSLT en VB.Net. Nunca ejecuta la coincidencia de plantilla para Direcciones.
¿Por qué?
¿Por qué podría fallar un XSLT?
Un XSLT fallará debido a cosas obvias como errores tipográficos. Sin embargo, la situación más probable se relaciona con el uso del espacio de nombres. Si declaró un espacio de nombre predeterminado para su XML pero no lo incluye en su XSLT, XSLT no coincidirá con las plantillas como podría esperar.
El siguiente ejemplo agrega el atributo xmlns:business
que declara que los elementos calificados por el prefijo business
pertenecen al espacio de nombres mynamespace.uri
. Luego usé este prefijo para calificar las coincidencias de la plantilla Dirección y Direcciones. Por supuesto, tendrá que cambiar el URI del espacio de nombres a lo que coincida con el espacio de nombres predeterminado de su archivo XML.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:business="mynamespace.uri"
exclude-result-prefixes="msxsl">
<xsl:template match="/">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="business:Addresses">
<xsl:element name="BusinessAddresses">
<xsl:apply-templates select="@*|node()" />
</xsl:element>
</xsl:template>
<xsl:template match="business:Address">
<xsl:element name="BusinessAddress">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
¿Cómo relaciona las plantillas según la ubicación del elemento y el nombre?
Hay varias maneras de lograr esta última parte para su problema, BusinessAddress o ContactAddress, pero lo más fácil es modificar los atributos de match
la plantilla para considerar los nodos principales. Si considera el atributo de match
como una ruta en el XML para un nodo, esta opción se vuelve más clara (el contenido de las plantillas se omite por brevedad):
<xsl:template match="business:Business/business:Addresses>
</xsl:template>
<xsl:template match="business:Business/business:Addresses/business:Address">
</xsl:template>
<xsl:template match="business:Contact/business:Addresses">
</xsl:template>
<xsl:template match="business:Contact/business:Addresses/business:Address">
</xsl:template>
Existen otros métodos para lograr esto si la match
se basa solo en el nombre del elemento, pero son más difíciles de implementar, seguir y mantener ya que implican el uso de comprobaciones condicionales en la jerarquía del nodo padre del elemento que se procesa, todo dentro la plantilla.
Quizás esto, si la información que muestra es realmente como con la que trabajaste
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Businesses">
<Businesses>
<xsl:apply-templates/>
</Businesses>
</xsl:template>
<xsl:template match="*">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="Addresses">
<BusinessAddresses>
<xsl:apply-templates/>
</BusinessAddresses>
</xsl:template>
<xsl:template match="Addresses/Address">
<BusinessAddress>
<xsl:value-of select="."/>
</BusinessAddress>
</xsl:template>
</xsl:stylesheet>