2011-08-26 48 views
2

這是我第一次用XSLT或XML做任何事情,所以請原諒。我發現XSLT Web文檔非常簡潔。將XSLT用作XML預處理器

我有一個XML文件,我想處理基於一組輸入定義來選擇性地刪除內容。該行爲應該類似於處理ifdef塊的簡單代碼預處理器。

我已經制定了如何做到如下,但一些部分,如「內容」變量似乎不是最好的方式來處理這個。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="xml" /> 
    <xsl:param name="defines-uri" required="yes"/> 

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

    <xsl:template match="ifdef"> 
    <xsl:variable name="contents" select="child::node()"/> 
    <xsl:variable name="defines" select="document($defines-uri)/defines"/> 
    <xsl:variable name="val" select="@select"/> 

    <xsl:for-each select="$defines"> 
     <xsl:if test="def=$val"> 
     <xsl:apply-templates select="$contents"/> 
     </xsl:if> 
    </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

主要問題是在定義中找到匹配的情況下應用模板。如果沒有內容,我會在輸出中獲得不同程度的定義文檔。

什麼是無需轉換就可以進行XML預處理的最佳方式?

+3

示例XML文檔和預期輸出將非常有用。 – Tomalak

回答

1

我已經弄清楚如何做到這一點,但「內容」變量等部分似乎並不是最好的方式來處理這個問題。

那麼,基本上你是對的。儘管如此,您仍然可以改進一點:

<xsl:variable name="defines" select="document($defines-uri)/defines"/> 

<xsl:template match="ifdef"> 
    <xsl:variable name="this" select="."/> 

    <xsl:for-each select="$defines[def = $this/@select]"> 
    <xsl:apply-templates select="$this/node()" /> 
    </xsl:for-each> 
</xsl:template> 

<xsl:for-each>更改上下文節點。在它內部,.指的是正在迭代的節點,而不是已被<xsl:template>匹配的節點。

這意味着您必須在變量中預先設置「外部」上下文,這是標準做法。

1

對於那些剛剛開始使用XSLT XML的人來說,您確實做得非常好。

這不是一個回答你的問題,但我只想說,這可能是一個更安全的「默認複製」模板:

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

此致工作由某些默認內置的恩典在模板中。但是,當添加更多模板時,您可能會遇到有關文本節點(或其他非元素事物)的奇怪行爲,因爲缺省值的優先級較低。

+0

+1 - 同意。值得注意的是,在更復雜的轉換中,OP的'實際上是無益的。 – Tomalak