有没有办法遍历一个键并输出它包含的所有值?
<xsl:key name="kElement" match="Element/Element[@idref]" use="@idref" />
我虽然这样:
<xsl:for-each select="key('kElement', '.')">
<li><xsl:value-of select="." /></li>
</xsl:for-each>
然而,这不起作用。我只想列出一个键中的所有值以进行测试。
问题很简单:如何做到这一点?
答案 0 :(得分:13)
你做不到。这不是关键所针对的。
当且仅当每个元素的键相同时,您才可以使用对key()
的单个调用遍历键中的每个元素。
如果您需要循环定义键的所有内容,则可以使用match="..."
元素的<key>
属性中的表达式。
所以,如果您有这样的文件:
<root>
<element name="Bill"/>
<element name="Francis"/>
<element name="Louis"/>
<element name="Zoey"/>
</root>
这样的键定义如下:
<xsl:key name="survivors" match="element" use="@name"/>
您可以使用其match
属性的内容遍历密钥使用的内容:
<xsl:for-each select="element">
<!-- stuff -->
</xsl:for-each>
或者,如果每个元素都有一些共同点:
<root>
<element name="Bill" class="survivor"/>
<element name="Francis" class="survivor"/>
<element name="Louis" class="survivor"/>
<element name="Zoey" class="survivor"/>
</root>
然后你可以像这样定义你的密钥:
<xsl:key name="survivors" match="element" use="@class"/>
迭代所有这样的元素:
<xsl:for-each select="key('survivors', 'survivor')">
<!-- stuff -->
</xsl:for-each>
因为每个元素共享class
属性的值“幸存者”。
在您的情况下,您的密钥是
<xsl:key name="kElement" match="Element/Element[@idref]" use="@idref" />
所以你可以遍历它所拥有的一切:
<xsl:for-each select="Element/Element[@idref]">
<!-- stuff -->
</xsl:for-each>
答案 1 :(得分:5)
您 CAN 创建用于循环的密钥 - 如果您只是在密钥元素的use属性中指定常量:
<xsl:key name="survivors" match="element" use="'all'"/>
然后您可以通过以下方式遍历所有元素:
<xsl:for-each select="key('survivors','all')">
...
</xsl:for-each>
或计算他们:
<xsl:value-of select="count(key('survivors','all'))"/>
请注意,常量可以是任何字符串,甚至可以是数字 - 但“全部”读数都很好。
但是,您无法使用此密钥来查找有关各个条目的信息(因为它们都具有相同的密钥)。
换句话说,有两种可能的键:
我不知道这个方法的执行效率如何,但它确实通过避免在整个XSL代码中重复相同(可能非常复杂)的XPath表达式来提高XSL的维护效率。
答案 2 :(得分:2)
不要在编程语言术语中考虑XSL密钥,而应将它们视为SQL的记录集。这样可以更好地理解。对于作为
创建的给定密钥索引<xsl:key name="paths" match="path" use="keygenerator()">
它可以是“迭代”/“走完”,如下所示
<xsl:for-each select="//path[generate-id()=generate-id(key('paths',keygenerator())[1])]">
要理解这个神奇的数字[1]
,让我们看看下面的例子:
考虑这个XML片段
<root>
<Person>
<name>Johny</name>
<date>Jan10</date>
<cost itemID="1">34</cost>
<cost itemID="1">35</cost>
<cost itemID="2">12</cost>
<cost itemID="3">09</cost>
</Person>
<Person>
<name>Johny</name>
<date>Jan09</date>
<cost itemID="1">21</cost>
<cost itemID="1">41</cost>
<cost itemID="2">11</cost>
<cost itemID="2">14</cost>
</Person>
</root>
使用此XSL进行转换。
<xsl:for-each select="*/Person">
<personrecords>
<xsl:value-of select="generate-id(.)" />--
<xsl:value-of select="name"/>--
<xsl:value-of select="date"/>--
</personrecords>
</xsl:for-each>
<xsl:for-each select="*/*/cost">
<costrecords>
<xsl:value-of select="generate-id(.)" />--
<xsl:value-of select="../name"/>--
<xsl:value-of select="../date"/>--
<xsl:value-of select="@itemID"/>--
<xsl:value-of select="text()"/>
</costrecords>
</xsl:for-each>
上面的XSL转换以Person
的形式列出了cost
节点和idpxxxxxxx
节点的唯一ID,如下所示。
1. <personrecords>idp2661952--Johny--Jan10-- </personrecords>
2. <personrecords>idp4012736--Johny--Jan09-- </personrecords>
3. <costrecords>idp2805696--Johny-- Jan10-- 1-- 34</costrecords>
4. <costrecords>idp4013568--Johny-- Jan10-- 1-- 35</costrecords>
5. <costrecords>idp2808192--Johny-- Jan10-- 2-- 12</costrecords>
6. <costrecords>idp2808640--Johny-- Jan10-- 3-- 09</costrecords>
7. <costrecords>idp2609728--Johny-- Jan09-- 1-- 21</costrecords>
8. <costrecords>idp4011648--Johny-- Jan09-- 1-- 41</costrecords>
9. <costrecords>idp2612224--Johny-- Jan09-- 2-- 11</costrecords>
10.<costrecords>idp2610432--Johny-- Jan09-- 2-- 14</costrecords>
让我们使用cost
和name
值组合在itemID
条记录上创建密钥。
<xsl:key name="keyByNameItem" match="cost" use="concat(../name, '+', @itemID)"/>
手动查看XML,上面的唯一键的数量将是三个: Johny + 1 , Johny + 2 和 Johny + 3 < /强>
现在让我们使用下面的代码段来测试这个密钥。
<xsl:for-each select="*/*/cost">
<costkeygroup>
<xsl:value-of select="generate-id(.)" />--
(1)<xsl:value-of select="generate-id(key('keyByNameItem',concat(../name, '+', @itemID) )[1] ) " />--
(2)<xsl:value-of select="generate-id(key('keyByNameItem',concat(../name, '+', @itemID) )[2] ) " />--
(3)<xsl:value-of select="generate-id(key('keyByNameItem',concat(../name, '+', @itemID) )[3] ) " />--
(4)<xsl:value-of select="generate-id(key('keyByNameItem',concat(../name, '+', @itemID) )[4] ) " />
</costkeygroup>
</xsl:for-each>
结果如下:
1. <costkeygroup>idp2805696-- (1)idp2805696-- (2)idp4013568-- (3)idp2609728-- (4)idp4011648</costkeygroup>
2. <costkeygroup>idp4013568-- (1)idp2805696-- (2)idp4013568-- (3)idp2609728-- (4)idp4011648</costkeygroup>
3. <costkeygroup>idp2808192-- (1)idp2808192-- (2)idp2612224-- (3)idp2610432-- (4)</costkeygroup>
4. <costkeygroup>idp2808640-- (1)idp2808640-- (2)-- (3)-- (4)</costkeygroup>
5. <costkeygroup>idp2609728-- (1)idp2805696-- (2)idp4013568-- (3)idp2609728-- (4)idp4011648</costkeygroup>
6. <costkeygroup>idp4011648-- (1)idp2805696-- (2)idp4013568-- (3)idp2609728-- (4)idp4011648</costkeygroup>
7. <costkeygroup>idp2612224-- (1)idp2808192-- (2)idp2612224-- (3)idp2610432-- (4)</costkeygroup>
8. <costkeygroup>idp2610432-- (1)idp2808192-- (2)idp2612224-- (3)idp2610432-- (4)</costkeygroup>
我们的兴趣在于努力了解[1]
,[2]
,[3]
,[4]
的重要性。在我们的例子中,密钥生成器是concat(../name, '+', @itemID)
。
对于给定的密钥,[1]
指的是满足密钥生成器的节点的第一次出现。类似地,[2]
指的是满足密钥生成器的节点的第二次出现。因此[2]
,[3]
,[4]
等都是满足相同密钥的节点,因此可以认为是给定密钥的重复。重复数量取决于输入XML。因此:
键 Johny + 1 满足 4 节点(1)idp2805696--(2)idp4013568--(3)idp2609728--(4)idp4011648 < / em>的
键 Johny + 2 满足 3 节点(1)idp2808192--(2)idp2612224--(3)idp2610432--(4) <登记/> 键 Johny + 3 满足 1 节点(1)idp2808640--(2) - (3) - (4)
因此,我们看到可以通过密钥访问XML的所有8个cost
节点。
这是一个结合转换结果的图像,有助于更好地理解。
红色方块表示 Johny + 1 的匹配节点。绿色方块表示 Johny + 3 的匹配节点。将idpxxxxxxx
中的<costkeygroup>
值与<costrecords>
中的值相匹配。 <costrecords>
帮助将idpxxxxxxx
值映射到源XML。
外卖是,
XSL密钥不会过滤或消除节点。可以通过密钥访问包括重复的所有节点。因此,当我们说“遍历”密钥时,没有概念表示原始节点集合中的结果子集可用于处理密钥。
要在上面的示例中仅“遍历”键的唯一节点,请使用
<xsl:for-each select="*/*/workTime[generate-id()=generate-id(key('keyByNameItem', concat(../name, '+', @itemID) )[1] ) ] ">
[1]
表示给定键值的第一条记录表示为唯一记录。几乎总是使用[1]
因为至少存在一个满足给定键值的节点。如果我们确定至少有2条记录可以满足密钥中的每个密钥值,我们可以继续使用[2]
将记录集中的第二条记录标识为唯一记录。
P.S节点/记录/元素这两个词可以互换使用。
答案 3 :(得分:0)
虽然我们可以输出它包含的所有值,但无法遍历键。在XSLT2中,它比在XSLT1中更容易(例如,根据前面的答案使用fn:generate-id
)。
使用fn:distinct-values
<xsl:variable name="e" select="."/>
<xsl:for-each select="distinct-values(Element/Element[@idref]/@idref)">
<li key="{.}"><xsl:value-of select="key('kElement', ., $e )" /></li>
</xsl:for-each>
使用xsl:for-each-group
<xsl:for-each-group select="Element/Element[@idref]" group-by="@idref">
<li key="{current-grouping-key()}"><xsl:value-of select="current-group()" /></li>
</xsl:for-each-group>