Xml 在XSLT密钥生成中使用模板
我有一个包含项目的XML文档,每个项目都有一个标记化的ID字符串Xml 在XSLT密钥生成中使用模板,xml,xslt,xslt-1.0,Xml,Xslt,Xslt 1.0,我有一个包含项目的XML文档,每个项目都有一个标记化的ID字符串 <?xml version="1.0"?> <Test> <Items> <Item> <ID>1_A_3</ID> <Name>foo</Name> </Item> <Item> <ID>1_B_5</ID>
<?xml version="1.0"?>
<Test>
<Items>
<Item>
<ID>1_A_3</ID>
<Name>foo</Name>
</Item>
<Item>
<ID>1_B_5</ID>
<Name>bar</Name>
</Item>
<Item>
<ID>1_B_7</ID>
<Name>baz</Name>
</Item>
</Items>
</Test>
1_A_3
福
1_B_5
酒吧
1_B_7
巴兹
我需要将其转换为另一个XML文档,该文档根据项目ID字符串的中间部分(上面示例中的字母)对项目进行分组
福
酒吧
巴兹
我正在使用密钥功能查找组:
<xsl:key name="uniqueGroupIDs"
match="Test/Items/Item"
use="substring-before(substring-after(ID,'_'),'_')"/>
<xsl:for-each
select="Test/Items/Item[generate-id() =
generate-id(key('uniqueGroupIDs',
substring-before(substring-after(ID,'_'),'_')))]">
请注意,这两个位置的子字符串调用都有代码重复。我已经有了一个做同样事情的模板:
<xsl:template name="ExtractGroupID">
<xsl:param name="idString"/>
<xsl:value-of
select="substring-before(substring-after($idString, '_'),'_')"/>
</xsl:template>
有没有办法在关键语句中使用该模板,以避免代码重复
在XSLT 2.0中,我只想定义一个函数来实现这一点,但由于我无法控制的工具限制,我一直坚持使用XSLT 1.0。如果要使用Muenchian分组方法,那么在vanilla XSLT 1.0中,您将不得不重复代码。能够在密钥提取中使用模板的解决方案速度会慢得多,可读性也会差得多。首先,如果您使用Muenchian分组方法查看这里的所有答案,您将看到它们中的每一个都“复制”了密钥值计算 唯一的“解决方案”是两阶段转换:一个模板只向输入源添加一个具有计算值的节点,一个键使用这个生成的节点(无需进一步计算)。这种方法对于复杂的计算键值也是有效的:XPath表达式能力之外的键值 例如,此样式表:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:key name="kItemByKey" match="Item[@key]" use="@key"/>
<xsl:template match="/">
<xsl:variable name="vrtfFirstPass">
<xsl:apply-templates select="/*/*/*"/>
</xsl:variable>
<GroupedItems>
<xsl:apply-templates select="msxsl:node-set($vrtfFirstPass)/*"/>
</GroupedItems>
</xsl:template>
<xsl:template match="Item[not(@key)]">
<Item key="{substring-before(substring-after(ID,'_'),'_')}">
<xsl:copy-of select="@*|node()"/>
</Item>
</xsl:template>
<xsl:template match="Item[@key]"/>
<xsl:template match="Item[generate-id()
= generate-id(
key('kItemByKey',@key)[1]
)]"
priority="1">
<Group id="{@key}">
<xsl:apply-templates select="key('kItemByKey',@key)/Name"/>
</Group>
</xsl:template>
<xsl:template match="Name">
<Item>
<xsl:value-of select="."/>
</Item>
</xsl:template>
</xsl:stylesheet>
输出:
<GroupedItems>
<Group id="A">
<Item>foo</Item>
</Group>
<Group id="B">
<Item>bar</Item>
<Item>baz</Item>
</Group>
</GroupedItems>
福
酒吧
巴兹
注意:
node-set()
扩展函数。@Alejandro:您能否链接到您描述的两阶段“解决方案”的示例?谢谢
<GroupedItems>
<Group id="A">
<Item>foo</Item>
</Group>
<Group id="B">
<Item>bar</Item>
<Item>baz</Item>
</Group>
</GroupedItems>