for-each 并使用 xslt 对 xml 进行排序和分组
Posted
技术标签:
【中文标题】for-each 并使用 xslt 对 xml 进行排序和分组【英文标题】:for-each and sort and group the xml using xslt 【发布时间】:2013-03-07 07:21:47 【问题描述】:我有一个如下的 XML。对于每个测试,我需要对 cat 和 title 和 group 进行排序。 对于 cat 值 abc,我需要获取标题并设置值。 任何集合值都符合在集合节点内按升序添加标题值的需要。在这里,我确实对 cat 值进行了硬编码。但在我的场景中,cat 值是从外部源获取的。
<?xml version="1.0" encoding="utf-8" ?>
<compound>
<test>
<title>k</title>
<cetval>
<cat>abc</cat>
<cat>fcg</cat>
</cetval>
<value>1</value>
<set>
<color>blue</color>
</set>
</test>
<test>
<title>p</title>
<cetval>
<cat>fcg</cat>
<cat>klm</cat>
</cetval>
<value>10</value>
<set>
<color>pink</color>
</set>
</test>
<test>
<title>j</title>
<cetval>
<cat>fcg</cat>
<cat>klm</cat>
<cat>abc</cat>
</cetval>
<value>484</value>
<set>
<color>yellow</color>
</set>
</test>
<test>
<title>v</title>
<cetval>
<cat>dji</cat>
<cat>kfjsdlk</cat>
</cetval>
<value>93</value>
</test>
<test>
<title>r</title>
<cetval>
<cat>deiu</cat>
<cat>kfjdf</cat>
<cat>abc</cat>
</cetval>
<value>10</value>
<set>
<color>blue</color>
</set>
<test>
<title>i</title>
<cetval>
<cat>fcg</cat>
<cat>klm</cat>
<cat>abc</cat>
</cetval>
<value>10</value>
</test>
<test>
<title>w</title>
<cetval>
<cat>diweif</cat>
<cat>fjf</cat>
<cat>abc</cat>
</cetval>
<value>10</value>
<set>
<color>yellow</color>
</set>
</test>
</test>
</compound>
我需要如下输出:
<?xml version="1.0" encoding="utf-8" ?>
<compound>
<cat>abc</cat>
<set>
<color>blue</color>
<title>k</title>
<title>r</title>
</set>
<set>
<color>yellow</color>
<title>j</title>
<title>w</title>
</set>
<title>i</title>
</compound>
我的变换如下所示:
<?xml version="1.0" encoding="utf-8"?>
<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:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="compound/test">
<xsl:sort select="./cetval/cat" order="ascending"/>
<xsl:sort select="./title" order="ascending"/>
<xsl:for-each select="./cetval/cat">
<xsl:choose>
<xsl:when test="./cat = 'abc' > 0">
<xsl:value-of select="ancestor::test/title"/>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
谁能建议我如何生成所需的输出?
【问题讨论】:
“蓝色”不应该有“k”和“r”的标题,而不是“k”和“p”吗? 蒂姆,我已经编辑了我的输出.. 选择<title>i</title>
的标准是什么?
如果 cat=abc 我需要选择标题...
【参考方案1】:
好的,我想我已经理解了您的要求。怎么样:
<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="kColor" match="test" use="set/color" />
<xsl:param name="catValue" select="'abc'" />
<xsl:template match="/*">
<xsl:copy>
<cat>
<xsl:value-of select ="$catValue"/>
</cat>
<xsl:apply-templates
select="//test[generate-id() =
generate-id(
key('kColor', set/color)
[cetval/cat = $catValue][1]
)
]" />
<xsl:apply-templates
select="//test[cetval/cat = $catValue and not(set/color)]
/title">
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="test">
<set>
<xsl:apply-templates select="set/color" />
<xsl:apply-templates
select="key('kColor', set/color)[cetval/cat = $catValue]/title">
<xsl:sort select="." />
</xsl:apply-templates>
</set>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这里$catValue
被指定为参数,因此您可以从外部传入不同的值。在您的示例 XML 上运行时,结果是:
<compound>
<cat>abc</cat>
<set>
<color>blue</color>
<title>k</title>
<title>r</title>
</set>
<set>
<color>yellow</color>
<title>j</title>
<title>w</title>
</set>
<title>i</title>
</compound>
【讨论】:
@user1490088:然后将其标记为正确答案(单击答案左侧的复选标记)【参考方案2】:更短更简单:
<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="kTestByCat" match="test" use="cetval/cat"/>
<xsl:key name="kTestByColor" match="test[cetval/cat='abc']"
use="set/color"/>
<xsl:template match="/">
<compound>
<cat>abc</cat>
<xsl:apply-templates select=
"/*/*[generate-id()
=
generate-id(key('kTestByColor',set/color)[1])]"/>
</compound>
</xsl:template>
<xsl:template match="test">
<set>
<color><xsl:value-of select="set/color"/></color>
<xsl:copy-of select="key('kTestByColor',set/color)/title"/>
</set>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<compound>
<test>
<title>k</title>
<cetval>
<cat>abc</cat>
<cat>fcg</cat>
</cetval>
<value>1</value>
<set>
<color>blue</color>
</set>
</test>
<test>
<title>p</title>
<cetval>
<cat>fcg</cat>
<cat>klm</cat>
</cetval>
<value>10</value>
<set>
<color>pink</color>
</set>
</test>
<test>
<title>j</title>
<cetval>
<cat>fcg</cat>
<cat>klm</cat>
<cat>abc</cat>
</cetval>
<value>484</value>
<set>
<color>yellow</color>
</set>
</test>
<test>
<title>v</title>
<cetval>
<cat>dji</cat>
<cat>kfjsdlk</cat>
</cetval>
<value>93</value>
</test>
<test>
<title>r</title>
<cetval>
<cat>deiu</cat>
<cat>kfjdf</cat>
<cat>abc</cat>
</cetval>
<value>10</value>
<set>
<color>blue</color>
</set>
<test>
<title>i</title>
<cetval>
<cat>fcg</cat>
<cat>klm</cat>
<cat>abc</cat>
</cetval>
<value>10</value>
</test>
<test>
<title>w</title>
<cetval>
<cat>diweif</cat>
<cat>fjf</cat>
<cat>abc</cat>
</cetval>
<value>10</value>
<set>
<color>yellow</color>
</set>
</test>
</test>
</compound>
产生了想要的正确结果:
<compound>
<cat>abc</cat>
<set>
<color>blue</color>
<title>k</title>
<title>r</title>
</set>
<set>
<color>yellow</color>
<title>j</title>
<title>w</title>
</set>
</compound>
如果您想为cat
的所有 区别值产生类似的结果,那么它又是简短而简单的:
<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="kCatByVal" match="cat" use="."/>
<xsl:key name="kColorByVal" match="color" use="."/>
<xsl:key name="kTestByCat" match="test" use="cetval/cat"/>
<xsl:variable name="vDistinctColors" select=
"/*/*/set/color[generate-id()=generate-id(key('kColorByVal',.)[1])]"/>
<xsl:template match="/">
<xsl:apply-templates select=
"/*/*/cetval/cat
[generate-id()
= generate-id(key('kCatByVal',.)[1])]"/>
</xsl:template>
<xsl:template match="cat">
<xsl:variable name="vcurCat" select="."/>
<compound>
<cat><xsl:apply-templates/></cat>
<xsl:for-each select="$vDistinctColors">
<xsl:apply-templates select=
"(key('kCatByVal',$vcurCat)/../../set/color[.=current()])[1]">
<xsl:with-param name="pCat" select="$vcurCat"/>
</xsl:apply-templates>
</xsl:for-each>
</compound>
</xsl:template>
<xsl:template match="color">
<xsl:param name="pCat"/>
<xsl:copy-of select="."/>
<xsl:copy-of select="key('kTestByCat',$pCat)[set/color=current()]/title"/>
</xsl:template>
</xsl:stylesheet>
当应用于同一个 XML 文档(上图)时,现在的结果是:
<compound>
<cat>abc</cat>
<color>blue</color>
<title>k</title>
<title>r</title>
<color>yellow</color>
<title>j</title>
<title>w</title>
</compound>
<compound>
<cat>fcg</cat>
<color>blue</color>
<title>k</title>
<color>pink</color>
<title>p</title>
<color>yellow</color>
<title>j</title>
</compound>
<compound>
<cat>klm</cat>
<color>pink</color>
<title>p</title>
<color>yellow</color>
<title>j</title>
</compound>
<compound>
<cat>dji</cat>
</compound>
<compound>
<cat>kfjsdlk</cat>
</compound>
<compound>
<cat>deiu</cat>
<color>blue</color>
<title>r</title>
</compound>
<compound>
<cat>kfjdf</cat>
<color>blue</color>
<title>r</title>
</compound>
【讨论】:
以上是关于for-each 并使用 xslt 对 xml 进行排序和分组的主要内容,如果未能解决你的问题,请参考以下文章
在 msxsl 中将节点作为参数传递:来自 XSLT for-each 的脚本 javascript 函数不起作用