XML/XSL/Xpath的新手,我已经在这些板上搜索了一个看似简单的问题的答案,但也许我对XSL太陌生,无法理解一些可能解决这个问题的答案。
我想选择一组与存储在文档中其他位置的不同节点值集匹配的节点,以便:
<body>
<partlist>
<part>head</part>
<part>spleen</part>
<part>toe</part>
</partlist>
<parts>
<head>this is a head</head>
<spleen>this is a spleen</spleen>
<toe>big toe</toe>
<toe>big toe</toe>
<parts>
</body>
因此,假设我想计算所有"部分",但我不知道"部分"节点名称,我希望 XPath expr 匹配一组名称等于另一组节点值的节点......
我对 XSL 足够陌生,既可以想象一个解决方案非常简单,但又有足够的经验意识到期望从 XSL 获得简单的解决方案肯定是一条错误的道路。
在我基于程序的无知中,这就是我尝试过的:
<xsl:template match="/">
<xsl:apply-templates select="partlist/part">
<xsl:with-param name="parts" select="parts"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="part">
<xsl:param name="parts"/>
<xsl:value-of select="count($parts[.])"/>
</xsl:template>
但这是完全错误的。任何帮助都非常感谢。
编辑:感谢您的回答,但我认为我没有被理解 - 错在我,因为我还没有完全清楚......我需要的是一个结果,告诉我是否有任何节点与引用集的节点值匹配......我认为会更改查询,因为我没有尝试输出计数列表,而是尝试将集合与集合进行匹配以计算总数......但是让我用 XSL 澄清一下,如果这样的事情是可能的。.这是我上面的代码,稍微修改了一下,以明确我的意图:
<xsl:template match="/">
<xsl:apply-templates select="partlist/part">
<xsl:with-param name="parts" select="parts"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="part">
<xsl:param name="parts"/>
<xsl:if select="count($parts[.]) > 0">1</xsl:if>
</xsl:template>
当应用于 XML 文档示例时,上述内容应输出:
1
这有意义吗?
编辑:我还应该指定我仅限于 XSL 1.0
local-name()
函数获取节点的名称,以便将其与给定值进行比较。
例如,您的样式表可以修改为:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="body/partlist/part"/>
</xsl:template>
<xsl:template match="part">
<xsl:variable name="part" select="."/>
<xsl:value-of select="count(/body/parts/*[local-name() = $part])"/>
</xsl:template>
</xsl:stylesheet>
编辑添加:
您还可以与值集进行比较,而不仅仅是单个值。从 XPath 1.0 规范第 3.4 节:
如果要比较的一个对象是节点集,另一个对象是字符串, 那么当且仅当 节点集使得在 节点和其他字符串的字符串值为 true。
如果要计算/body/parts
下有多少个元素的本地名称与 /body/partlist/part
中列出的部分匹配,可以使用以下 XPath 表达式来完成:
count(/body/parts/*[local-name() = /body/partlist/part])
编辑后添加的问题的最后一个转换可以重写
,例如:<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="body">
<xsl:apply-templates select="partlist">
<xsl:with-param name="parts" select="parts"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="partlist">
<xsl:param name="parts"/>
<xsl:if test="count($parts/*[local-name() = current()/part]) > 0">1</xsl:if>
</xsl:template>
</xsl:stylesheet>
I.此 XSLT 1.0 转换:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="part">
<xsl:value-of select="."/>
<xsl:value-of select=
"concat(': ',
count(/*/parts/*[name() = current()]),
'
')"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
应用于提供的 XML 文档时:
<body>
<partlist>
<part>head</part>
<part>spleen</part>
<part>toe</part>
</partlist>
<parts>
<head>this is a head</head>
<spleen>this is a spleen</spleen>
<toe>big toe</toe>
<toe>big toe</toe>
</parts>
</body>
产生所需的正确结果:
head: 1
spleen: 1
toe: 2
解释:
正确使用模板和current()
功能。
II. 使用单个 XPath 2.0 表达式:
/*/partlist
/part
/concat(.,
': ', for $p in .
return count(/*/parts/*[name() eq $p]),
'
'
)
当根据同一 XML 文档(如上(计算此 Xpath 2.0 表达式时,将生成所需的正确结果:
head: 1
spleen: 1
toe: 2
下面是基于 XSLT 2.0 的验证:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:sequence select=
"/*/partlist
/part
/concat(.,
': ', for $p in .
return count(/*/parts/*[name() eq $p]),
'
'
)
"/>
</xsl:template>
</xsl:stylesheet>
更新:
OP现在改变了这个问题,似乎他想:
我需要的是一个结果,告诉我是否有任何节点 匹配引用集的节点值...
这同样简单 -- 可以使用单个 XPath 表达式获得:
/*/parts/*[name() = /*/partlist/part]
此表达式的计算结果是准确true()
何时存在某些/*/parts/*
,其name()
是/*/partlist/part
元素的字符串值之一。
上述表达式可以在任何需要布尔值的地方"按原样"使用(例如在任何谓词中,作为xsl:if
或xsl:when
指令的test
属性的值,...等。
如果需要值 1(anf 不是 true()
(,只需使用:
number(/*/parts/*[name() = /*/partlist/part])
这给了我们想要的结果 1 或 0,因为根据定义:
number(true()) = 1
和
number(false()) = 0