Mae*_*o13 6 xslt xpath xslt-1.0
我有一个XSLT,其中(从输入数据中)创建中间变量,如下所示(硬编码示例,但本质上是动态的):
<xsl:variable name="variableX">
<ValidCode CodePart="CP1" Code="C1"/>
<ValidCode CodePart="CP2" Code="C2"/>
<ValidCode CodePart="CP1" Code="C3"/>
<ValidCode CodePart="CP2" Code="C4"/>
<ValidCode CodePart="CP2" Code="C5"/>
</xsl:variable>
Run Code Online (Sandbox Code Playgroud)
我希望遍历CodePart值的不同出现。在XSLT 2.0中,这很容易:
<xsl:for-each select="distinct-values($variableX/ValidCode/@CodePart)">...</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)
但是,如何在XSLT 1.0中做到最好呢?
请注意,我不能使用键,因为它是动态确定的变量,而不是输入文件的一部分。
我的输入文件确实包含所有可能的代码部分的列表,如下所示:
<root>
<CodePart><value>CP1</value></CodePart>
<CodePart><value>CP2</value></CodePart>
<CodePart><value>CP3</value></CodePart>
</root>
Run Code Online (Sandbox Code Playgroud)
所以我想到了循环//CodePart/value,以确保初学者的独特性。但是然后我需要一些包含条件的Xpath表达式
“值出现在所有$ variableX / ValidCode / @ CodePart值的节点集中”
并使用类似
<xsl:for-each select="//CodePart[..condition..]/value">...</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)
我正在寻找Xpath表达式的简单形式吗?
还是其他方法更可取?
请注意,我无法使用密钥,因为它是动态确定的变量,而不是输入文件的一部分。
这根本不是真的。
这是一个简短、简单且最有效的使用键的解决方案(顺便说一句,不使用任何条件指令或xsl:for-each根本不使用:)):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kCodeByPart" match="ValidCode" use="@CodePart"/>
<xsl:variable name="variableX">
<ValidCode CodePart="CP1" Code="C1"/>
<ValidCode CodePart="CP2" Code="C2"/>
<ValidCode CodePart="CP1" Code="C3"/>
<ValidCode CodePart="CP2" Code="C4"/>
<ValidCode CodePart="CP2" Code="C5"/>
</xsl:variable>
<xsl:variable name="vCodes" select="ext:node-set($variableX)/*"/>
<xsl:template match="/">
<xsl:apply-templates select=
"$vCodes[generate-id()
=
generate-id(key('kCodeByPart', @CodePart)[1])
]"/>
</xsl:template>
<xsl:template match="ValidCode">
Code Part: <xsl:value-of select="@CodePart"/>
Codes: <xsl:apply-templates select=
"key('kCodeByPart', @CodePart)/@Code"/>
</xsl:template>
<xsl:template match="@Code">
<xsl:value-of select="concat(., ' ')"/>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当此转换应用于任何 XML 文档(未使用)时,就会产生所需的正确结果:
Code Part: CP1
Codes: C1 C3
Code Part: CP2
Codes: C2 C4 C5
Run Code Online (Sandbox Code Playgroud)
解释:
正如W3C XSLT 1.0 建议中所指定的:
Run Code Online (Sandbox Code Playgroud)"The key can be used to retrieve a key from a document other than the document containing the context node."
在提供的解决方案中,我们甚至不使用这种可能性 - 上下文节点和检索到的密钥都来自同一文档 - 中包含的临时树$vCodes。
同样,它指定一个密钥可以用于多个文档:
“样式表使用 xsl:key 元素为每个文档声明一组键。”
简而言之:索引是在当前文档(包含上下文(当前)节点的文档)上执行的。
我认为您不能直接使用 XPath - 但您应该能够仅检查有效值,如下所示:
<xsl:for-each select="//CodePart/value">
<xsl:variable name="CodePart" select="."/>
<xsl:if test="$variableX/ValidCode[@CodePart=$CodePart]">
. . .
</xsl:if>
</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)
或者更简单(感谢评论):
<xsl:for-each select="//CodePart/value">
<xsl:if test="$variableX/ValidCode[@CodePart=current()]">
. . .
</xsl:if>
</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)
如果$variableX不是节点集而是 XML 片段,则需要将其转换为节点集 - 这是依赖于实现的,使用 Microsoft 处理器:
<xsl:for-each select="//CodePart/value" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:if test="msxsl:node-set($variableX)/ValidCode[@CodePart=current()]">
. . .
</xsl:if>
</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)