volver - xmlns c#
XSL: ¿Cómo eliminar los espacios de nombres no utilizados de xml de origen? (3)
Tengo un xml con muchos espacios de nombres no utilizados, como este:
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com" xmlns:ns3="http://www.c.com" xmlns:ns4="http://www.d.com">
<ns1:Body>
<ns2:a>
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
Me gustaría eliminar los espacios de nombres no utilizados sin tener que especificar en el xslt cuáles eliminar / mantener. El resultado xml debe ser este:
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com">
<ns1:Body>
<ns2:a>
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
He buscado en Google pero no he encontrado una solución para este problema en particular. ¿Hay alguna?
Gracias.
PS: No estoy 100% seguro, pero creo que debería ser para XSL 1.0.
Agregando a la respuesta de Dimitre, si esos espacios de nombres deben conservarse y solo ocurren en los valores de los atributos, agregue esta condición: @*[contains(.,concat($vPrefix,'':''))]
:
<xsl:if test= "$vtheElem/descendant::* [namespace-uri() = current() and
substring-before(name(),'':'') = $vPrefix or
@*[substring-before(name(),'':'') = $vPrefix] or
@*[contains(.,concat($vPrefix,'':''))]
]">
Esto conservará correctamente el espacio de nombres ns3
debido a attrib="ns3:Header"
como en el siguiente ejemplo.
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com" xmlns:ns3="http://www.c.com" xmlns:ns4="http://www.d.com">
<ns1:Body ns2:x="1">
<ns2:a>
<ns2:b atrib="ns3:Header">data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
Bien si usas
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="@* | text() | comment() | processing-instruction()">
<xsl:copy/>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
luego se eliminan los espacios de nombres no utilizados, pero el resultado es más probable que se vea como
<ns1:Envelope xmlns:ns1="http://www.a.com">
<ns1:Body>
<ns2:a xmlns:ns2="http://www.b.com">
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
de lo que pediste.
A diferencia de la respuesta de @ Martin-Honnen, esta solución produce exactamente el resultado deseado : los nodos de espacio de nombres necesarios permanecen donde están y no se mueven hacia abajo.
Además, esta solución trata correctamente con los atributos que se encuentran en un espacio de nombres :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*" priority="-2">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:variable name="vtheElem" select="."/>
<xsl:for-each select="namespace::*">
<xsl:variable name="vPrefix" select="name()"/>
<xsl:if test=
"$vtheElem/descendant::*
[(namespace-uri()=current()
and
substring-before(name(),'':'') = $vPrefix)
or
@*[substring-before(name(),'':'') = $vPrefix]
]
">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
cuando esta transformación se aplica en el siguiente documento XML (el documento XML proporcionado con un atributo de espacio de nombre agregado):
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com" xmlns:ns3="http://www.c.com" xmlns:ns4="http://www.d.com">
<ns1:Body ns2:x="1">
<ns2:a>
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
Se produce el resultado correcto y deseado :
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com">
<ns1:Body ns2:x="1">
<ns2:a>
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>