XSL в текст, эквивалент 'fmt'

Я обрабатываю XML-документ с тегами <paragraph>, содержащими текст, в обычный текстовый файл. Иногда строки обрываются в непонятных местах, а иногда они слишком длинные. У меня есть шаблон для абзацев, который просто запускает действие apply-template и добавляет пару новых строк.

Есть ли способ переформатировать текст () в абзаце, аналогичный команде unix 'fmt' (которая переворачивает поток текста до нормализованной ширины) после применения шаблонов имеет возможность обрабатывать другие теги внутри абзаца (например, полужирный, em и т. д.).

Кроме того, есть ли способ для каждой переформатированной строки сделать отступ, как вы обычно делаете в блочной кавычке в текстовом документе?


person JeffG    schedule 03.09.2011    source источник
comment
Не ожидайте, что многие люди знают, что делает unix 'fmt'. Пожалуйста, предоставьте полный пример (небольшого) XML-документа, точный желаемый результат и правила, которым должно соответствовать преобразование.   -  person Dimitre Novatchev    schedule 03.09.2011
comment
Хороший вопрос, +1. См. мой ответ для простого решения XSLT 1.0, использующего шаблон FXSL str-split-to-lines.   -  person Dimitre Novatchev    schedule 03.09.2011
comment
Итак, @JeffG, был ли мой ответ полезен?   -  person Dimitre Novatchev    schedule 05.09.2011
comment
XSLT — не лучший инструмент для подобных операций со строками. Вам, вероятно, лучше изучить использование функций расширения, если вам действительно нужно сделать это в преобразовании.   -  person Flynn1179    schedule 05.09.2011


Ответы (1)


Одним из простых решений является использование шаблона str-split-to-lines из FXSL следующим образом:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:ext="http://exslt.org/common"
xmlns:str-split2lines-func="f:str-split2lines-func"
exclude-result-prefixes="xsl f ext str-split2lines-func"
>


   <xsl:import href="dvc-str-foldl.xsl"/>

   <str-split2lines-func:str-split2lines-func/>

   <xsl:output indent="yes" omit-xml-declaration="yes"/>

    <xsl:template match="/">
      <xsl:call-template name="str-split-to-lines">
        <xsl:with-param name="pStr" select="/*"/>
        <xsl:with-param name="pLineLength" select="50"/>
        <xsl:with-param name="pDelimiters" select="' &#9;&#10;&#13;'"/>
      </xsl:call-template>
    </xsl:template>

    <xsl:template name="str-split-to-lines">
      <xsl:param name="pStr"/>
      <xsl:param name="pLineLength" select="60"/>
      <xsl:param name="pDelimiters" select="' &#9;&#10;&#13;'"/>

      <xsl:variable name="vsplit2linesFun"
                    select="document('')/*/str-split2lines-func:*[1]"/>

      <xsl:variable name="vrtfParams">
       <delimiters><xsl:value-of select="$pDelimiters"/></delimiters>
       <lineLength><xsl:copy-of select="$pLineLength"/></lineLength>
      </xsl:variable>

      <xsl:variable name="vResult">
          <xsl:call-template name="dvc-str-foldl">
            <xsl:with-param name="pFunc" select="$vsplit2linesFun"/>
            <xsl:with-param name="pStr" select="$pStr"/>
            <xsl:with-param name="pA0" select="ext:node-set($vrtfParams)"/>
          </xsl:call-template>
      </xsl:variable>

      <xsl:for-each select="ext:node-set($vResult)/line">
        <xsl:for-each select="word">
          <xsl:value-of select="concat(., ' ')"/>
        </xsl:for-each>
        <xsl:value-of select="'&#xA;'"/>
      </xsl:for-each>
    </xsl:template>

    <xsl:template match="str-split2lines-func:*" mode="f:FXSL">
      <xsl:param name="arg1" select="/.."/>
      <xsl:param name="arg2"/>

      <xsl:copy-of select="$arg1/*[position() &lt; 3]"/>
      <xsl:copy-of select="$arg1/line[position() != last()]"/>

      <xsl:choose>
        <xsl:when test="contains($arg1/*[1], $arg2)">
          <xsl:if test="string($arg1/word)">
             <xsl:call-template name="fillLine">
               <xsl:with-param name="pLine" select="$arg1/line[last()]"/>
               <xsl:with-param name="pWord" select="$arg1/word"/>
               <xsl:with-param name="pLineLength" select="$arg1/*[2]"/>
             </xsl:call-template>
          </xsl:if>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="$arg1/line[last()]"/>
          <word><xsl:value-of select="concat($arg1/word, $arg2)"/></word>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>

      <!-- Test if the new word fits into the last line -->
    <xsl:template name="fillLine">
      <xsl:param name="pLine" select="/.."/>
      <xsl:param name="pWord" select="/.."/>
      <xsl:param name="pLineLength" />

      <xsl:variable name="vnWordsInLine" select="count($pLine/word)"/>
      <xsl:variable name="vLineLength" 
       select="string-length($pLine) + $vnWordsInLine"/>
      <xsl:choose>
        <xsl:when test="not($vLineLength + string-length($pWord) 
                           > 
                            $pLineLength)">
          <line>
            <xsl:copy-of select="$pLine/*"/>
            <xsl:copy-of select="$pWord"/>
          </line>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="$pLine"/>
          <line>
            <xsl:copy-of select="$pWord"/>
          </line>
          <word/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

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

<text>
Dec. 13 — As always for a presidential inaugural, security and surveillance were
extremely tight in Washington, DC, last January. But as George W. Bush prepared to
take the oath of office, security planners installed an extra layer of protection: a
prototype software system to detect a biological attack. The U.S. Department of
Defense, together with regional health and emergency-planning agencies, distributed
a special patient-query sheet to military clinics, civilian hospitals and even aid
stations along the parade route and at the inaugural balls. Software quickly
analyzed complaints of seven key symptoms — from rashes to sore throats — for
patterns that might indicate the early stages of a bio-attack. There was a brief
scare: the system noticed a surge in flulike symptoms at military clinics.
Thankfully, tests confirmed it was just that — the flu.
</text>

Выполняется требуемый вывод (слова, заключенные в строки максимальной шириной 50):

Dec. 13 — As always for a presidential inaugural, 
security and surveillance were extremely tight in 
Washington, DC, last January. But as George W. 
Bush prepared to take the oath of office, security 
planners installed an extra layer of protection: a 
prototype software system to detect a biological 
attack. The U.S. Department of Defense, together 
with regional health and emergency-planning 
agencies, distributed a special patient-query 
sheet to military clinics, civilian hospitals and 
even aid stations along the parade route and at 
the inaugural balls. Software quickly analyzed 
complaints of seven key symptoms — from rashes to 
sore throats — for patterns that might indicate 
the early stages of a bio-attack. There was a 
brief scare: the system noticed a surge in flulike 
symptoms at military clinics. Thankfully, tests 
confirmed it was just that — the flu.
person Dimitre Novatchev    schedule 03.09.2011