XSL T讓你遞歸遍歷節點樹。在遍歷樹時,可以通過創建比其他模板規則更具體的模板規則來獲得XSLT來處理節點。
你試圖解決的問題是在轉換你的XML樹時有一些細微的差別。良好的開端是採取identity transform:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
這個身份轉換隻會產生XML輸出相同的輸入XML。它按原樣匹配並複製每個XML節點。然後,您會逐步模擬您的輸出,直到您得到您想要的。請參閱<xsl:copy/>
的文檔。
您想要進行復制的例外是當您遇到沒有任何子節點的元素時。要匹配任何元素,我們使用*
。要匹配沒有元素,我們使用not(*)
。爲了匹配沒有元素的元素,我們使用*[not(*)]
。實際上,這些規則是由XSLT使用的查詢語言XPath定義的。讓我們來試試下面的XSLT對你的XML:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*[not(*)]">
<found-an-element-with-no-children/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我們得到:
<?xml version="1.0" encoding="utf-8"?><DEV>
<HDR>
<found-an-element-with-no-children/>
<found-an-element-with-no-children/>
</HDR>
<DSC>
<found-an-element-with-no-children/>
</DSC>
</DEV>
的好處是,任何一個節點只能比對,在一次一個模板規則。我們更接近我們現在想要的地方。
這裏是<xsl:copy/>
進來。我們現在將使用它,因爲我們想複製原始元素的名稱。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*[not(*)]">
<xsl:copy>
<found-an-element-with-no-children/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
現在,我們得到:
<?xml version="1.0" encoding="utf-8"?><DEV>
<HDR>
<ApID><found-an-element-with-no-children/></ApID>
<STAT><found-an-element-with-no-children/></STAT>
</HDR>
<DSC>
<Cap><found-an-element-with-no-children/></Cap>
</DSC>
</DEV
現在添加屬性到我們新創建的節點,並在其中包括我們剛纔匹配節點的文本內容:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*[not(*)]">
<xsl:copy>
<xsl:attribute name="V">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
看起來我們在這裏:
<?xml version="1.0" encoding="utf-8"?><DEV>
<HDR>
<ApID V="value1"/>
<STAT V="value2"/>
</HDR>
<DSC>
<Cap V="value3"/>
</DSC>
</DEV>
現在兩個指針:
- 你
ApID
,STAT
和Cap
將能夠複製舊屬性無。您需要包含<xsl:apply-templates select="@*"/>
以包含這些屬性。
- 而當您包含這些屬性時,如果原始輸入包含
V
屬性會發生什麼情況?
- 您可能想額外考慮當匹配的標籤沒有文字時會發生什麼 - 以及爲什麼。
這裏沒有模板規則問題的順序嗎?我的意思是在完成'match =「@ * | node()」'之後繼續處理? –
XSLT具有模板優先級的概念。在兩個模板可以匹配同一個節點的情況下,它將優先考慮更具體的模板(即具有此處的條件的模板)。如果你願意,你可以在http://www.w3.org/TR/xslt#conflict閱讀它。 –