xml - use xsl para enviar texto sin formato
xslt foreach (2)
Necesitaba usar XSL para generar un resultado simple de texto plano desde XML. Como no encontré ningún ejemplo bueno y conciso en línea, decidí publicar mi solución aquí. Cualquier enlace que se refiera a un mejor ejemplo sería apreciado:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" >
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="script/command" xml:space="preserve">at -f <xsl:value-of select="username"/> <xsl:value-of select="startTime/@hours"/>:<xsl:value-of select="startTime/@minutes"/> <xsl:value-of select="startDate"/><xsl:text>
</xsl:text></xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Algunas cosas importantes que me ayudaron aquí:
- el uso de xsl: output para omitir la declaración estándar al comienzo del documento de salida
- el uso del atributo xml: space = "preserve" para preservar cualquier espacio en blanco que escribí dentro de la etiqueta xsl: for-each. Esto también requiere que escriba todo el código dentro de la etiqueta for-each, incluyendo esa etiqueta también, en una sola línea (con la excepción del salto de línea).
- el uso de para insertar un salto de línea - nuevamente tuve que omitir la sangría xml estándar aquí.
La salida resultante y deseada para este xslt fue:
at -f alluser 23:58 17.4.2010
en -f ggroup67 7:58 28.4.2010
at -f ggroup70 15:58 18.4.2010
at -f alluser 23:58 18.4.2010
en -f ggroup61 7:58 22.9.2010
at -f ggroup60 23:58 21.9.2010
at -f alluser 3:58 22.9.2010
Como dije, cualquier sugerencia de cómo hacer esto de manera más elegante sería apreciada.
SEGUIMIENTO 2011-05-08:
Este es el tipo de xml que estoy tratando:
<script xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="script.xsd">
<command>
<username>alluser</username>
<startTime minutes="58" hours="23"/>
<startDate>17.4.2010</startDate>
</command>
</script>
Solo por diversión: esto se puede hacer de una manera muy general y compacta :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:apply-templates select="node()|@*"/>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="username">
at -f <xsl:apply-templates select="*|@*"/>
</xsl:template>
</xsl:stylesheet>
cuando se aplica en este documento XML :
<script>
<command>
<username>John</username>
<startTime hours="09:" minutes="33"/>
<startDate>05/05/2011</startDate>
<username>Kate</username>
<startTime hours="09:" minutes="33"/>
<startDate>05/05/2011</startDate>
<username>Peter</username>
<startTime hours="09:" minutes="33"/>
<startDate>05/05/2011</startDate>
</command>
</script>
el resultado deseado y correcto se produce:
at -f 09:33 05/05/2011
at -f 09:33 05/05/2011
at -f 09:33 05/05/2011
Nota : Este enfoque genaral es mejor aplicable si todos los datos que se emiten están contenidos en nodos de texto, no en atributos.
- Puede definir una plantilla para que coincida con el
script/command
y eliminar elxsl:for-each
-
concat()
se puede utilizar para acortar la expresión y evitar que inserte explícitamente tantos elementos<xsl:text>
y<xsl:value-of>
. - El uso de una entidad de referencia


para el retorno de carro, en lugar de confiar en preservar el salto de línea entre su elemento<xsl:text>
es un poco más seguro, ya que el formato del código no estropeará sus saltos de línea. Además, para mí, se lee como un salto de línea explícito y es más fácil de entender el intento.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format" >
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:template match="script/command">
<xsl:value-of select="concat(''at -f ''
,username
,'' ''
,startTime/@hours
,'':''
,startTime/@minutes
,'' ''
,startDate
,''
'')"/>
</xsl:template>
</xsl:stylesheet>