web-dev-qa-db-fra.com

Insérer un saut de ligne dans un PDF produire à partir de XSL FO en utilisant <xsl: valeur-de>

J'utilise XSL FO pour générer un fichier PDF contenant un tableau avec des informations. Une de ces colonnes est une colonne "Description". Voici un exemple de chaîne que je remplis avec l'un de ces champs Description:

This is an example Description.<br/>List item 1<br/>List item 2<br/>List item 3<br/>List item 4

À l'intérieur de la cellule de tableau qui correspond à cette description, j'aimerais que la sortie s'affiche comme telle:

This is an example Description.
List item 1
List item 2
List item 3
List item 4

En cherchant ailleurs, j'ai appris que vous pouvez faire des sauts de ligne en XSL FO en utilisant un <fo:block></fo:block> dans un autre élément <fo:block>. Par conséquent, même avant d'analyser le code XML avec ma feuille de style XSL, je remplace toutes les occurrences de <br/> par <fo:block/>, de sorte que la valeur littérale de la chaîne ressemble maintenant à ceci:

This is an example Description.<fo:block/>List item 1<fo:block/>List item 2<fo:block/>List item 3<fo:block/>List item 4

Le problème se pose lorsque la chaîne de description que j'utilise est obtenue à l'aide de <xsl:value-of>, par exemple:

<fo:block>
    <xsl:value-of select="descriptionStr"/>
</fo:block>

Dans ce cas, la valeur qui est générée dans mon document PDF est la valeur littérale. Elle ressemble donc exactement à l'exemple précédent avec tous les littéraux <fo:block/>. J'ai essayé manuellement de coder en dur le <fo:block/> au milieu d'une autre chaîne et il s'affiche correctement. Par exemple. si j'écris dans ma feuille de style:

<fo:block>Te<fo:block/>st</fo:block>

Il s'affichera correctement comme suit:

Te
st

Mais cela ne semble pas se produire lorsque le <fo:block/> est dans la valeur d'une instruction <xsl:value-of select=""/>. J'ai essayé de rechercher ceci sur SO ainsi que sur Google, etc., sans succès. Tout conseil ou aide sera grandement apprécié. Je vous remercie!

19
Zkoh

Vous ne devriez pas utiliser l'instruction xsl:value-of mais plutôt xsl:apply-templates: pour une règle intégrée, le nœud texte ne doit afficher que la valeur de chaîne. Pour un élément br vide, vous pouvez déclarer une règle correspondant à descriptionStr/br ou descriptionStr//br (selon votre entrée) afin de la transformer en fo:block vide.

5
user357812

Vous pouvez également remplacer <br/> par &#xA; et ajouter un attribut linefeed-treatment="preserve" à votre <fo:block>.

Quelque chose comme:

<fo:block linefeed-treatment="preserve">This is an example Description.&#xA;List item 1&#xA;List item 2&#xA;List item 3&#xA;List item 4</fo:block>

Modifier

Certains utilisateurs peuvent avoir besoin d'utiliser \n au lieu de &#xA; en fonction de la manière dont ils créent le XML. Voir Conserver le & # xA; xml marshalling pour plus de détails.

37
Daniel Haley

Cela m'a aidé et devrait être la solution la plus simple (travailler avec Apache FOP 1.1):

Pourquoi ne pas remplacer votre <br/> par un caractère Unicode appelé séparateur line.

   <xsl:template match="br">
      <xsl:value-of select="'&#x2028;'"/>
   </xsl:template>

Voir https://en.wikipedia.org/wiki/Newline#Unicode

6
j.per

Le code suivant a fonctionné:

<fo:block white-space-collapse="false" 
    white-space-treatment="preserve" 
    font-size="0pt" line-height="15px">.</fo:block>

Cela fait croire au processeur xsl que ce bloc contient une ligne de texte, qui a en fait une taille de police de 0pt. Vous pouvez personnaliser la hauteur de ligne en fournissant votre propre valeur.

5
user2731517

Générer des chaînes contenant un balisage XML échappé est rarement la bonne réponse, mais si c'est avec cela que vous devez travailler, utilisez une entrée comme celle-ci:

<Description><![CDATA[This is an example Description.<br/>List item 1<br/>List item 2<br/>List item 3<br/>List item 4]]></Description>

si vous utilisez XSLT 2.0, vous pouvez utiliser xsl:analyze-string pour obtenir le fo:block vide que vous vouliez à l'origine:

<xsl:template match="Description">
  <fo:block>
    <xsl:analyze-string select="." regex="&lt;br/>">
      <xsl:matching-substring>
        <fo:block />
      </xsl:matching-substring>
      <xsl:non-matching-substring>
        <xsl:value-of select="." />
      </xsl:non-matching-substring>
    </xsl:analyze-string>
  </fo:block>
</xsl:template>

mais si vous utilisez XSLT 2.0, vous pouvez utiliser de manière plus précise linefeed-treatment="preserve" conformément à @ Daniel Haley et utiliser replace() pour insérer les sauts de ligne:

<xsl:template match="Description">
  <fo:block linefeed-treatment="preserve">
    <xsl:value-of select="replace(., '&lt;br/>', '&#xA;')" />
  </fo:block>
</xsl:template>

Si vous utilisez XSLT 1.0, vous pouvez suivre votre chemin dans la chaîne:

<xsl:template match="Description">
  <fo:block linefeed-treatment="preserve">
    <xsl:call-template name="replace-br" />
  </fo:block>
</xsl:template>

<xsl:template name="replace-br">
  <xsl:param name="text" select="." />

  <xsl:choose>
    <xsl:when test="not(contains($text, '&lt;br/>'))">
      <xsl:value-of select="$text" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="substring-before($text, '&lt;br/>')"/>
      <xsl:text>&#xA;</xsl:text> <!-- or <fo:block /> -->
      <xsl:call-template name="replace-br">
        <xsl:with-param name="text" select="substring-after($text, '&lt;br/>')"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
2
Tony Graham

Essaye ça: 

<fo:block><fo:inline color="transparent">x</fo:inline></fo:block>

Ce code ajoute un bloc contenant du texte transparent, le faisant ressembler à une nouvelle ligne.

1
wymeric

Essayez d’utiliser linefeed-treatment = "preserve" et\n au lieu de <br> pour une nouvelle ligne.

<fo:block linefeed-treatment="preserve" >
 <xsl:value-of select="Description" />
</fo:block>
0
zongo

J'utilise généralement un bloc vide d'une hauteur modifiable si j'ai besoin de plus ou moins d'espace:

<fo:block padding-top="5mm" />

Je sais que ce n’est pas la meilleure solution, mais c’est fonctionnel.

0
indemidel

J'ai eu un bloc de texte qui ressemble à ceci

<fo:table-cell display-align="right">
<fo:block font-size="40pt" text-align="right">
    <xsl:text> Text 1 </xsl:text>
    <fo:block> </fo:block>
    <xsl:text> Text2 </xsl:text>
    <fo:block> </fo:block>
    <xsl:text> Text 3</xsl:text>
</fo:block>

NB: notez le vide 

0
stingray_

Pour XSLT 1.0, j'utilise mon Modèle de saut de ligne XSLT sur GitHub.

Pour XSL-FO, il prend en charge

  • Sauts de ligne
  • Délimiteurs de ligne (par rapport aux sauts de ligne)
  • Série de pointeurs d'affilée
  • Ignorer les répétitions de pointeurs (désactivez la série de pointeurs dans une ligne)
  • Toute chaîne en tant que pointeur pour insérer un saut ou un délimiteur ("\ n" par défaut)
  • Hauteur des délimiteurs de lignes
  • Hauteur du délimiteur de ligne par défaut à partir d'une taille de police actuelle.
  • Ignorer automatiquement le caractère "\ r" lors de la recherche d'un lieu de pause.
  • Ajout de la prise en charge de XSLT 2.0 pour une migration transparente.
  • autre chose...

Pour XSLT 2.0 et les versions ultérieures, envisagez d’utiliser des approches telles que

  • XSLT 2.0 xsl: analyse-string (RegEx)
  • XPath 2.0 tokenize + XSLT (RegEx)
  • passer des séquences en tant que paramètre de modèle (XSLT 2.0)
  • etc
0
it3xl