Удалить пробелы из HTML, сгенерированного с помощью XSL

Задний план

Сохраняйте удобочитаемый исходный код XSL при создании HTML без чрезмерных разрывов, которые вводят пробелы между предложениями и завершающими знаками препинания. Из Переосмысление XSLT:

Пробелы в таблицах стилей XSLT особенно проблематичны, поскольку они служат двум целям: (1) для форматирования самой таблицы стилей XSLT; и (2) для указания того, где должны располагаться пробелы в выходных данных XML, обработанных с помощью XSLT.

Проблема

Шаблон XSL содержит следующий код:

  <xsl:if test="@min-time &lt; @max-time">
    for
    <xsl:value-of select="@min-time" />
    to
    <xsl:value-of select="@max-time" />
    minutes
  </xsl:if>

  <xsl:if test="@setting">
    on <xsl:value-of select="@setting" /> heat
  </xsl:if>
  .

Это, например, генерирует следующий вывод (с пробелами точно так, как показано):

    for
    2
    to
    3
    minutes
  .

Все основные браузеры производят:

for 2 to 3 minutes .

Почти безупречно, за исключением пробела между словом minutes и пунктуацией. Желаемый результат:

for 2 to 3 minutes.

Можно убрать пробел, удалив отступы и символы новой строки в шаблоне XSL, но это означает наличие уродливого исходного кода XSL.

Обходной путь

Первоначально желаемый вывод был заключен в переменную, а затем записан следующим образом:

<xsl:value-of select="normalize-space($step)" />.

Это работало, пока я не попытался обернуть <span> элементов в переменную. Элементы <span> никогда не появлялись в сгенерированном HTML-коде. Также неверен следующий код:

<xsl:copy-of select="normalize-space($step)" />.

Технические детали

Таблица стилей уже использует:

<xsl:strip-space elements="*" />
<xsl:output indent="no" ... />

Связанный

Вопрос

Как сказать процессору XSLT убрать это пространство?

Спасибо!


person Dave Jarvis    schedule 14.05.2012    source источник
comment
Пробовали ли вы использовать редактор виртуального форматирования? При этом в исходный текст не добавляются никакие символы отступа — форматирование просто непрерывно перестраивается в контекст XSLT по мере редактирования XSLT.   -  person pgfearo    schedule 15.05.2012
comment
@pgfearo: я слишком привязан к vi. ;-) А я решил проблему уже с лишней переменной. Однако за идею спасибо!   -  person Dave Jarvis    schedule 15.05.2012


Ответы (2)


Вместо использования copy-of вы можете применить шаблон удостоверения с дополнительным шаблоном, который обрезает пробелы в текстовых узлах. Вы создаете только одну переменную, как в своем первом обходном пути.

Ты звонишь:

<li><xsl:apply-templates select="$step" mode="nospace" />.</li>

Шаблоны:

<xsl:template match="text()" mode="nospace" priority="1" >
    <xsl:value-of select="normalize-space(.)" />
</xsl:template>

<xsl:template match="node() | @*" mode="nospace">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*" mode="nospace" />
    </xsl:copy>
</xsl:template>
person user570783    schedule 14.05.2012

И. Это преобразование:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="t[@max-time > @min-time]">
  <span>
    <xsl:value-of select=
      "concat('for ', @min-time, ' to ', @max-time, ' minutes')"/>
  </span>
  <xsl:apply-templates select="@setting"/>
  <xsl:text>.</xsl:text>
 </xsl:template>

 <xsl:template match="@setting">
  <span>
    <xsl:value-of select="concat(' on ', ., ' heat')"/>
  </span>
 </xsl:template>
</xsl:stylesheet>

при применении к следующему XML-документу (ни один не был представлен!):

<t min-time="2" max-time="3" setting="moderate"/>

выдает желаемый правильный результат:

<span>for 2 to 3 minutes</span>
<span> on moderate heat</span>.

и отображается в браузере как:

2-3 минуты на умеренном огне.

Когда такое же преобразование применяется к этому XML-документу:

<t min-time="2" max-time="3"/>

снова получен правильный желаемый результат:

<span>for 2 to 3 minutes</span>.

и отображается в браузере как:

на 2-3 минуты.


II. Компоновочное (визуальное) решение:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" xmlns:gen="gen:gen" xmlns:gen-attr="gen:gen-attr"
 exclude-result-prefixes="my gen">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <my:layout>
  <span>for <gen-attr:min-time/> to <gen-attr:max-time/> minutes</span>
  <gen-attr:setting><span> on <gen:current/> heat</span></gen-attr:setting>
  <gen:literal>.</gen:literal>
 </my:layout>

 <xsl:variable name="vLayout" select="document('')/*/my:layout/*"/>
 <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="node()|@*">
   <xsl:param name="pCurrent"/>
     <xsl:copy>
       <xsl:apply-templates select="node()|@*">
       <xsl:with-param name="pCurrent" select="$pCurrent"/>
       </xsl:apply-templates>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="/">
  <xsl:apply-templates select="$vLayout">
   <xsl:with-param name="pCurrent" select="$vDoc/*"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="gen-attr:*">
  <xsl:param name="pCurrent"/>
  <xsl:value-of select="$pCurrent/@*[name() = local-name(current())]"/>
 </xsl:template>

 <xsl:template match="gen-attr:setting">
  <xsl:param name="pCurrent"/>
  <xsl:variable name="vnextCurrent" select=
   "$pCurrent/@*[name() = local-name(current())]"/>
  <xsl:apply-templates select="node()[$vnextCurrent]">
    <xsl:with-param name="pCurrent" select="$vnextCurrent"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="gen:current">
  <xsl:param name="pCurrent"/>
   <xsl:value-of select="$pCurrent"/>
 </xsl:template>

 <xsl:template match="gen:literal">
  <xsl:apply-templates/>
 </xsl:template>
</xsl:stylesheet>

Это преобразование дает нам представление о том, как сделать визуальное (скелетное) представление желаемого вывода и использовать его для «заполнения» нужными данными из исходного XML-документа.

Результат идентичен первому решению. Если это преобразование выполняется «как есть», оно создаст множество пространств имен — они безвредны и не будут созданы, если макет находится в отдельном XML-файле.

person Dimitre Novatchev    schedule 14.05.2012
comment
@DaveJarvis: Мы не можем догадаться - я ответил на заданный вами вопрос. Вы можете отредактировать вопрос с отсутствующей информацией или (предпочтительно) задать новый вопрос. Уверяю вас, что правильное использование XSLT может дать желаемый результат — чаще всего без необходимости постобработки. Во втором решении, которое я предоставил, я демонстрирую идею заполнения пробелов, которая одновременно наглядна и мощна. Подводя итог: при хорошем дизайне и соответствующей экспертизе XSLT можно успешно и легко решить эту и подобные задачи. - person Dimitre Novatchev; 14.05.2012