一些事情,這將使這些答案的理解您可以更容易:
首先,節點和元素是不一樣的東西。元素是節點,但節點不一定是元素。您經常會發現人們交替使用這些術語。 XML中實際上有四種節點:元素,文本節點,處理指令和註釋。 (屬性並不是真正的節點,我將在第二時間完成。)
在XSLT中,XML文檔的根不是它的頂層元素;根是一種實際上並不存在的抽象。頂層元素是根的孩子。例如,這裏有一個良好的XML文檔,其根有五個子節點,包括頂級元素:
<?xml-stylesheet href="mystyle.css" type="text/css"?>
<!-- this is a perfectly legitimate XML document -->
<top_level_element/>
五?看起來只有三個。我想我會讓你弄清楚其他兩個是你自己的。提示:在這個例子中實際上可能有七個節點。
XPath表達式/
找到文檔根,而不是頂級元素。在上述情況下,要查找頂級元素,請使用/top_level_element
或/*
。 (使用/*
來查找頂級元素總是安全的,因爲文檔根目錄必須有一個元素子元素。)
因此,我們來看看apply-templates
的功能。它基本上執行兩個步驟:首先,它構建一組節點。然後,對於每一個,它都會找到一個匹配的模板(從XSLT文件中的模板中找到)並將模板應用到它。正如您在其中一條評論中觀察到的那樣,它在概念上與循環非常相似。
select
屬性用於第一步。它提供了一個XPath表達式,用於構建將要應用模板的節點集。如果沒有提供select
屬性,則它構建的列表是上下文節點的所有子節點。 (「上下文節點」是當前模板正在應用的節點。)
template
元素上的match
屬性用於第二步。樣式表處理器查找所有模板,其match
屬性與其嘗試應用模板的節點相匹配。如果它找到多於一個,則它選擇它可以最特定的一個,例如,考慮到這些模板:
<xsl:template match="*"/>
<xsl:template match="foo"/>
<xsl:template match="foo[bar]"/>
與bar
子元素foo
元素將第三匹配,沒有bar
一個foo
元素將被第二匹配,和一個baz
元素將通過首次匹配。 (XSLT使用的實際方法定義爲here;實際上,我已經使用XSLT將近十年了,但我從未需要知道它是如何工作的,儘管它很有趣。)
如果它不找到匹配,它將使用內置的默認模板爲節點的類型 - 基本上,你可以假設任何XSLT轉換隱含地包含了這些模板:
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()">
<xsl:copy/>
</xsl:template>
<xsl:template match="processing-instruction() | comment() | @*"/>
武裝用這些知識,你現在可以瞭解身份變換:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
匹配任何節點或屬性(請注意,屬性不是節點,這就是爲什麼需要@*
),複製它,然後將模板應用於其所有子節點和屬性。 (只有文檔根目錄和元素纔會有子節點,並且只有元素將具有屬性。)由於它是變換中唯一的模板,並且它匹配所有節點和屬性,所以它將自身應用於所有子節點和屬性。因此,它將源樹中的所有內容複製到輸出樹中。
如果這個模板添加到識別轉換:
<xsl:template match="foo"/>
你現在有一個變換拷貝源代碼樹每個節點除了foo
元素 - 這第二個模板匹配foo
元素(第一個也是如此,但由於第二個屬性更具體,它是XSLT選擇的一個),並且對它們不做任何處理。
鑑於這一切,在回答您的具體問題:
<xsl:apply-templates>
適用模板上下文節點的孩子。
在步驟1中不匹配匹配的節點; XSLT處理器爲每個處理器找到一個模板並應用它。
在此示例中,上下文節點是文檔根,頂層元素以及其外部的任何註釋或處理指令都是子級的抽象節點。
聲明「屬性不是真正的節點」是不正確的。屬性是節點,但屬性不是元素的子節點。有關更多詳細信息,請參閱下面的答案。 只爲兒童執行模板(axis child :),但不能用於屬性(axis attribute :): –
2017-11-27 18:48:27