Создание новой линии в XSLT

198

Я хочу создать новую строку для вывода текста в XSLT. Любые идеи?

Mithil
источник
11
Я думаю, пришло время принять ответ :)
Florjon

Ответы:

240

Следующий код XSL создаст символ новой строки ( перевода строки):

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

Для возврата каретки используйте:

<xsl:text>&#xd;</xsl:text>
Florjon
источник
7
+1: это более надежно, чем <xsl:text>использование метода новой строки, если вы используете что-либо, что может переформатировать ваш XSL-файл и смешаться с пробелами.
Ян Робертс
49

Мой любимый метод для этого выглядит примерно так:

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

Затем, когда вы хотите вывести новую строку (возможно, в csv), вы можете вывести что-то вроде следующего:

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

Я использовал эту технику при выводе SQL из ввода XML. На самом деле, я склонен создавать переменные для запятых, кавычек и новых строк.

Ник Гибсон
источник
3
Обратите внимание, что ответ Флориона ниже значительно более стабилен, чем мой.
Ник Гибсон
1
Возможно, стоит добавить объявление xml:space="preserve"к xsl:textэлементу для повышения стабильности, но я согласен, что ответ @ Florjon, вероятно, более безопасный.
Flynn1179
Недостатком этого решения является также включение любого отступа, что может быть нежелательно.
Wmassingham
47

Включите атрибут Method = "text" в тег xsl: output и добавьте новые строки в свой текстовый контент в XSL в соответствующих точках. Если вы предпочитаете хранить исходный код своей XSL-записи, используйте объект, в &#10;котором вы хотите новую строку.

AnthonyWJones
источник
31

Ты можешь использовать: <xsl:text>&#10;</xsl:text>

посмотрите пример

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

если вы напишите это в файле, например,

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

эта переменная создаст новую строку infile как:

commons-dbcp_commons-dbcp = 1.2.2
junit_junit = 4.4
org.easymock_easymock = 2.4
user878525
источник
6

ИМХО не нужно больше информации, чем дал @Florjon. Может быть, осталось немного мелких деталей, чтобы понять, почему это иногда не работает для нас.

Прежде всего, &#xa(hex) или &#10(dec) внутри a <xsl:text/>всегда будут работать, но вы можете их не видеть.

  1. В разметке HTML нет новой строки. Использование простой <br/>подойдет. В противном случае вы увидите пустое пространство. Просмотр источника из браузера покажет вам, что на самом деле произошло. Однако в некоторых случаях вы ожидаете такого поведения, особенно если потребитель не является браузером напрямую. Например, вы хотите создать HTML-страницу и просмотреть ее структуру, отформатированную с пустыми строками и идентификаторами, прежде чем отправлять ее в браузер.
  2. Помните, где вам нужно использовать, disable-output-escapingа где нет. Возьмите следующий пример, где мне нужно было создать xml из другого и объявить его DTD из таблицы стилей.

Первая версия экранирует символы (по умолчанию для 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>

и вот результат:

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

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

Хорошо, он делает то, что мы ожидаем, экранирование выполняется так, чтобы используемые символы отображались правильно. Форматирование XML-части внутри корневого узла выполняется с помощью ident="yes". Но при ближайшем рассмотрении мы видим, что символ новой строки &#xaне был экранирован и переведен как есть, выполнив двойной перевод строки! У меня нет объяснения этому, будет полезно узнать. Кто угодно?

Вторая версия не избегает персонажей, поэтому они создают то, для чего они предназначены. Сделанное изменение было:

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

и вот результат:

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

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

и это будет хорошо. Оба cr и lf правильно отображаются.

  1. Не забывайте, что мы говорим nl, а не crlf( nl=lf). Моя первая попытка состояла в том, чтобы использовать только cr: &#xdи хотя выходной xml был правильно проверен DOM.

Я просматривал поврежденный XML:

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

Парсер DOM игнорировал управляющие символы, но обработчик - нет. Я провел довольно много времени, стуча головой, прежде чем понял, как глупо я этого не видел!

Для записи я использую переменную внутри тела с обоими CRLF, чтобы быть на 100% уверенной, что она будет работать везде.

Agoun
источник
4

Я добавил DOCTYPEдирективу, которую вы видите здесь:

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

Это позволяет мне использовать &nl;вместо &#xa;вывода новой строки в выводе. Как и другие решения, это обычно помещается внутри <xsl:text>тега.

Сэм Харвелл
источник
3

Можешь попробовать,

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

Это сработает.

itzmebibin
источник
2

Я второй метод Ник Гибсон, это всегда был мой любимый:

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

Однако я использую задачу Ant <echoxml> для создания таблиц стилей и запуска их для файлов. Задача будет выполнять шаблоны значений атрибутов, например, $ {DSTAMP}, но также будет переформатировать ваш xml, поэтому в некоторых случаях ссылка на сущность предпочтительнее.

<xsl:variable name='nl'><xsl:text>&#xa;</xsl:text></xsl:variable>
Хэнк Рацзесбергер
источник
3
Если вы используете переменную, лучше использовать selectвместо xsl:text. Пример: таким <xsl:variable name="nl" select="'&#xA;'"/>образом вы не создаете ненужный RTF (фрагмент дерева результатов).
Даниэль Хейли
2

Я обнаружил разницу между буквальными символами новой строки <xsl:text>и буквальными символами новой строки &#xA;.

В то время как буквальные переводы строк работали нормально в моей среде (с использованием Saxon и процессора Java XSLT по умолчанию), мой код завершился ошибкой, когда он был выполнен другой группой, работающей в среде .NET.

При переходе на entity ( &#xA;) мой код генерации файлов работал одинаково на Java и .NET.

Кроме того, буквенные символы новой строки уязвимы для переформатирования в IDE и могут случайно потеряться, если файл поддерживается кем-то «не в курсе».

Агнесса
источник
2

Я заметил , из моего опыта , что производство новой линии ВНУТРИ в <xsl:variable>статье не работает. Я пытался сделать что-то вроде:

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

Все, что я пытался вставить в эту «новую строку» (пустой <xsl:text>узел), просто не работало (включая большинство простых предложений на этой странице), не говоря уже о том, что HTML там просто не будет работать, поэтому в итоге я пришлось разделить его на 2 переменные, вызвать их вне области <xsl:variable>видимости и поместить простое <br/>между ними, то есть:

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

Да, я знаю, это не самое сложное решение, но оно работает, просто делюсь своим опытом разочарования с XSL;)

ShayLivyatan
источник
2

Я не мог просто использовать этот <xsl:text>&#xa;</xsl:text>подход, потому что если я отформатирую XML-файл с использованием XSLT, сущность исчезнет. Так что мне пришлось использовать немного более округлый подход к использованию переменных

<xsl:variable name="nl" select="'&#10;'"/>
<xsl:template match="/">
    <xsl:value-of select="$nl" disable-output-escaping="no"/>
    <xsl:apply-templates select="*"/>
</xsl:template>
Архимед Траяно
источник
-4

просто добавьте этот тег:

<br/>

меня устраивает ;) .

Ионут Ионете
источник
7
Вопрос о выводе текста. Ваше решение будет работать только в том случае, если вывод будет представлен как HTML.
Oberlies