2010-12-15 15 views
3

xslt:analyze-stringを使用して頭字語をHTMLテキストに追加したいとします。 問題:私のHTMLテキストでは、XMLノードとして扱われるようにxslt:analyze-stringを使用して、頭字語をHTMLに追加します。

<strong>some text</strong> 

などのタグです。 xslt:analyze-stringを適用すると、これらのノードは文字列に変換され、タグは取り除かれます。また、私の再帰的なXSLTスタイルシートでは、既に挿入されている頭字語も削除されています。

私の質問:HTMLノードを文字列に変換してHTMLタグを保存するxslt:analyze-stringを防止するためのトリックはありますか?

ここに私の例です:

スタイルシート:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xhtml" > 

    <xsl:template match="/"> 
     <div> 
      <xsl:call-template name="insert-acronyms"> 
       <xsl:with-param name="text" select="/doc/div"/> 
       <xsl:with-param name="acronyms" select="/doc/dictionary/acronym"/> 
      </xsl:call-template> 
     </div> 
    </xsl:template> 


    <xsl:template name="insert-acronyms"> 
     <xsl:param name="text" as="node()*"/> 
     <xsl:param name="acronyms"/> 

     <xsl:choose> 
      <xsl:when test="$acronyms"> 
       <xsl:call-template name="insert-acronyms"> 
        <xsl:with-param name="acronyms" select="$acronyms[position() &gt; 1]"/> 
        <xsl:with-param name="text"> 
         <xsl:call-template name="replace-words"> 
          <xsl:with-param name="text" select="$text"/> 
          <xsl:with-param name="name" select="$acronyms[1]/name"/> 
          <xsl:with-param name="description" select="$acronyms[1]/description"/> 
         </xsl:call-template> 
        </xsl:with-param> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:copy-of select="$text"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 


    <xsl:template name="replace-words"> 
     <xsl:param name="text" /> 
     <xsl:param name="name" /> 
     <xsl:param name="description" /> 

     <xsl:analyze-string select="$text" regex="{concat('(^|\W)(', string-join($name, '|'), ')(\W|$)')}"> 
      <xsl:matching-substring> 
       <xsl:value-of select="regex-group(1)"/> 
       <xsl:element name="acronym"> 
       <xsl:attribute name="title"><xsl:value-of select="$description"/></xsl:attribute> 
        <xsl:value-of select="regex-group(2)"/> 
       </xsl:element> 
       <xsl:value-of select="regex-group(3)"/> 
      </xsl:matching-substring> 
      <xsl:non-matching-substring> 
       <xsl:value-of select="."/> 
      </xsl:non-matching-substring> 
     </xsl:analyze-string> 
    </xsl:template> 

</xsl:stylesheet> 

出典:変革の

<?xml version="1.0" encoding="UTF-8"?> 
<doc> 
    <dictionary> 

     <acronym> 
      <name>WWW</name> 
      <description>The World Wide Web</description> 
     </acronym> 

     <acronym> 
      <name>HTML</name> 
      <description>The HyperText Markup Language</description> 
     </acronym> 

    </dictionary> 

    <div> 
     <p>In the <strong>WWW</strong> you can find a lot of <em>HTML</em> documents.</p> 
    </div> 

</doc> 

結果(強いとEM-タグが剥ぎ取られ、唯一の頭文字が原因で挿入されていますもう一方も剥ぎ取られます)。

+0

良い質問、+1。私の答えは、提供されたコードの問題点を指摘し、はるかに単純で非再帰的な解決策を見てください。 :) –

答えて

2

提供されたコードが不必要に複雑です。主な問題は、頭字語を1つずつ作成し、再帰処理を不必要に試みることです。ここで

が簡単かつ論理的である、非再帰的ソリューション

<doc> 
    <dictionary> 
     <acronym> 
      <name>WWW</name> 
      <description>The World Wide Web</description> 
     </acronym> 
     <acronym> 
      <name>HTML</name> 
      <description>The HyperText Markup Language</description> 
     </acronym> 
    </dictionary> 
    <div> 
     <p>In the <strong>WWW</strong> you can find a lot of <em>HTML</em> documents.</p> 
    </div> 
</doc> 

たかった:この変換が提供されるXML文書に適用され

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="my:my" exclude-result-prefixes="my"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

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

<xsl:template match="/*"> 
    <xsl:apply-templates/> 
</xsl:template> 

<xsl:template match="text()" priority="0.1"> 
    <xsl:sequence select= 
    "my:insert-acronyms(., /*/dictionary/acronym)"/> 
</xsl:template> 

    <xsl:function name="my:insert-acronyms" as="node()*"> 
    <xsl:param name="text" as="text()"/> 
    <xsl:param name="acronyms" as="node()*"/> 

    <xsl:sequence select= 
    "if($acronyms) 
     then my:replace-words($text, $acronyms/name) 
     else $text 
    "/> 
</xsl:function> 

<xsl:function name="my:replace-words" as="node()*"> 
    <xsl:param name="text" as="text()" /> 
    <xsl:param name="names" as="node()*" /> 

    <xsl:analyze-string select="$text" 
    regex="{concat('(^|\W)(', string-join($names, '|'), ')(\W|$)')}"> 
    <xsl:matching-substring> 
    <xsl:value-of select="regex-group(1)"/> 
    <acronym title="{$names[. eq regex-group(2)]/../description}"> 
     <xsl:value-of select="regex-group(2)"/> 
    </acronym> 
    <xsl:value-of select="regex-group(3)"/> 
    </xsl:matching-substring> 
    <xsl:non-matching-substring> 
    <xsl:value-of select="."/> 
    </xsl:non-matching-substring> 
    </xsl:analyze-string> 
</xsl:function> 

<xsl:template match="dictionary"/> 
</xsl:stylesheet> 

、正しい結果が得られます

+0

ありがとうございました。これは正常に動作します。 – Suidu

+0

+1一致するテキストノードの解決方法。 –

1

xsl:analyze-stringの文字列で動作します。任意の/すべてのノードに適用しようとするのではなく、text()ノードに適用するだけです。

は(未テスト)に、あなたのスタイルシートを変更してみてください:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xhtml="http://www.w3.org/1999/xhtml" 
xmlns="http://www.w3.org/1999/xhtml" 
exclude-result-prefixes="xhtml" > 
<xsl:output indent="yes" /> 

    <xsl:template match="/"> 

      <xsl:apply-templates select="/doc/div" /> 

    </xsl:template> 

    <xsl:template match="text()" priority="1"> 
     <xsl:call-template name="insert-acronyms"> 
       <xsl:with-param name="text" select="."/> 
       <xsl:with-param name="acronyms" select="/doc/dictionary/acronym"/> 
     </xsl:call-template> 
    </xsl:template> 

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

    <xsl:template name="insert-acronyms"> 
     <xsl:param name="text" as="node()*"/> 
     <xsl:param name="acronyms"/> 

     <xsl:choose> 
      <xsl:when test="$acronyms"> 
       <xsl:call-template name="insert-acronyms"> 
        <xsl:with-param name="acronyms" select="$acronyms[position() &gt; 1]"/> 
        <xsl:with-param name="text"> 
         <xsl:call-template name="replace-words"> 
          <xsl:with-param name="text" select="$text"/> 
          <xsl:with-param name="name" select="$acronyms[1]/name"/> 
          <xsl:with-param name="description" select="$acronyms[1]/description"/> 
         </xsl:call-template> 
        </xsl:with-param> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:copy-of select="$text"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 


    <xsl:template name="replace-words"> 
     <xsl:param name="text" /> 
     <xsl:param name="name" /> 
     <xsl:param name="description" /> 

     <xsl:analyze-string select="$text" regex="{concat('(^|\W)(', string-join($name, '|'), ')(\W|$)')}"> 
      <xsl:matching-substring> 
       <xsl:value-of select="regex-group(1)"/> 
       <xsl:element name="acronym"> 
       <xsl:attribute name="title"><xsl:value-of select="$description"/></xsl:attribute> 
        <xsl:value-of select="regex-group(2)"/> 
       </xsl:element> 
       <xsl:value-of select="regex-group(3)"/> 
      </xsl:matching-substring> 
      <xsl:non-matching-substring> 
       <xsl:value-of select="."/> 
      </xsl:non-matching-substring> 
     </xsl:analyze-string> 
    </xsl:template> 

</xsl:stylesheet> 
+0

私はこのソリューションをテストしましたが、問題はすべての略語を置き換えていないということでした。 Dimitre Novatchevの解決策が働いているので、私は理由を探すことはしませんでした。 – Suidu

関連する問題