Produire une nouvelle ligne en XSLT

198

Je veux produire une nouvelle ligne pour la sortie de texte en XSLT. Des idées?

Mithil
la source
11
Je pense qu'il est temps d'accepter la réponse :)
Florjon

Réponses:

240

Le code XSL suivant produira un caractère de nouvelle ligne ( saut de ligne):

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

Pour un retour chariot , utilisez:

<xsl:text>&#xd;</xsl:text>
Florjon
la source
7
+1: c'est plus robuste que l' <xsl:text>approche contenant une nouvelle ligne si vous utilisez quelque chose qui pourrait reformater votre fichier XSL et jouer avec les espaces.
Ian Roberts
49

Ma méthode préférée pour le faire ressemble à:

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

Ensuite, chaque fois que vous voulez sortir une nouvelle ligne (peut-être en csv), vous pouvez sortir quelque chose comme ceci:

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

J'ai utilisé cette technique lors de la sortie de sql à partir d'une entrée xml. En fait, j'ai tendance à créer des variables pour les virgules, les guillemets et les retours à la ligne.

Nic Gibson
la source
3
Veuillez noter que la réponse de Florjon ci-dessous est considérablement plus stable que la mienne.
Nic Gibson
1
Cela vaut probablement la peine d'ajouter la déclaration xml:space="preserve"à l' xsl:textélément pour une stabilité accrue, mais je conviens que la réponse de @ Florjon est probablement plus sûre.
Flynn1179
Cette solution présente l'inconvénient d'inclure également toute indentation, ce qui peut ne pas être souhaitable.
wmassingham
47

Incluez l'attribut Method = "text" sur la balise xsl: output et incluez les retours à la ligne dans votre contenu littéral dans le XSL aux points appropriés. Si vous préférez conserver le code source de votre rangement XSL, utilisez l'entité &#10;où vous voulez une nouvelle ligne.

AnthonyWJones
la source
31

Vous pouvez utiliser: <xsl:text>&#10;</xsl:text>

voir l'exemple

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

si vous écrivez ceci dans un fichier, par exemple

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

cette variable produira un nouveau fichier de ligne comme:

commons-dbcp_commons-dbcp = 1.2.2
junit_junit = 4.4
org.easymock_easymock = 2.4
user878525
la source
6

À mon humble avis, il ne faut pas plus d'informations que @Florjon. Peut-être que quelques petits détails sont laissés pour comprendre pourquoi cela pourrait ne pas fonctionner parfois pour nous.

Tout d'abord, le &#xa(hex) ou le &#10(dec) à l'intérieur d'un <xsl:text/>fonctionnera toujours, mais vous ne le verrez peut-être pas.

  1. Il n'y a pas de nouvelle ligne dans un balisage HTML. Utiliser un simple <br/>fera l'affaire. Sinon, vous verrez un espace blanc. La visualisation de la source à partir du navigateur vous dira ce qui s'est réellement passé. Cependant, il y a des cas où vous vous attendez à ce comportement, surtout si le consommateur n'est pas directement un navigateur. Par exemple, vous souhaitez créer une page HTML et afficher sa structure correctement formatée avec des lignes vides et des identifiants avant de la servir au navigateur.
  2. N'oubliez pas où vous devez utiliser disable-output-escapinget où vous ne l'utilisez pas. Prenez l'exemple suivant où j'ai dû créer un xml à partir d'un autre et déclarer sa DTD à partir d'une feuille de style.

La première version échappe les caractères (par défaut pour 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>

Et voici le résultat:

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

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

Ok, il fait ce que nous attendons, l'échappement est fait pour que les caractères que nous utilisons soient affichés correctement. Le formatage des pièces XML à l'intérieur du nœud racine est géré par ident="yes". Mais en y regardant de plus près, nous voyons que le caractère de nouvelle ligne &#xan'a pas été échappé et traduit tel quel, effectuant un double saut de ligne! Je n'ai pas d'explication à ce sujet, ce sera bon à savoir. N'importe qui?

La deuxième version n'échappe pas aux personnages donc ils produisent ce à quoi ils sont destinés. Le changement effectué était:

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

Et voici le résultat:

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

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

et ce sera ok. Cr et lf sont correctement rendus.

  1. N'oubliez pas que nous parlons nl, pas crlf( nl=lf). Ma première tentative a été d'utiliser uniquement cr: &#xdet alors que le xml de sortie était correctement validé par DOM.

Je visualisais un xml corrompu:

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

L'analyseur DOM n'a pas tenu compte des caractères de contrôle, mais pas le rendu. J'ai passé pas mal de temps à me cogner la tête avant de réaliser à quel point je ne voyais pas ça!

Pour mémoire, j'utilise une variable à l'intérieur du corps avec les deux CRLF juste pour être sûr à 100% que cela fonctionnera partout.

Agoun
la source
4

J'ai ajouté la DOCTYPEdirective que vous voyez ici:

<?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">

Cela me permet d'utiliser &nl;au lieu de &#xa;produire une nouvelle ligne dans la sortie. Comme d'autres solutions, cela est généralement placé à l'intérieur d'une <xsl:text>balise.

Sam Harwell
la source
3

Tu peux essayer,

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

Ça va marcher.

itzmebibin
la source
2

J'appuie la méthode de Nic Gibson, c'était toujours ma préférée:

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

Cependant, j'utilise la tâche Ant <echoxml> pour créer des feuilles de style et les exécuter sur des fichiers. La tâche fera des modèles de valeur d'attribut, par exemple $ {DSTAMP}, mais elle reformatera également votre xml, donc dans certains cas, la référence d'entité est préférable.

<xsl:variable name='nl'><xsl:text>&#xa;</xsl:text></xsl:variable>
Hank Ratzesberger
la source
3
Si vous utilisez une variable, il serait préférable d'utiliser à la selectplace de xsl:text. Exemple: De <xsl:variable name="nl" select="'&#xA;'"/>cette façon, vous ne créez pas un RTF inutile (fragment d'arbre de résultats).
Daniel Haley
2

J'ai trouvé une différence entre les retours à la ligne littéraux dans <xsl:text>et les retours à la ligne littéraux utilisant &#xA;.

Alors que les sauts de ligne littéraux fonctionnaient bien dans mon environnement (en utilisant à la fois Saxon et le processeur Java XSLT par défaut), mon code a échoué lorsqu'il a été exécuté par un autre groupe fonctionnant dans un environnement .NET.

La modification en entités ( &#xA;) a permis à mon code de génération de fichiers de fonctionner de manière cohérente à la fois sur Java et .NET.

De plus, les sauts de ligne littéraux sont susceptibles d'être reformatés par les IDE et peuvent être perdus par inadvertance lorsque le fichier est conservé par quelqu'un «qui n'est pas au courant».

Agnès
la source
2

J'ai remarqué d'après mon expérience que la production d'une nouvelle ligne INSIDE une <xsl:variable>clause ne fonctionne pas. J'essayais de faire quelque chose comme:

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

Tout ce que j'ai essayé de mettre dans cette "nouvelle ligne" (le <xsl:text>nœud vide ) n'a tout simplement pas fonctionné (y compris la plupart des suggestions les plus simples de cette page), sans parler du fait que HTML ne fonctionnera tout simplement pas là, donc finalement je a dû le diviser en 2 variables, les appeler en dehors du <xsl:variable>champ d'application et mettre un simple <br/>entre elles, c'est-à-dire:

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

Ouais, je sais, ce n'est pas la solution la plus sophistiquée mais ça marche, juste partager mon expérience de frustration avec les XSL;)

ShayLivyatan
la source
2

Je ne pouvais pas simplement utiliser l' <xsl:text>&#xa;</xsl:text>approche parce que si je formate le fichier XML en utilisant XSLT, l'entité disparaîtra. J'ai donc dû utiliser une approche un peu plus ronde à l'aide 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>
Archimedes Trajano
la source
-4

ajoutez simplement cette balise:

<br/>

ça marche pour moi ;) .

Ionut Ionete
la source
7
La question concerne la sortie de texte. Votre solution ne fonctionnerait que si la sortie était rendue au format HTML.
oberlies