我有一个包含项目的XML文档,每个项目都有一个标记化的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>
我需要将其转换为另一个XML文档,该文档根据ID字符串的 middle 部分(上例中的字母)对项目进行分组。
<?xml version='1.0' ?>
<GroupedItems>
<Group id="A">
<Item>foo</Item>
</Group>
<Group id="B">
<Item>bar</Item>
<Item>baz</Item>
</Group>
</GroupedItems>
我正在使用按键功能找到群组:
<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。
答案 0 :(得分:1)
如果你想使用Muenchian分组方法,使用vanilla XSLT 1.0就会遇到代码重复问题。能够在密钥提取中使用模板的解决方案会慢得多,而且可读性也会降低。
答案 1 :(得分:1)
首先,如果您使用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()
扩展功能。