1

XSLT 2.0 スタイルシートの実行中に、特定のテキスト (例: "story 3.1"、"story 8.19"、"story 21.76") を見つけて、何かを行う必要があります (例: ハイパーリンクでラップする)。これらのインスタンスを見つけて、やりたいことを実行するのは簡単な作業でした。私が遭遇した問題は、ハイパーリンクでラップする必要があるコンテンツが混在している場合があることです (例: "story 3.1<i>a</i>")。私はそれを行う方法を理解することができませんでした。

ここにいくつかのサンプルデータと私のテンプレートがあります:

<p>Jack goes up the hill (story 3.1<i>a</i>) to fetch a pail of water.</p>

<xsl:template match="text()">
<xsl:variable name="content" as="xs:string" select="."/>
<xsl:analyze-string select="$content" regex="Story [0-9]*\.[0-9]*" flags="i">
  <xsl:matching-substring>
    <xsl:variable name="figureToTargetId">
      <xsl:analyze-string select="." regex="[0-9]*\.[0-9]*">
        <xsl:matching-substring>
          <xsl:value-of select="concat('s',.)"/>
        </xsl:matching-substring>
      </xsl:analyze-string>
    </xsl:variable>
    <a href="#{$figureToTargetId}"><xsl:value-of select="."/></a>        
  </xsl:matching-substring>
  <xsl:non-matching-substring><xsl:value-of select="."/>
  </xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>

上記の場合、「story 3.1<i>a</i>」をハイパーリンクで囲みたいと思います。

理想的にはこれを回避するには、text() 以外で一致させる必要があることを知っています。それが何であるかはわかりません。

私が検討してきたアプローチの 1 つは、xsl:for-each を使用してテキスト ノード セットをループ処理し、次のテキスト ノードの長さが正確に 1 つの英字であるかどうかをテストすることです。そうである場合は、前のテキスト ノードと同じハイパーリンクでラップします。(さまざまな理由から、上記の正規表現に一致するテキスト ノードの後の任意の 1 つのアルファ文字の長いテキスト ノードは、同じターゲットにハイパーリンクする必要があることを私は知っています。) しかし、より洗練された解決策があることを願っています。

4

1 に答える 1

1

この変換:

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


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

 <xsl:template match="p/text()[matches(., 'Story [0-9]+(\.[0-9]+)')]">
    <xsl:variable name="vCur" select="."/>
    <xsl:variable name="pContent" select="string(.)"/>
    <xsl:analyze-string select="$pContent" regex="Story [0-9]*\.[0-9]*" flags="i">
      <xsl:matching-substring>
        <xsl:variable name="figureToTargetId">
          <xsl:analyze-string select="." regex="[0-9]*\.[0-9]*">
            <xsl:matching-substring>
              <xsl:value-of select="concat('s',.)"/>
            </xsl:matching-substring>
          </xsl:analyze-string>
        </xsl:variable>
        <a href="#{$figureToTargetId}">
         <xsl:value-of select="."/>
         <xsl:if test="not(matches($vCur, 'Story [0-9]+(\.[0-9]+).+$'))">
          <xsl:sequence select="$vCur/following-sibling::*[1]"/>
         </xsl:if>
        </a>
      </xsl:matching-substring>
      <xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
    </xsl:analyze-string>
 </xsl:template>
 <xsl:template match=
  "p/*[preceding-sibling::node()[1]
         [self::text()
        and
          matches(., 'Story [0-9]+(\.[0-9]+)$')]
         ]"/>
</xsl:stylesheet>

このドキュメントに適用した場合(両方の興味深いケースを含むように拡張された提供されたドキュメント):

<t>
    <p>Little Red Riding Hood (Story 3.1) </p>
    <p>Jack goes up the hill (Story 3.1<i>a</i>) to fetch a pail of water.</p>
</t>

必要な正しい結果を生成します:

<t>
      <p>Little Red Riding Hood (<a href="#s3.1">Story 3.1</a>) </p>
      <p>Jack goes up the hill (<a href="#s3.1">Story 3.1<i>a</i>
      </a>) to fetch a pail of water.</p>
</t>

説明:

一致した部分文字列が現在のテキスト ノードの接尾辞であるかどうかを確認します。そうである場合は、最初に続く兄弟要素もコピーします。

更新

コメントで、OP は新しい追加の要件を設定しました。これも に変更<i><em>ます。

これには、上記のソリューションをわずかに更新するだけで済みます。

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


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

 <xsl:template match="p/text()[matches(., 'Story [0-9]+(\.[0-9]+)')]">
    <xsl:variable name="vCur" select="."/>
    <xsl:variable name="pContent" select="string(.)"/>
    <xsl:analyze-string select="$pContent" regex="Story [0-9]*\.[0-9]*" flags="i">
      <xsl:matching-substring>
        <xsl:variable name="figureToTargetId">
          <xsl:analyze-string select="." regex="[0-9]*\.[0-9]*">
            <xsl:matching-substring>
              <xsl:value-of select="concat('s',.)"/>
            </xsl:matching-substring>
          </xsl:analyze-string>
        </xsl:variable>
        <a href="#{$figureToTargetId}">
         <xsl:value-of select="."/>
         <xsl:if test="not(matches($vCur, 'Story [0-9]+(\.[0-9]+).+$'))">
          <xsl:apply-templates mode="match" select="$vCur/following-sibling::*[1]"/>
         </xsl:if>
        </a>
      </xsl:matching-substring>
      <xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
    </xsl:analyze-string>
 </xsl:template>
 <xsl:template match=
  "p/*[preceding-sibling::node()[1]
         [self::text()
        and
          matches(., 'Story [0-9]+(\.[0-9]+)$')]
         ]"/>
 <xsl:template mode="match" match=
  "p/i[preceding-sibling::node()[1]
         [self::text()
        and
          matches(., 'Story [0-9]+(\.[0-9]+)$')]
         ]">
  <em><xsl:apply-templates/></em>
 </xsl:template>

</xsl:stylesheet>
于 2012-08-12T17:46:35.693 に答える