2015-02-08 82 views
1

我正在使用XSLT 2.0。在xsl:template(模板-1)中,我使用xsl:analyze-string創建具有xml:lang屬性的新的span元素。我有第二個模板(template-2),它將class屬性添加到包含xml:lang屬性的元素。在我的樣式表中,由第一個模板創建的新創建的span元素沒有被第二個處理。我如何解決這個問題,並讓第二個模板對第一個模板的結果進行操作?XSLT模板不適用於新創建的元素

實施例:

輸入:<p>The base form of a noun is technically called a <span xml:lang="sa-Latn">prātipadika</span> (प्रातिपदिक).</p>

所需的輸出:<p>The base form of a noun is technically called a <span xml:lang="sa-Latn" class="lang-sa-latn">prātipadika</span> (<span xml:lang="sa-Deva" class="lang-sa-deva">प्रातिपदिक</span>).</p>該正確的輸出具有最終spanxml:langclass屬性。

樣式表輸出:<p>The base form of a noun is technically called a <span xml:lang="sa-Latn" class="lang-sa-latn">prātipadika</span> (<span xml:lang="sa-Deva">प्रातिपदिक</span>).</p>在最終的span上錯誤輸出class="sa-lang-deva"

(由樣式表幫助所產生的額外的類來解決不足的CSS支持一定的電子書閱讀器的。)


這裏是我的樣式表:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="2.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns="http://www.w3.org/1999/xhtml" 
       xpath-default-namespace="http://www.w3.org/1999/xhtml" 
       xmlns:xml="http://www.w3.org/XML/1998/namespace" 
       xmlns:epub="http://www.idpf.org/2007/ops"> 

    <xsl:output method="xhtml" encoding="utf-8" indent="no"/> 

    <xsl:template match="/"> 
     <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops"> 
      <xsl:apply-templates/> 
     </html> 
    </xsl:template> 

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

    <!-- Template-1: Add xml:lang attribute to Devanagari text. --> 
    <xsl:template match="element()/text()"> 
     <xsl:variable name="textValue" select="."/> 
     <xsl:analyze-string select="$textValue" regex="([&#x0900;-&#x097f;]+)((\s+[&#x0900;-&#x097f;]+)*)"> 
      <xsl:matching-substring> 
       <span xml:lang="sa-Deva"><xsl:value-of select="."/></span> 
      </xsl:matching-substring> 
      <xsl:non-matching-substring> 
       <xsl:value-of select="."/> 
      </xsl:non-matching-substring> 
     </xsl:analyze-string> 
    </xsl:template> 

    <!-- Template-2: Add lang-* class attribute when xml:lang attribute present. --> 
    <xsl:template match="*[@xml:lang]"> 
     <xsl:call-template name="addClass"> 
      <xsl:with-param name="newClass">lang-<xsl:value-of select="@xml:lang"/></xsl:with-param> 
     </xsl:call-template> 
    </xsl:template> 

    <!-- Add a class attribute to an element. --> 
    <xsl:template name="addClass"> 
     <xsl:param name="newClass"/> 
     <xsl:copy> 
      <xsl:copy-of select="@*"/> 
      <xsl:attribute name="class"><xsl:value-of select="normalize-space(concat(@class, ' ', lower-case($newClass)))"/></xsl:attribute> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

回答

1

您需要將由analyze-string創建的節點捕獲到變量中,然後將模板應用於它們。您可以使用模板模式來避免無限遞歸。

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="2.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns="http://www.w3.org/1999/xhtml" 
       xpath-default-namespace="http://www.w3.org/1999/xhtml" 
       xmlns:xml="http://www.w3.org/XML/1998/namespace" 
       xmlns:epub="http://www.idpf.org/2007/ops"> 

    <xsl:output method="xhtml" encoding="utf-8" indent="no"/> 

    <xsl:template match="/"> 
     <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops"> 
      <xsl:apply-templates/> 
     </html> 
    </xsl:template> 

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

    <!-- Template-1: Add xml:lang attribute to Devanagari text. Note no 
     mode attribute, so only applies in default mode. --> 
    <xsl:template match="text()"> 
     <xsl:variable name="textValue" select="."/> 
     <xsl:variable name="nodes" as="node()*"> 
      <xsl:analyze-string select="$textValue" regex="([&#x0900;-&#x097f;]+)((\s+[&#x0900;-&#x097f;]+)*)"> 
       <xsl:matching-substring> 
        <span xml:lang="sa-Deva"><xsl:value-of select="."/></span> 
       </xsl:matching-substring> 
       <xsl:non-matching-substring> 
        <xsl:value-of select="."/> 
       </xsl:non-matching-substring> 
      </xsl:analyze-string> 
     </xsl:variable> 
     <!-- apply templates to generated nodes, but with a mode that stops 
      this template from firing again --> 
     <xsl:apply-templates select="$nodes" mode="no-deva" /> 
    </xsl:template> 

    <!-- Template-2: Add lang-* class attribute when xml:lang attribute present. --> 
    <xsl:template match="*[@xml:lang]" mode="#all"> 
     <xsl:call-template name="addClass"> 
      <xsl:with-param name="newClass">lang-<xsl:value-of select="@xml:lang"/></xsl:with-param> 
     </xsl:call-template> 
    </xsl:template> 

    <!-- Add a class attribute to an element. --> 
    <xsl:template name="addClass"> 
     <xsl:param name="newClass"/> 
     <xsl:copy> 
      <xsl:copy-of select="@*"/> 
      <xsl:attribute name="class"><xsl:value-of select="normalize-space(concat(@class, ' ', lower-case($newClass)))"/></xsl:attribute> 
      <xsl:apply-templates select="@*|node()" mode="#current"/> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

Working example

我到你原來的XSLT作出的變化是:

  • 添加mode="#all"的身份模板和 「模板2」,所以他們在所有模式適用,將mode="#current"添加到相關的apply-templates指令中,因此它們使用任何當前模式遞歸。
  • analyze-string<xsl:variable>包圍以捕獲其生成的節點。
  • apply-templates到這些節點使用不同的模式

由於I(故意)沒有初始通期間apply-templates mode="no-deva"過程中添加到mode="#all"模板1它只匹配,而不是。

+0

這很好用!謝謝。我沒有想到這樣捕獲節點。您設置模式的方式也很有指導意義。 – keithm 2015-02-08 23:44:55