xslt 1.0,使用键选择节点组
我想根据一些变量选择节点。 XML代码:xslt 1.0,使用键选择节点组,xslt,grouping,xslt-1.0,muenchian-grouping,xslkey,Xslt,Grouping,Xslt 1.0,Muenchian Grouping,Xslkey,我想根据一些变量选择节点。 XML代码: <data> <prot seq="AAA"> <node num="1">1345</node> <node num="1">11245</node> <node num="2">88885</node> </
<data>
<prot seq="AAA">
<node num="1">1345</node>
<node num="1">11245</node>
<node num="2">88885</node>
</prot>
<prot seq="BBB">
<node num="1">678</node>
<node num="1">456</node>
<node num="2">6666</node>
</prot>
<prot seq="CCC">
<node num="1">111</node>
<node num="1">222</node>
<node num="2">333</node>
</prot>
</data>
1345
11245
88885
678
456
6666
111
222
333
我想要的XML
<output>
<prot seq="AAA">
<node num="1">1345</node>
<node num="2">88885</node>
</prot>
<prot seq="BBB">
<node num="1">678</node>
<node num="2">6666</node>
</prot>
<prot seq="CCC">
<node num="1">111</node>
<node num="2">333</node>
</prot>
</data>
1345
88885
678
6666
111
333
因此,我的想法是使用xsl:key元素对节点进行分组,然后对每个节点执行一次测试。例如:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="by" match="/data/prot" use="concat(@seq,'|',node/@num)"/>
<xsl:template match="/">
<root>
<xsl:apply-templates select="/data/prot"/>
</root>
</xsl:template>
<xsl:template match="/data/prot">
<xsl:for-each select="./node">
<xsl:for-each select="key('by',concat(current()/../@seq,'|',current()/@num))">
node <xsl:value-of select="./node" />
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
节点
但结果并不是我所期望的,我看不出我做错了什么。我更愿意为每一个结构保留。这就好像我没有正确使用xsl:key分组特性一样
我得到的输出,不需要的
<root>
node 1345
node 1345
node 678
node 678
node 111
node 111</root>
节点1345
节点1345
节点678
节点678
节点111
节点111
以及要测试的代码
谢谢 代码中的主要问题是关键索引
prot
元素,但我们要消除重复(并且需要索引)的是节点
元素
这里有一个简短而正确的解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="nodeByParentAndNum" match="node"
use="concat(generate-id(..), '+', @num)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<data>
<xsl:apply-templates/>
</data>
</xsl:template>
<xsl:template match=
"node
[not(generate-id()
=
generate-id(key('nodeByParentAndNum',
concat(generate-id(..), '+', @num)
)
[1]
)
)
]
"/>
</xsl:stylesheet>
<data>
<prot seq="AAA">
<node num="1">1345</node>
<node num="1">11245</node>
<node num="2">88885</node>
</prot>
<prot seq="BBB">
<node num="1">678</node>
<node num="1">456</node>
<node num="2">6666</node>
</prot>
<prot seq="CCC">
<node num="1">111</node>
<node num="1">222</node>
<node num="2">333</node>
</prot>
</data>
<data>
<prot seq="AAA">
<node num="1">1345</node>
<node num="2">88885</node>
</prot>
<prot seq="BBB">
<node num="1">678</node>
<node num="2">6666</node>
</prot>
<prot seq="CCC">
<node num="1">111</node>
<node num="2">333</node>
</prot>
</data>
当此转换应用于提供的XML文档时:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="nodeByParentAndNum" match="node"
use="concat(generate-id(..), '+', @num)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<data>
<xsl:apply-templates/>
</data>
</xsl:template>
<xsl:template match=
"node
[not(generate-id()
=
generate-id(key('nodeByParentAndNum',
concat(generate-id(..), '+', @num)
)
[1]
)
)
]
"/>
</xsl:stylesheet>
<data>
<prot seq="AAA">
<node num="1">1345</node>
<node num="1">11245</node>
<node num="2">88885</node>
</prot>
<prot seq="BBB">
<node num="1">678</node>
<node num="1">456</node>
<node num="2">6666</node>
</prot>
<prot seq="CCC">
<node num="1">111</node>
<node num="1">222</node>
<node num="2">333</node>
</prot>
</data>
<data>
<prot seq="AAA">
<node num="1">1345</node>
<node num="2">88885</node>
</prot>
<prot seq="BBB">
<node num="1">678</node>
<node num="2">6666</node>
</prot>
<prot seq="CCC">
<node num="1">111</node>
<node num="2">333</node>
</prot>
</data>
1345
11245
88885
678
456
6666
111
222
333
生成所需的正确结果:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="nodeByParentAndNum" match="node"
use="concat(generate-id(..), '+', @num)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<data>
<xsl:apply-templates/>
</data>
</xsl:template>
<xsl:template match=
"node
[not(generate-id()
=
generate-id(key('nodeByParentAndNum',
concat(generate-id(..), '+', @num)
)
[1]
)
)
]
"/>
</xsl:stylesheet>
<data>
<prot seq="AAA">
<node num="1">1345</node>
<node num="1">11245</node>
<node num="2">88885</node>
</prot>
<prot seq="BBB">
<node num="1">678</node>
<node num="1">456</node>
<node num="2">6666</node>
</prot>
<prot seq="CCC">
<node num="1">111</node>
<node num="1">222</node>
<node num="2">333</node>
</prot>
</data>
<data>
<prot seq="AAA">
<node num="1">1345</node>
<node num="2">88885</node>
</prot>
<prot seq="BBB">
<node num="1">678</node>
<node num="2">6666</node>
</prot>
<prot seq="CCC">
<node num="1">111</node>
<node num="2">333</node>
</prot>
</data>
1345
88885
678
6666
111
333
作为旁注——一定要使用一个真正的XSLT处理器,而不是一些“蛋糕”,它们可能在需要时随时可用,也可能不可用,而且可能有很多问题。我推荐的好的XSLT处理器有:(XSLT1.0)MSXML3,4,6、Saxon 6.5.4、.NET XslCompiledTransform、AltovaXML。(XSLT 2.0)Saxon 9.xx、XQSharp、AltovaXML。我正在研究这个主题,这就是为什么我还没有回答。但是,关于您的答案,您是否参考web客户端xsltcake来进行测试?我在代码中使用的处理器是firefox,我主要使用这个web应用程序来简化问题,如果我不能解决问题,就把它发布在这里。Gerard,我不会向任何朋友推荐xslcake——它是测试版的,不可靠(可能在任何时候都不可用——一次基本的DOS攻击会让它长期失效),它使用不同的XSLT处理器产生不同的结果(取决于发送请求的浏览器),有时会产生荒谬的结果。作者自己警告他们的用户这个应用程序的状态和有用性。我建议使用一个好的XSLT IDE,比如XSelerator或at list Kernow。实际上,由于我的处理器将是firefox,所以xsltcake使用相同的处理器是合适的(只要我使用firefox访问它)。但关于它的阿尔法状态你是对的。对我来说,不安装任何东西就可以使用它是一个非常有用的功能。也许在更成熟的状态下还有更多类似的web服务吗?没有,我想主要原因是,这是对DOS攻击的邀请。