online - Reemplazar el valor de cadena del nodo del espacio de nombres con xslt--- lo que está mal con mi xsl
xslt online (1)
Estoy intentando reemplazar la cadena del espacio de nombres usando xslt.
Tengo la cadena de espacio de nombres de origen y la cadena de espacio de nombres de destino en otro archivo xml en el formato de "namespace source =" xxx "target =" xxx "". Todas las cadenas de espacio de nombres de origen en mi xml a ser transformado deben cambiarse al valor objetivo correspondiente. Solo los elementos deben considerarse como atributos que no tienen espacio de nombres.
Estoy usando el procesador xalan xslt predeterminado de JDK, que es compatible con xslt 1.0. Me gustaría mantener xslt 1.0 si es posible, pero puedo cambiar el procesador y usar xslt 2.0 si es realmente necesario.
Por ejemplo, entrada xml de entrada transformada:
<root xmlns="http://ns1" xmlns:ns2="http://ns2-old" xmlns:ns3="http://ns3">
<ElementA xmlns="http://ns4-old">
<ElementB/>
<ns2:elementD/>
</ElementA>
</root>
El xml de salida debe ser (" http: // ns2-old " se cambia a " http: // ns2-new ", y " http: // ns4-old " se cambia a " http: // ns4-new " )
<root xmlns="http://ns1" xmlns:ns2="http://ns2-new" xmlns:ns3="http://ns3">
<ElementA xmlns="http://ns4-new">
<ElementB/>
<ns2:elementD/>
</ElementA>
</root>
Aquí está mi xsl que no está funcionando:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="nsmapdoc" select="document(''my-map-file'')"/>
<xsl:key name="nsmap" match="//namespace/@target" use="@source"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- process each element -->
<xsl:template match="element()">
<xsl:for-each select="namespace::*">
<!-- for each namespace node of the element, save the string value-->
<xsl:variable name="sourceuri"><xsl:value-of select="."/>
</xsl:variable>
<!-- get the target value for this namespace-->
<xsl:variable name="targeturi">
<xsl:for-each select="$nsmapdoc">
<xsl:value-of select="key(''nsmap'', $sourceuri)"/>
</xsl:for-each>
</xsl:variable>
<!-- if target value exists, replace the current namespace node string value with the target value-->
<xsl:if test="$targeturi">
<xsl:value-of select="$targeturi"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Tengo algunas preguntas:
Para la plantilla de identidad que hace la copia, ¿por qué hacer "match =" node () | @ * "en lugar de simplemente" match = "node ()"? ¿El atributo también es un nodo?
No estoy seguro de haberlo hecho correctamente para obtener el valor de la cadena del espacio de nombres (como " http: // ns1 ", " http: // ns2-old ") para el elemento.
Creo que obtuve la clave correctamente. Sin embargo, no estoy seguro si usé el tipo correctamente --- parece que la variable targeturi no es una cadena. Si la clave no tiene la entrada, ¿qué buscará la entrada? En mi caso, debería reemplazar el valor del espacio de nombres solo para el espacio de nombres que tiene una entrada en el mapa.
¿Cómo escribir un nuevo valor de cadena para el nodo de espacio de nombres?
Necesito procesar cada nodo de espacio de nombres para el elemento. ¿Es la forma correcta de definir una variable en el interior?
por favor ayuda a ver qué está mal con mi xsl. Cualquier sugerencia es apreciada.
Creo que tienes dos, posiblemente tres, preguntas separadas aquí.
La primera pregunta es: cómo mover elementos de un espacio de nombres a otro, utilizando un "mapa" de espacios de nombres de origen a destino. Déjame responder esta pregunta primero. Dado:
XML
<root xmlns="http://ns1" xmlns:ns2="http://ns2-old" xmlns:ns3="http://ns3">
<ElementA xmlns="http://ns4-old">
<ElementB/>
<ns2:ElementD/>
</ElementA>
</root>
map.xml
<root>
<namespace source="http://ns2-old" target="http://ns2-new"/>
<namespace source="http://ns4-old" target="http://ns4-new"/>
</root>
La siguiente hoja de estilo:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:param name="nsmapdoc" select="document(''map.xml'')"/>
<xsl:template match="*">
<xsl:variable name="old-ns" select="namespace-uri()"/>
<xsl:variable name="map-entry" select="$nsmapdoc/root/namespace[@source=$old-ns]"/>
<xsl:variable name="new-ns">
<xsl:choose>
<xsl:when test="$map-entry">
<xsl:value-of select="$map-entry/@target"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$old-ns"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{local-name()}" namespace="{$new-ns}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
volverá:
<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://ns1">
<ElementA xmlns="http://ns4-new">
<ElementB/>
<ElementD xmlns="http://ns2-new"/>
</ElementA>
</root>
Nota :
ElementA y su hijo ElementB se han movido del URI de espacio de nombres " http: // ns4-old " a URI " http: // ns4-new ";
ElementD se ha movido del URI de espacio de nombres " http: // ns2-old " a URI " http: // ns2-new ";
El prefijo de ElementD ha sido eliminado; esto es un cambio cosmético sin sentido, y no debería presentar ningún problema para la aplicación receptora;
El elemento raíz ha permanecido en su espacio de nombre original;
Las declaraciones de espacio de nombres no utilizadas se han descartado.
Tenga en cuenta también que no estamos utilizando una clave para buscar el nuevo espacio de nombres: usar una clave entre documentos es bastante incómodo en XSLT 1.0 y he decidido prescindir de ella.
La segunda pregunta es cómo copiar las declaraciones de espacios de nombres no utilizados. Hay varias respuestas posibles para elegir:
No es necesario copiarlos, ya que no se usan para nada;
No es posible copiarlos;
Es posible copiarlos copiando algún elemento del documento fuente; sin embargo, copiar un elemento también copia su espacio de nombre, por lo que esto solo se puede hacer si hay un elemento conocido que se supone que debe permanecer en su espacio de nombre original. Por ejemplo, si sabe de antemano que el elemento raíz no se debe mover a otro espacio de nombre, puede agregar otra plantilla a la hoja de estilo:
para obtener este resultado:
<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://ns1" xmlns:ns2="http://ns2-old" xmlns:ns3="http://ns3">
<ElementA xmlns="http://ns4-new">
<ElementB/>
<ElementD xmlns="http://ns2-new"/>
</ElementA>
</root>