Produciendo una nueva línea en XSLT

198

Quiero producir una nueva línea para la salida de texto en XSLT. ¿Algunas ideas?

Mithil
fuente
11
Creo que es hora de aceptar la respuesta :)
Florjon

Respuestas:

240

El siguiente código XSL producirá un carácter de nueva línea (avance de línea):

<xsl:text>&#xa;</xsl:text>

Para un retorno de carro , use:

<xsl:text>&#xd;</xsl:text>
Florjon
fuente
77
+1: esto es más robusto que el que <xsl:text>contiene un enfoque de nueva línea si usa cualquier cosa que pueda formatear su archivo XSL y ensuciar el espacio en blanco.
Ian Roberts el
49

Mi método preferido para hacer esto se parece a:

<xsl:stylesheet>

<xsl:output method='text'/>

<xsl:variable name='newline'><xsl:text>
</xsl:text></xsl:variable>

<!-- note that the layout there is deliberate -->

...

</xsl:stylesheet>

Luego, cada vez que desee generar una nueva línea (quizás en csv) puede generar algo como lo siguiente:

<xsl:value-of select="concat(elem1,elem2,elem3,$newline)" />

He usado esta técnica al generar sql desde la entrada xml. De hecho, tiendo a crear variables para comas, comillas y líneas nuevas.

Nic Gibson
fuente
3
Tenga en cuenta que la respuesta de Florjon a continuación es considerablemente más estable que la mía.
Nic Gibson
1
Probablemente valga la pena agregar la declaración xml:space="preserve"al xsl:textelemento para una mayor estabilidad, pero estoy de acuerdo en que la respuesta de @ Florjon es probablemente más segura.
Flynn1179
Esta solución tiene el inconveniente de incluir también cualquier sangría, que puede no ser deseable.
wmassingham
47

Incluya el atributo Method = "text" en la etiqueta xsl: output e incluya nuevas líneas en su contenido literal en el XSL en los puntos apropiados. Si prefiere mantener el código fuente de su XSL ordenado, use la entidad &#10;donde desea una nueva línea.

AnthonyWJones
fuente
31

Puedes usar: <xsl:text>&#10;</xsl:text>

ver el ejemplo

<xsl:variable name="module-info">
  <xsl:value-of select="@name" /> = <xsl:value-of select="@rev" />
  <xsl:text>&#10;</xsl:text>
</xsl:variable>

si escribe esto en el archivo, por ejemplo

<redirect:write file="temp.prop" append="true">
  <xsl:value-of select="$module-info" />
</redirect:write>

Esta variable producirá un nuevo archivo de línea como:

commons-dbcp_commons-dbcp = 1.2.2
junit_junit = 4.4
org.easymock_easymock = 2.4
usuario878525
fuente
6

En mi humilde opinión, no se necesita más información de la que @Florjon dio. Tal vez se dejen algunos pequeños detalles para entender por qué a veces podría no funcionar para nosotros.

En primer lugar, el &#xa(hex) o &#10(dec) dentro de a <xsl:text/>siempre funcionará, pero es posible que no lo veas.

  1. No hay nueva línea en un marcado HTML. Usar un simple <br/>lo hará bien. De lo contrario, verá un espacio en blanco. Ver la fuente desde el navegador le dirá lo que realmente sucedió. Sin embargo, hay casos en los que espera este comportamiento, especialmente si el consumidor no es directamente un navegador. Por ejemplo, desea crear una página HTML y ver su estructura bien formateada con líneas vacías e ideas antes de publicarla en el navegador.
  2. Recuerde dónde debe usar disable-output-escapingy dónde no. Tome el siguiente ejemplo donde tuve que crear un xml de otro y declarar su DTD desde una hoja de estilo.

La primera versión escapa a los caracteres (por defecto para xsl: text)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" encoding="utf-8"/>

    <xsl:template match="/">
        <xsl:text>&lt;!DOCTYPE Subscriptions SYSTEM "Subscriptions.dtd"&gt;&#xa;&#xa;&#xd;</xsl:text>
        <xsl:copy>
            <xsl:apply-templates select="*" mode="copy"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="@*|node()" mode="copy">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" mode="copy"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

y aqui esta el resultado:

<?xml version="1.0" encoding="utf-8"?>
&lt;!DOCTYPE Subscriptions SYSTEM "Subscriptions.dtd"&gt;

&#13;<Subscriptions>
    <User id="1"/>   
</Subscriptions>

Ok, hace lo que esperamos, el escape se realiza para que los caracteres que utilizamos se muestren correctamente. El formato de parte XML dentro del nodo raíz es manejado por ident="yes". Pero con una mirada más cercana , vemos que el carácter de nueva línea &#xano se escapó y se tradujo como está, ¡realizando un salto de línea doble! No tengo una explicación sobre esto, será bueno saberlo. ¿Nadie?

La segunda versión no escapa de los personajes, por lo que están produciendo para lo que están destinados. El cambio realizado fue:

<xsl:text disable-output-escaping="yes">&lt;!DOCTYPE Subscriptions SYSTEM "Subscriptions.dtd"&gt;&#xa;&#xa;&#xd;</xsl:text>

y aqui esta el resultado:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Subscriptions SYSTEM "Subscriptions.dtd">

<Subscriptions>
    <User id="1"/>   
</Subscriptions>

y eso estará bien Tanto cr como lf se representan correctamente.

  1. No olvides que estamos hablando nl, no crlf( nl=lf). Mi primer intento fue usar solo cr: &#xdy aunque el xml de salida fue validado por DOM correctamente.

Estaba viendo un xml dañado:

<?xml version="1.0" encoding="utf-8"?>
<Subscriptions>riptions SYSTEM "Subscriptions.dtd">
    <User id="1"/>   
</Subscriptions>

El analizador DOM no tuvo en cuenta los caracteres de control, pero el renderizado no. ¡Pasé bastante tiempo golpeándome la cabeza antes de darme cuenta de lo tonto que no estaba viendo esto!

Para el registro, uso una variable dentro del cuerpo con ambos CRLF solo para estar 100% seguro de que funcionará en todas partes.

Agoun
fuente
4

Agregué la DOCTYPEdirectiva que ves aquí:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
  <!ENTITY nl "&#xa;">
]>
<xsl:stylesheet xmlns:x="http://www.w3.org/2005/02/query-test-XQTSCatalog"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.0">

Esto me permite usar en &nl;lugar de &#xa;producir una nueva línea en la salida. Al igual que otras soluciones, esto generalmente se coloca dentro de una <xsl:text>etiqueta.

Sam Harwell
fuente
3

Puedes probar,

<xsl:text>&#xA;</xsl:text>

Funcionará.

itzmebibin
fuente
2

Secundo el método de Nic Gibson, este siempre fue mi favorito:

<xsl:variable name='nl'><xsl:text>
</xsl:text></xsl:variable>

Sin embargo, he estado usando la tarea Ant <echoxml> para crear hojas de estilo y ejecutarlas contra archivos. La tarea hará plantillas de valor de atributo, por ejemplo, $ {DSTAMP}, pero también formateará su xml, por lo que en algunos casos, la referencia de entidad es preferible.

<xsl:variable name='nl'><xsl:text>&#xa;</xsl:text></xsl:variable>
Hank Ratzesberger
fuente
3
Si usa una variable, sería mejor usarla en selectlugar de xsl:text. Ejemplo: de <xsl:variable name="nl" select="'&#xA;'"/>esa manera no se crea un RTF innecesario (fragmento de árbol de resultados).
Daniel Haley
2

He encontrado una diferencia entre las nuevas <xsl:text>líneas literales y las nuevas líneas literales usando&#xA; .

Si bien las nuevas líneas literales funcionaron bien en mi entorno (utilizando Saxon y el procesador XSLT Java predeterminado), mi código falló cuando fue ejecutado por otro grupo que se ejecuta en un entorno .NET.

Cambiar a entidades (&#xA; ) hizo que mi código de generación de archivos se ejecutara de manera consistente tanto en Java como en .NET.

Además, las nuevas líneas literales son vulnerables a ser formateadas por IDEs y pueden perderse sin darse cuenta cuando alguien que no está al tanto mantiene el archivo.

Inés
fuente
2

He notado por mi experiencia que producir una nueva línea DENTRO de una <xsl:variable>cláusula no funciona. Estaba tratando de hacer algo como:

<xsl:variable name="myVar">
  <xsl:choose>
    <xsl:when test="@myValue != ''">
      <xsl:text>My value: </xsl:text>
      <xsl:value-of select="@myValue" />
      <xsl:text></xsl:text> <!--NEW LINE-->
      <xsl:text>My other value: </xsl:text>
      <xsl:value-of select="@myOtherValue" />
    </xsl:when>
  </xsl:choose>
<xsl:variable>

<div>
  <xsl:value-of select="$myVar"/>
</div>

Todo lo que intenté poner en esa "nueva línea" (el <xsl:text>nodo vacío ) simplemente no funcionó (incluidas la mayoría de las sugerencias más simples en esta página), sin mencionar el hecho de que HTML simplemente no funcionará allí, así que eventualmente tuvo que dividirlo en 2 variables, llamarlas fuera del <xsl:variable>alcance y poner un simple <br/>entre ellas, es decir:

<xsl:variable name="myVar1">
  <xsl:choose>
    <xsl:when test="@myValue != ''">
      <xsl:text>My value: </xsl:text>
      <xsl:value-of select="@myValue" />
    </xsl:when>
  </xsl:choose>
<xsl:variable>

<xsl:variable name="myVar2">
  <xsl:choose>
    <xsl:when test="@myValue != ''">
      <xsl:text>My other value: </xsl:text>
      <xsl:value-of select="@myOtherValue" />
    </xsl:when>
  </xsl:choose>
<xsl:variable>

<div>
  <xsl:value-of select="$myVar1"/>
  <br/>
  <xsl:value-of select="$myVar2"/>
</div>

Sí, lo sé, no es la solución más sofisticada, pero funciona, solo compartiendo mi experiencia de frustración con XSL;)

ShayLivyatan
fuente
2

No podría simplemente usar el <xsl:text>&#xa;</xsl:text>enfoque porque si formateo el archivo XML usando XSLT, la entidad desaparecerá. Así que tuve que usar un enfoque un poco más redondo sobre el uso de variables

<xsl:variable name="nl" select="'&#10;'"/>
<xsl:template match="/">
    <xsl:value-of select="$nl" disable-output-escaping="no"/>
    <xsl:apply-templates select="*"/>
</xsl:template>
Arquímedes Trajano
fuente
-4

solo agrega esta etiqueta:

<br/>

esto funciona para mi ;) .

Ionut Ionete
fuente
77
La pregunta es sobre la salida de texto. Su solución solo funcionaría si el resultado se representara como HTML.
Oberlies