Produzindo uma nova linha em XSLT

198

Eu quero produzir uma nova linha para saída de texto em XSLT. Alguma ideia?

Mithil
fonte
11
Eu acho, é hora de aceitar a resposta :)
Florjon

Respostas:

240

O seguinte código XSL produzirá um caractere de nova linha (avanço de linha):

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

Para um retorno de carro , use:

<xsl:text>&#xd;</xsl:text>
Florjon
fonte
7
+1: é mais robusto do que o que <xsl:text>contém uma abordagem de nova linha se você usar qualquer coisa que possa reformatar seu arquivo XSL e mexer com o espaço em branco.
11261 Ian Roberts
49

Meu método preferido para fazer isso se parece com:

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

Então, sempre que você desejar gerar uma nova linha (talvez em csv), poderá gerar algo como o seguinte:

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

Eu usei essa técnica ao gerar sql a partir da entrada xml. De fato, costumo criar variáveis ​​para vírgulas, aspas e novas linhas.

Nic Gibson
fonte
3
Observe que a resposta de Florjon abaixo é consideravelmente mais estável que a minha.
precisa
1
Provavelmente vale a pena adicionar a declaração xml:space="preserve"ao xsl:textelemento para aumentar a estabilidade, mas eu concordo que a resposta de @ Florjon é provavelmente mais segura.
Flynn1179
Esta solução tem a desvantagem de incluir também qualquer recuo, o que pode não ser desejável.
217156 wanderingham
47

Inclua o atributo Method = "text" na tag xsl: output e inclua novas linhas no seu conteúdo literal no XSL nos pontos apropriados. Se você preferir manter o código-fonte do seu XSL organizado, use a entidade &#10;em que deseja uma nova linha.

AnthonyWJones
fonte
31

Você pode usar: <xsl:text>&#10;</xsl:text>

veja o exemplo

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

se você escrever isso no arquivo, por exemplo

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

essa variável produzirá uma nova linha infile como:

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

IMHO, não são necessárias mais informações do que @Florjon deu. Talvez alguns pequenos detalhes sejam deixados para entender por que às vezes isso não funciona para nós.

Primeiro de tudo, o &#xa(hex) ou &#10(dec) dentro de um <xsl:text/>sempre funcionará, mas você pode não vê-lo.

  1. Não há nova linha em uma marcação HTML. Usando um simples <br/>vai fazer bem. Caso contrário, você verá um espaço em branco. Visualizar a fonte do navegador informa o que realmente aconteceu. No entanto, há casos em que você espera esse comportamento, principalmente se o consumidor não for diretamente um navegador. Por exemplo, você deseja criar uma página HTML e visualizar sua estrutura bem formatada com linhas e identificadores vazios antes de veiculá-la no navegador.
  2. Lembre-se de onde você precisa usar disable-output-escapinge onde não precisa . Pegue o exemplo a seguir, onde eu tive que criar um xml de outro e declarar seu DTD em uma folha de estilo.

A primeira versão escapa dos caracteres (padrão 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>

E aqui está o resultado:

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

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

Ok, faz o que esperamos, o escape é feito para que os caracteres que usamos sejam exibidos corretamente. A formatação da parte XML dentro do nó raiz é tratada por ident="yes". Mas, olhando mais de perto , vemos que o caractere de nova linha &#xanão foi escapado e traduzido como está, realizando um avanço de linha duplo! Eu não tenho uma explicação sobre isso, será bom saber. Qualquer um?

A segunda versão não escapa aos personagens, então eles estão produzindo o que devem fazer. A alteração feita foi:

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

E aqui está o resultado:

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

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

e tudo ficará bem. Cr e lf são renderizados corretamente.

  1. Não esqueça que estamos falando nl, não crlf( nl=lf). Minha primeira tentativa foi usar apenas cr: &#xde enquanto o xml de saída foi validado pelo DOM corretamente.

Eu estava vendo um xml corrompido:

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

O analisador DOM desconsiderou os caracteres de controle, mas o renderizado não. Passei bastante tempo batendo minha cabeça antes de perceber o quão bobo eu não estava vendo isso!

Para o registro, eu uso uma variável dentro do corpo com os dois CRLF apenas para ter 100% de certeza de que funcionará em qualquer lugar.

Agoun
fonte
4

Eu adicionei a DOCTYPEdiretiva que você vê aqui:

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

Isso me permite usar em &nl;vez de &#xa;produzir uma nova linha na saída. Como outras soluções, isso geralmente é colocado dentro de uma <xsl:text>tag.

Sam Harwell
fonte
3

Podes tentar,

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

Vai funcionar.

itzmebibin
fonte
2

Segundo o método de Nic Gibson, esse sempre foi o meu favorito:

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

No entanto, tenho usado a tarefa Ant <echoxml> para criar folhas de estilo e executá-las em arquivos. A tarefa criará modelos de valor de atributo, por exemplo, $ {DSTAMP}, mas também reformatará seu xml; portanto, em alguns casos, a referência da entidade é preferível.

<xsl:variable name='nl'><xsl:text>&#xa;</xsl:text></xsl:variable>
Hank Ratzesberger
fonte
3
Se você usar uma variável, seria melhor usar em selectvez de xsl:text. Exemplo: <xsl:variable name="nl" select="'&#xA;'"/>Dessa forma, você não cria um RTF desnecessário (fragmento da árvore de resultados).
Daniel Haley
2

Eu encontrei uma diferença entre as novas <xsl:text>linhas literais e as novas linhas literais usando &#xA;.

Enquanto novas linhas literais funcionavam bem em meu ambiente (usando o Saxon e o processador Java XSLT padrão), meu código falhou quando foi executado por outro grupo em execução em um ambiente .NET.

Mudar para entity ( &#xA;) fez com que meu código de geração de arquivos fosse executado consistentemente em Java e .NET.

Além disso, as novas linhas literais são vulneráveis ​​a serem reformatadas pelos IDEs e podem inadvertidamente se perder quando o arquivo é mantido por alguém que 'não conhece'.

Agnes
fonte
2

Percebi pela minha experiência que produzir uma nova linha dentro de uma <xsl:variable>cláusula não funciona. Eu estava tentando fazer 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>

Tudo o que tentei colocar nessa "nova linha" (o <xsl:text>nó vazio ) simplesmente não funcionou (incluindo a maioria das sugestões mais simples nesta página), sem mencionar o fato de que o HTML simplesmente não funcionará lá, então, eventualmente, teve que dividi-lo para 2 variáveis, chamá-los fora do <xsl:variable>escopo e colocar um simples <br/>entre eles, ou seja:

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

Sim, eu sei, não é a solução mais sofisticada, mas funciona, apenas compartilhando minha experiência de frustração com XSLs;)

ShayLivyatan
fonte
2

Eu não poderia simplesmente usar a <xsl:text>&#xa;</xsl:text>abordagem, porque se eu formatar o arquivo XML usando XSLT, a entidade desaparecerá. Então eu tive que usar uma abordagem um pouco mais abrangente sobre a abordagem usando variáveis

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

basta adicionar esta tag:

<br/>

funciona para mim ;) .

Ionut Ionete
fonte
7
A questão é sobre a saída de texto. Sua solução funcionaria apenas se a saída fosse renderizada como HTML.
Oberlies