Как в XSLT разделить текстовое содержимое элемента на строки? - PullRequest
2 голосов
/ 21 марта 2012

Я использую XSLT для разбора текстового содержимого элемента XML.Этот текст содержит новые строки, но я не могу их правильно проанализировать.Я использую код, который нашел в Интернете, чтобы разделить текст.Вот соответствующая часть кода.

<xsl:variable name="first">
  <xsl:value-of select="substring-before($source, $newline)"/>
</xsl:variable>
<xsl:variable name="rest">
  <xsl:value-of select="substring-after($source, $newline)"/>
</xsl:variable>

Это часть шаблона recusrive, который помещает в себя $ rest.

Проблема в том, что образец кода не определяет $ newline,Если я установлю $ newline на букву, например, 's', текст будет очень просто разделен (например, он превратит входные данные «звучащие» в «re» и «раунд»).Но когда я пытаюсь установить $ newline на символ новой строки, то есть &#xa; или &#xa0;, он повторяется вечно и вызывает переполнение стека.Я также попытался определить ENTITY для новой строки, но это не имеет значения.

На входе есть обычный CR / LF в конце каждой строки (я нахожусь в окне Windows).

Кто-нибудь имеет представление о том, что я делаю неправильно, или предложить подход?

Спасибо, Mathijs

Ответы [ 5 ]

3 голосов
/ 21 марта 2012

Если вы можете использовать EXSLT, попробуйте с str: tokenize

<xsl:for-each select="str:tokenize($source, $newline)">
  <xsl:value-of select="."/>
  <xsl:text>&#x0a;</xsl:text>
</xsl:for-each>

или аналогично XSLT 2.0:

<xsl:for-each select="tokenize($source, $newline)">
  <xsl:sequence select="."/>
  <xsl:text>&#x0a;</xsl:text>
</xsl:for-each>
2 голосов
/ 22 марта 2012

Ответ Maestro13 приблизил меня, и я закончил тем, что слил шаблон, который у меня был, с его, чтобы создать его, которым я поделюсь здесь для будущих поколений. Это шаблон, который возвращает длину самой длинной строки в строке, которую вы ему передаете.

<xsl:template name="longestCodeLine">
    <xsl:param name="str"/>

    <xsl:choose>
    <!-- Is this the last line? -->
    <xsl:when test="contains($str, '&#xA;')">
        <!-- No. First isolate all remaining lines, and recurse to find its longest line. -->
        <xsl:variable name="bestOfTheRest">
            <xsl:call-template name="longestCodeLine">
                <xsl:with-param name="str" select="substring-after($str, '&#xA;')"/>                        
            </xsl:call-template>
        </xsl:variable>
        <xsl:choose>
            <!-- Compare the longest of the remaining lines to this one. Which one's longer? -->
            <!-- If the longest of the remaining lines is longer, return that line. -->
            <xsl:when test="string-length($bestOfTheRest) &gt; string-length(substring-before($str, '&#xA;'))">
                <xsl:value-of select="$bestOfTheRest"/>
            </xsl:when>
            <!-- If this line longer, return this line. -->
            <xsl:otherwise>
                <xsl:value-of select="substring-before($str, '&#xA;')"/>
            </xsl:otherwise>
        </xsl:choose>
            </xsl:when>
    <!-- If there are no \n's left, this is your last string. So it is by definition the longest one left. -->
    <xsl:otherwise>
        <xsl:value-of select="$str"/>
    </xsl:otherwise>
    </xsl:choose>   
</xsl:template>
2 голосов
/ 21 марта 2012

Возможно, вы сможете использовать следующее.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <root>
            <xsl:for-each select="root/str">
                <str>
                    <xsl:call-template name="strSplit">
                        <xsl:with-param name="str" select="."/>
                        <xsl:with-param name="seqno" select="1"/>
                    </xsl:call-template>
                </str>
            </xsl:for-each>
        </root>
   </xsl:template>

    <xsl:template name="strSplit">
        <xsl:param name="str"/>
        <xsl:param name="seqno"/>

        <xsl:variable name="afterLeadingWS"
            select="substring-after($str, substring-before($str,substring-before(normalize-space($str), ' ')))"/>

        <xsl:choose>
            <xsl:when test="contains($afterLeadingWS, '&#xA;')">
                <line>
                    <xsl:attribute name="seqno"><xsl:value-of select="$seqno"/></xsl:attribute>
                    <xsl:attribute name="length"><xsl:value-of select="string-length(substring-before($afterLeadingWS, '&#xA;'))"/></xsl:attribute>
                    <xsl:value-of select="substring-before($afterLeadingWS, '&#xA;')"/>
                </line>
                <xsl:call-template name="strSplit">
                    <xsl:with-param name="str" select="substring-after($afterLeadingWS, '&#xA;')"/>
                    <xsl:with-param name="seqno" select="$seqno + 1"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <line>
                    <xsl:attribute name="seqno"><xsl:value-of select="$seqno"/></xsl:attribute>
                    <xsl:value-of select="$afterLeadingWS"/>
                </line>
            </xsl:otherwise>
        </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

Применительно к

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <str>
        yigifgniuq  h 
        eukwgf kuew hgk.uhgku
        ,/v.,silghouihhg
    </str>
    <str>
        09734ymmnyr n.0808
        o149013483ymr7rg
        738924m c0 

    </str>
</root>

результат будет

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <str>
        <line seqno="1" length="13">yigifgniuq  h </line>
        <line seqno="2" length="21">eukwgf kuew hgk.uhgku</line>
        <line seqno="3" length="18">        ,/v.,silghouihhg</line>
        <line seqno="4">    </line>
    </str>
    <str>
        <line seqno="1" length="18">09734ymmnyr n.0808</line>
        <line seqno="2" length="16">o149013483ymr7rg</line>
        <line seqno="3" length="11">738924m c0 </line>
        <line seqno="4" length="2">     </line>
        <line seqno="5">    </line>
    </str>
</root>

Обратите внимание, что ведущие вкладки (или пробелы) рассматриваются как часть строк.

2 голосов
/ 21 марта 2012

Я использовал этот шаблон один раз. Это именованный шаблон, поэтому вы можете называть его там, где вам это нужно. Текст здесь разделен на 70 символов:

<xsl:template name="Texts">
    <xsl:param name="string" select="TEXTITEM" />
    <xsl:param name="line-length" select="70"/>
    <xsl:variable name="line" select="substring($string,1,$line-length)"/>
    <xsl:variable name="rest" select="substring($string, $line-length+1)"/>
    <xsl:if test="$line">
        <MYTEXT> 
            <xsl:value-of select="$line"/>  
        </MYTEXT> 
    </xsl:if>
    <xsl:if test="$rest">
        <xsl:call-template name="Texts">
            <xsl:with-param name="string" select="$rest"/>
            <xsl:with-param name="line-length" select="$line-length"/>
        </xsl:call-template>
    </xsl:if>   
</xsl:template>

Дайте мне знать, если это работает для вас.

С уважением, Питер

1 голос
/ 04 марта 2014

Думаю, я бы добавил код разделения строки, который добавляет новые строки после пробела.

<xsl:function name="kode:splitLongLine">
  <xsl:param name="string"/>
  <xsl:variable name="regex">
   <xsl:text>(((.){1,55})( |$))</xsl:text>
  </xsl:variable>

  <xsl:variable name="result">
   <xsl:analyze-string select="$string" regex="{$regex}">
    <xsl:matching-substring>
     <xsl:value-of select="concat(regex-group(1),'&#10;')"/>
    </xsl:matching-substring>
    <xsl:non-matching-substring>
     <xsl:value-of select="concat('REPORT ERROR: ', .)"/>
    </xsl:non-matching-substring>
   </xsl:analyze-string>
  </xsl:variable>

  <xsl:sequence select="$result"/>
 </xsl:function>
...