2011-05-06 24 views
22

Necesitaba usar XSL para generar un resultado de texto simple desde XML. Como no encontré ningún ejemplo bueno y conciso en línea, decidí publicar mi solución aquí. Cualquier enlaces en referencia a un ejemplo mejor sería, por supuesto, se apreciará:use xsl para enviar texto sin formato

<?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 han ayudado aquí:

  1. el uso de XSL: salida de omitir la declaración normalizada al principio del documento de salida
  2. el uso del atributo xml: space = "preserve" para conservar cualquier espacio en blanco que haya escrito dentro de la etiqueta xsl: for-each. Esto también me obligó a escribir 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 sangría xml estándar aquí.

El resultante y de salida deseado para este XSLT fue:

en Alluser -f 23:58 17.4.2010
en ggroup67 -f 07:58 28.4.2010
en -f ggroup70 15: 58 18.4.2010
en Alluser -f 23:58 18.4.2010
en ggroup61 -f 7:58 22.9.2010
en -f ggroup60 23:58 21.9.2010
en Alluser -f 03: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 estoy tratando a:

<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> 
+1

Puede ahorrar en el número de elementos '' usando 'concat ('at -f', username, '', startTime/@ hours, '', ...)'. Además, podría envolver su código fuente; si lo hace dentro de las etiquetas, no afectará la salida. –

+0

Buena pregunta, +1. Vea mi respuesta para una solución completa, muy corta y realmente genérica. –

+0

@Christopher Creutzig: Gracias por la gran sugerencia sobre concat(). ¿A qué te refieres con "envolver tu código fuente"? – Chris

Respuesta

21
  • Se puede definir una plantilla para que coincida con el script/command y eliminar la xsl:for-each
  • concat() se puede utilizar para acortar la expresión y evitar insertar explícitamente tantas <xsl:text> y <xsl:value-of> elementos.
  • El uso de una referencia de entidad &#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 de 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> 
+0

Gracias Mads, excelentes sugerencias. Esto es exactamente lo que estaba buscando. Había olvidado las características útiles de XPath 2 ... ¿Cómo es que me da una nueva línea en Windows, cuando Windows generalmente requiere no solo un avance de línea, sino también un retorno de carro? – Chris

+1

@Chris Dickinson Tenga en cuenta, esta es una solución XSLT/XPath 1.0, no se utilizan funciones XPath 2.0. ' ' (Line Feed) suele ser suficiente. Puede agregar ' ' (retorno de carro) si necesita CRLF. –

7

Sólo por diversión: esto se puede hacer de una manera muy general y compacto:

<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 querido, resultado 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 es mejor genaral aplicable si todos los datos se impriman está contenida en los nodos de texto - no en atributos.

+0

Faltan los valores @ * (y se suponía que estaban delimitados por ':'). Además, no estoy seguro de si los espacios iniciales antes de 'at -f' en la salida serían un problema. –

+0

@Mads Hansen: Gracias por notar esto. Corregido ahora. –

+0

Casi, pero no creo que el código fuente XML tenga ':' en el valor de '@ horas'. La muestra XSL publicada pone explícitamente ':' en, no seleccionando desde el valor del atributo. –

Cuestiones relacionadas