Xml 按嵌套参数分组的XSL
我有一个这样的XML文件Xml 按嵌套参数分组的XSL,xml,xslt,xslt-2.0,Xml,Xslt,Xslt 2.0,我有一个这样的XML文件 <fruits> <fruit> <name>banana</name> <country>Morocco</country> </fruit> <fruit> <name>orange</name> <country>Morocco</country> </fruit>
<fruits>
<fruit>
<name>banana</name>
<country>Morocco</country>
</fruit>
<fruit>
<name>orange</name>
<country>Morocco</country>
</fruit>
<fruit>
<name>grape</name>
<country>Egypt</country>
</fruit>
</fruits>
这个怎么样:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each-group select="fruit" group-by="country">
<country name="{country}">
<xsl:for-each select="current-group()">
<fruit>
<name>
<xsl:value-of select="name" />
</name>
</fruit>
</xsl:for-each>
</country>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
或者更干净的方法:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each-group select="fruit" group-by="country">
<country name="{country}">
<xsl:apply-templates select="current-group()" />
</country>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="fruit/country" />
</xsl:stylesheet>
在示例输入上运行时,其中一个会产生:
<fruits>
<country name="Morocco">
<fruit>
<name>banana</name>
</fruit>
<fruit>
<name>orange</name>
</fruit>
</country>
<country name="Egypt">
<fruit>
<name>grape</name>
</fruit>
</country>
</fruits>
香蕉
橙色
葡萄
如果您仅限于XSLT 1.0,那么有几种方法可以做到这一点:它们都不整洁。这一个查找所有在同一国家/地区之前没有同级的
元素。然后,它复制
元素,然后为其自身和具有相同国家/地区的每个后续兄弟节点复制一个新的
节点
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="/fruits">
<xsl:copy>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="fruit">
<xsl:if test="not(country = preceding-sibling::fruit/country)">
<country>
<xsl:attribute name="name">
<xsl:value-of select="country"/>
</xsl:attribute>
<xsl:for-each select="../fruit[country=current()/country]">
<fruit>
<xsl:copy-of select="name" />
</fruit>
</xsl:for-each>
</country>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
你很接近了-
groupby
表达式是相对于select
ed节点的XPath,所以你只需要groupby=“country”
,即使在XSLT1.0中,Muenchian分组也比使用前面的同级节点进行分组好得多。
@JLRishe:我同意它更有效,但它也是(甚至更有效)不透明的和不可理解的。所以这取决于你所说的“更可取”是什么意思。你已经表明了你的观点,但否决票表明我的回答没有用。你真的准备这么说吗?这只是我的观点,但我认为使用前面的兄弟姐妹进行分组是一种不好的做法,即使它更容易理解。你的回答也不正确。请仔细将您的输出与OP的期望输出进行比较。此外,OP明确表示需要2.0解决方案。这更接近,但仍然不正确。:)密切观察国家
元素与水果
元素的关系。
<fruits>
<country name="Morocco">
<fruit>
<name>banana</name>
</fruit>
<fruit>
<name>orange</name>
</fruit>
</country>
<country name="Egypt">
<fruit>
<name>grape</name>
</fruit>
</country>
</fruits>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="/fruits">
<xsl:copy>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="fruit">
<xsl:if test="not(country = preceding-sibling::fruit/country)">
<country>
<xsl:attribute name="name">
<xsl:value-of select="country"/>
</xsl:attribute>
<xsl:for-each select="../fruit[country=current()/country]">
<fruit>
<xsl:copy-of select="name" />
</fruit>
</xsl:for-each>
</country>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<fruits>
<country name="Morocco">
<fruit>
<name>banana</name>
</fruit>
<fruit>
<name>orange</name>
</fruit>
</country>
<country name="Egypt">
<fruit>
<name>grape</name>
</fruit>
</country>
</fruits>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="fruit-by-country" match="fruit" use="country" />
<xsl:template match="/fruits">
<xsl:copy>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="fruit">
<xsl:if test="generate-id() = generate-id(key('fruit-by-country', country)[1])">
<country>
<xsl:attribute name="name">
<xsl:value-of select="country"/>
</xsl:attribute>
<xsl:for-each select="key('fruit-by-country', country)">
<fruit>
<xsl:copy-of select="name" />
</fruit>
</xsl:for-each>
</country>
</xsl:if>
</xsl:template>
</xsl:stylesheet>