1

PDF への逐語出力用のハイフネーション スクリプトを作成する XSLT 1.0 に行き詰まっています。(これは PDF であるため、巧妙な CSS を使用して問題を解決することはできません。スクリプトの一部として stringlength を比較するために、text() ノードと子 text() ノードの両方にアクセスできるようにしたいと考えています。

例えば:

<programlisting>This text will be displayed without word-wrap
I can measure length of string between end line chars '&#10;'
and break long lines. That works great until

<emphasis>this gets added</emphasis> then my counting loop doesn't
count the text in the emphasis tags.
</programlisting>

screen というテンプレートを使用して text() をループしています。行末文字を検出し、行が長すぎるかどうかを判断します。長い行は分割され、残りが最大行長未満になるまでテンプレートを再帰的に繰り返します...その後、次のテキスト行に... ...うまく機能しますが、今ではいくつかの子供がいます文字列の長さを計算するために、 text() と子ノードの text() に同時にアクセスする方法がわかりません。

長いサンプルコードで申し訳ありません...

合わせるテンプレートはこんな感じ…

<xsl:template match="programlisting/text()"> 
   <xsl:variable name="max_width">100</xsl:variable>
   <xsl:variable name="min_width">80</xsl:variable>
          <xsl:call-template name="screen">
            <xsl:with-param name="text" select="."/>
            <xsl:with-param name="max_width" select="$max_width"/>
            <xsl:with-param name="min_width" select="$min_width"/>
          </xsl:call-template>
</xsl:template>

改行前の文字列が長すぎるかどうかを判断するテンプレート:

<xsl:template name="screen"> 
    <xsl:param name="text" select="."/>
    <xsl:param name="max_width"/>
    <xsl:param name="min_width"/>
    <xsl:variable name="fixed_text"> <!-- add end linebreak if missing -->
        <xsl:choose>
            <xsl:when test="substring($text,string-length($text),1) = '&#10;'">
                <xsl:value-of select="$text"/>  
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="concat($text,'&#10;')"/>  
            </xsl:otherwise>
        </xsl:choose> 
     </xsl:variable>
     <xsl:variable name="first_line">
                <xsl:value-of select="substring-before(concat($fixed_text,'&#10;'),'&#10;')"/>
    </xsl:variable>
    <xsl:variable name="other_lines">
                <xsl:value-of select="substring-after($fixed_text,concat($first_line,'&#10;'))"/>
    </xsl:variable>
    <xsl:choose>
        <xsl:when test="string-length(normalize-space($first_line)) &lt; 1"><!-- blank line (just trim and copy)-->
            <xsl:value-of select="concat($verbatim_padding,substring($first_line,1,100),'&#10;')"/>
        </xsl:when>
        <xsl:when test="string-length($first_line) &lt; 100"> <!-- short line (just copy)-->
            <xsl:value-of select="concat($verbatim_padding,$first_line,'&#10;')"/>
        </xsl:when>
        <xsl:otherwise>
            <!--  Line is too long!!  -->
            <xsl:variable name="wrapped_lines">
               <xsl:call-template name="break_line"> 
                    <xsl:with-param name="long_string" select="$first_line"/>
                    <xsl:with-param name="max_chars" select="100"/>
                    <xsl:with-param name="min_chars" select="80"/>
                    <xsl:with-param name="break_chars" select="' ,/;'"/>
                    <xsl:with-param name="linebreak_string" select="'~'"/>
                </xsl:call-template> 
            </xsl:variable>
            <xsl:value-of select="concat($verbatim_padding,$wrapped_lines)"/>
        </xsl:otherwise>
    </xsl:choose>
    <xsl:if test="string-length($other_lines) &gt; 0">
          <xsl:call-template name="screen">
            <xsl:with-param name="text" select="$other_lines"/>
            <xsl:with-param name="max_width" select="$max_width"/>
            <xsl:with-param name="min_width" select="$min_width"/>
          </xsl:call-template>
    </xsl:if>
</xsl:template>

長い行を分割するテンプレート:

<xsl:template name="break_line"> 
    <xsl:param name="long_string"/>
    <xsl:param name="max_chars"/> <!--max chars allowed on a line -->
    <xsl:param name="min_chars"/> <!--max char position foa soft linebreak (else we hard break at the max chars!) -->
    <xsl:param name="break_chars"/>   <!-- chars used for soft breaking -->
    <xsl:param name="linebreak_string"/>  <!-- add this to end of a broken line -->
    <xsl:choose>
      <xsl:when test="(string-length($long_string) &lt; $max_chars) or (string-length($long_string) &lt; $min_chars) or (string-length($long_string) &lt; 1)">
          <xsl:value-of select="concat($long_string,'&#10;')"/>
       </xsl:when>
      <xsl:otherwise>
            <xsl:variable name="trim_x_by">
                    <xsl:call-template name="CheckLastChar">
                        <xsl:with-param name="string" select="$long_string"/>
                        <xsl:with-param name="start" select="$max_chars"/>
                        <xsl:with-param name="stop" select="$min_chars"/>
                        <xsl:with-param name="break_chars" select="$break_chars"/>
                        <xsl:with-param name="max_chars" select="$max_chars"/>
                     </xsl:call-template>
            </xsl:variable>
            <xsl:variable name="first_x_chars"><xsl:value-of select="substring($long_string,1,$trim_x_by)"/></xsl:variable>
            <xsl:variable name="remaining_chars"><xsl:value-of select="substring-after($long_string,$first_x_chars)"/></xsl:variable>

            <xsl:value-of select="concat($first_x_chars,' ',$linebreak_string)"/>

            <xsl:call-template name="break_line"> 
                <xsl:with-param name="long_string" select="$remaining_chars"/>
                <xsl:with-param name="max_chars" select="$max_chars"/>
                <xsl:with-param name="min_chars" select="$min_chars"/>
                <xsl:with-param name="break_chars" select="$break_chars"/>
                <xsl:with-param name="linebreak_string" select="$linebreak_string"/>
            </xsl:call-template> 
      </xsl:otherwise>
    </xsl:choose>
</xsl:template>

最後に、文字列の文字を再帰的にチェックして、安全に改行 (ソフト ブレーク) できるかどうかを確認します。

   <xsl:template name="CheckLastChar">
        <xsl:param name="string"/>
        <xsl:param name="stop" select="1"/>
        <xsl:param name="start" select="string-length($string)"/>
        <xsl:param name="count" select="$start"/>
        <xsl:param name="break_chars"/>
        <xsl:param name="max_chars"/>
        <xsl:choose>
          <xsl:when test="($count &lt; $stop) or (string-length($string) &lt; $stop)"> 
                <!-- gone so far into the line that a linebreak would look weird! So return the max-length and that will
                force a 'hard' linebreak exactly at the max-length point regardless of the character -->
                <xsl:value-of select="$max_chars"/> 
          </xsl:when>
          <xsl:otherwise>
                <xsl:variable name="last_char"><xsl:value-of select="substring($string,$count,1)"/></xsl:variable>
                <xsl:choose>
                  <xsl:when test="contains($break_chars,$last_char)">
                        <xsl:value-of select="$count"/>
                  </xsl:when>
                 <xsl:otherwise>
                        <!-- keep looking -->
                        <xsl:call-template name="CheckLastChar">
                            <xsl:with-param name="string" select="$string"/>
                            <xsl:with-param name="stop" select="$stop"/>
                            <xsl:with-param name="start" select="$start"/>
                            <xsl:with-param name="count" select="$count - 1"/>
                            <xsl:with-param name="break_chars" select="$break_chars"/>
                            <xsl:with-param name="max_chars" select="$max_chars"/>
                        </xsl:call-template>
                  </xsl:otherwise>
                </xsl:choose>
          </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
4

1 に答える 1

1

要素内のすべてのテキスト (子孫のテキストを含む) を取得するには、次を使用しますstring(Element)

<xsl:template match="programlisting"> 
   <xsl:variable name="max_width">100</xsl:variable>
   <xsl:variable name="min_width">80</xsl:variable>
          <xsl:call-template name="screen">
            <xsl:with-param name="text" select="string(.)"/>
            <xsl:with-param name="max_width" select="$max_width"/>
            <xsl:with-param name="min_width" select="$min_width"/>
          </xsl:call-template>
</xsl:template>

属性text()から が削除されていることに注意してください。match

XPath 仕様

要素ノードの文字列値は、要素ノードのすべてのテキスト ノードの子孫の文字列値をドキュメント順に連結したものです。

string() 関数は、次のようにオブジェクトを文字列に変換します。 ノード セットは、ドキュメント順で最初のノード セット内のノードの文字列値を返すことによって文字列に変換されます。ノード セットが空の場合、空の文字列が返されます。

于 2013-01-24T19:12:05.437 に答える