Stworzenie nowej linii w XSLT

198

Chcę utworzyć nowy wiersz dla tekstu wyjściowego w XSLT. Jakieś pomysły?

Mithil
źródło
11
Myślę, że czas przyjąć odpowiedź :)
Florjon

Odpowiedzi:

240

Poniższy kod XSL utworzy znak nowej linii (znak wiersza):

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

Do zwrotu karetki użyj:

<xsl:text>&#xd;</xsl:text>
Florjon
źródło
7
+1: jest to bardziej niezawodne niż <xsl:text>podejście zawierające nową linię, jeśli użyjesz czegoś, co może ponownie sformatować plik XSL i zepsuć się spacją.
Ian Roberts
49

Moja ulubiona metoda robienia tego wygląda mniej więcej tak:

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

Następnie, ilekroć chcesz wypisać nowy wiersz (być może w csv), możesz wypisać coś takiego:

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

Użyłem tej techniki podczas wyprowadzania sql z wejścia xml. W rzeczywistości staram się tworzyć zmienne dla przecinków, cudzysłowów i znaków nowej linii.

Nic Gibson
źródło
3
Pamiętaj, że poniższa odpowiedź Florjon jest znacznie bardziej stabilna niż moja.
Nic Gibson,
1
Prawdopodobnie warto dodać deklarację xml:space="preserve"do xsl:textelementu w celu zwiększenia stabilności, ale zgodzę się, że odpowiedź @ Florjon jest prawdopodobnie bezpieczniejsza.
Flynn1179
Wadą tego rozwiązania jest także włączenie wgłębień, które mogą być niepożądane.
wmassingham,
47

Dołącz atrybut Method = "text" do znacznika wyjściowego xsl: i wstaw nowe znaki w swojej dosłownej treści do XSL w odpowiednich punktach. Jeśli wolisz zachować kod źródłowy swojej XSL schludny, użyj encji, w &#10;której chcesz nową linię.

AnthonyWJones
źródło
31

Możesz użyć: <xsl:text>&#10;</xsl:text>

patrz przykład

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

jeśli napiszesz to w pliku np

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

ta zmienna utworzy nowy infiltr linii jako:

commons-dbcp_commons-dbcp = 1.2.2
junit_junit = 4.4
org.easymock_easymock = 2.4
użytkownik878525
źródło
6

IMHO nie wymaga więcej informacji niż @Florjon. Być może pozostawiono kilka drobnych szczegółów, aby zrozumieć, dlaczego czasami może to nie działać.

Przede wszystkim &#xa (hex) lub &#10(dec) wewnątrz <xsl:text/>zawsze będzie działać, ale możesz go nie zobaczyć.

  1. W znacznikach HTML nie ma znaku nowej linii. Za pomocą prostego<br/> wystarczy. W przeciwnym razie zobaczysz białą przestrzeń. Wyświetlenie źródła z przeglądarki powie Ci, co się naprawdę wydarzyło. Są jednak przypadki, w których można oczekiwać takiego zachowania, zwłaszcza jeśli konsument nie jest bezpośrednio przeglądarką. Na przykład, chcesz utworzyć stronę HTML i wyświetlić jej strukturę sformatowaną ładnie z pustymi liniami i identyfikatorami przed podaniem jej do przeglądarki.
  2. Pamiętaj, gdzie chcesz użyć disable-output-escaping a gdzie nie. Weźmy następujący przykład, w którym musiałem utworzyć plik XML z innego i zadeklarować jego DTD z arkusza stylów.

Pierwsza wersja nie zawiera znaków (domyślnie dla 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>

a oto wynik:

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

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

Ok, robi to, czego oczekujemy, ucieczka jest wykonywana, aby używane znaki były wyświetlane poprawnie. Formatowanie części XML w węźle głównym jest obsługiwane przez ident="yes". Ale przy bliższym spojrzeniu widzimy, że znak nowej linii&#xa nie został ocalony i przetłumaczony , wykonując podwójny przesuw linii! Nie mam wyjaśnienia na ten temat, dobrze będzie wiedzieć. Ktoś?

Druga wersja nie ucieka bohaterom, więc produkują to, do czego są przeznaczeni. Dokonana zmiana to:

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

a oto wynik:

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

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

i będzie dobrze. Zarówno cr, jak i lf są poprawnie renderowane.

  1. Nie zapominaj, że mówimy nl, a nie crlf( nl=lf). Moją pierwszą próbą było użycie tylko cr: &#xdi podczas gdy wyjściowy plik XML został poprawnie sprawdzony przez DOM.

Przeglądałem uszkodzony plik XML:

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

Parser DOM zignorował znaki sterujące, ale renderowany nie. Spędziłem trochę czasu, uderzając się w głowę, zanim zdałem sobie sprawę, jak głupio tego nie widziałem!

Dla przypomnienia używam zmiennej wewnątrz ciała z obydwoma CRLF, aby mieć 100% pewność, że będzie działać wszędzie.

Agoun
źródło
4

Dodałem DOCTYPEdyrektywę, którą widzicie tutaj:

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

To pozwala mi użyć &nl;zamiast &#xa;tworzyć nowy wiersz w danych wyjściowych. Podobnie jak inne rozwiązania, zwykle umieszcza się go w <xsl:text>tagu.

Sam Harwell
źródło
3

Możesz spróbować,

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

To będzie działać.

itzmebibin
źródło
2

Popieram metodę Nic Gibsona, zawsze była to moja ulubiona:

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

Używam jednak zadania Ant <echoxml> do tworzenia arkuszy stylów i uruchamiania ich z plikami. Zadanie wykona szablony wartości atrybutów, np. $ {DSTAMP}, ale również sformatuje twój plik xml, więc w niektórych przypadkach wskazane jest odwołanie do encji.

<xsl:variable name='nl'><xsl:text>&#xa;</xsl:text></xsl:variable>
Hank Ratzesberger
źródło
3
Jeśli użyjesz zmiennej, lepiej byłoby użyć selectzamiast niej xsl:text. Przykład: <xsl:variable name="nl" select="'&#xA;'"/>W ten sposób nie tworzysz niepotrzebnego RTF (fragment drzewa wyników).
Daniel Haley,
2

Znalazłem różnicę między dosłownymi znakami nowej linii <xsl:text>i dosłownymi znakami nowej linii&#xA; .

Podczas gdy dosłownie nowe wiersze działały dobrze w moim środowisku (przy użyciu zarówno saskiego, jak i domyślnego procesora Java XSLT), mój kod zawiódł, gdy został wykonany przez inną grupę działającą w środowisku .NET.

Zmiana na podmioty (&#xA; ) sprawiła, że ​​mój kod generowania plików działał spójnie zarówno w Javie, jak i .NET.

Ponadto dosłowne znaki nowej linii są podatne na formatowanie przez IDE i mogą zostać przypadkowo utracone, gdy plik jest utrzymywany przez kogoś „nie znanego”.

Agnieszka
źródło
2

Zauważyłem z mojego doświadczenia wynika, że produkcja nowej linii INSIDE o <xsl:variable>klauzuli nie działa. Próbowałem zrobić coś takiego:

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

Wszystko, co próbowałem umieścić w „nowej linii” (pustym <xsl:text>węźle) po prostu nie działało (w tym większość prostszych sugestii na tej stronie), nie wspominając już o tym, że HTML po prostu tam nie działa, więc ostatecznie musiał podzielić go na 2 zmienne, wywołać je poza <xsl:variable>zakresem i umieścić prostą <br/>między nimi, tj .:

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

Tak, wiem, to nie jest najbardziej wyrafinowane rozwiązanie, ale działa, po prostu dzielę się swoją frustracją z XSL;)

ShayLivyatan
źródło
2

Nie mogłem po prostu użyć tego <xsl:text>&#xa;</xsl:text>podejścia, ponieważ jeśli sformatuję plik XML za pomocą XSLT, encja zniknie. Musiałem więc użyć nieco więcej rundy na temat podejścia wykorzystującego zmienne

<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
źródło
-4

po prostu dodaj ten tag:

<br/>

mi to pasuje ;) .

Ionut Ionete
źródło
7
Pytanie dotyczy wyjścia tekstu. Twoje rozwiązanie działałoby tylko wtedy, gdy wynik byłby renderowany jako HTML.
oberlies