Разделите строку на 100 блоков с помощью XSLT 1.0 - PullRequest
2 голосов
/ 19 октября 2011

Я хотел попробовать некоторые вещи.Теперь я попытался разбить строку на 100 блоков.Так вот, как далеко я получил:

<xsl:template name="split100check">
    <xsl:param name="input"></xsl:param>
    <xsl:variable name="newInput" select="concat(normalize-space($input), ' ' )"></xsl:variable>
    <xsl:variable name="start" select="substring($input, 1, 100)"></xsl:variable>
    <xsl:variable name="end" select="substring($input, 101)"></xsl:variable>
    <PART>
        <xsl:value-of select="$start"></xsl:value-of>
    </PART>
    <xsl:if test="$end">
        <xsl:call-template name="split100check">
            <xsl:with-param name="input" select="$end"></xsl:with-param>
        </xsl:call-template>
    </xsl:if>9
</xsl:template>

Так что это почти то, что я хотел бы достичь.Он принимает строку на 100 блоков, но разделяет и слова.Например:

<main>
    <long>
    A very long text here [....] only for test
    </long>
</main>

Допустим, первые 100 блоков заканчиваются словом «только», но в его середине.таким образом, первый блок будет «Очень длинный текст [....] вкл», а второй блок «ly for test».Итак, как мне создать этот шаблон, чтобы делать то, что я хочу?

info: я могу использовать только XSLT 1.0

Редактировать: чтобы сделать более понятным пример с разбивкой на 10 блоков:

Текст: «Привет, мой друг» -> разделить его на 10 блоков было бы с моим подходом:

первый блок: <PART>Hello my f</PART>

второй блок: <PART>riend</PART>

Я хочу, чтобы слова не разделялись следующим образом:

первый блок: <PART>Hello my </PART>

второй блок: <PARTR>friend </PART>

Первый блоктеперь уже не ровно 10 символов, но это не имеет значения.Он должен содержать столько слов, сколько уместится в блоке из 10 символов.

gz ALeks

1 Ответ

1 голос
/ 19 октября 2011

Вы можете использовать шаблон 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"/>

   <!-- to be applied on text.xml -->

   <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="60"/>
        <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) or string($arg1/line/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>

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

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