xml xslt foreach plaintext line-breaks

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í:

  1. el uso de xsl: output para omitir la declaración estándar al comienzo del documento de salida
  2. 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).
  3. 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 el xsl: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 &#xA; 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 ,''&#xA;'')"/> </xsl:template> </xsl:stylesheet>