我最近开始研究XSLT。我需要根据id字段对节点值进行分组。但是,id字段可以是重复值。例如,下面假设是XML结构。
<ProductResults>
<ProductResult>
<ProductId>1000</ProductId>
<Location>Bangalore</Location>
<ModuleNumber>02</ModuleNumber>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>2000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Bangalore</Location>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>01</ModuleNumber>
<Location>Mumbai</Location>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>4000</ProductId>
<ModuleNumber>02</ModuleNumber>
<Location>Kolkata</Location>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Chennai</Location>
<StoreId>1234<StoreId>
</ProductResult>
</ProductResults>
如果您注意到,ProductId 1000重复三次。我应该编写XSLT来生成以下输出。
{
"StoreId": "1234",
"Locations": [
{
"ProductId": "1000",
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "02"
},
{
"Location": "Mumbai",
"ModuleNumber": "01"
},
{
"Location": "Chennai",
"ModuleNumber": "03"
}
]
},
{
"ProductId": "2000",
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "03"
}
]
},
{
"ProductId": "4000",
"Locations": [
{
"Location": "Kolkata",
"ModuleNumber": "02"
}
]
}
]
}
由于ProductId字段在重复,我不能直接使用foreach循环,这会为同一个ProductId创建额外的代码块。对此有何建议?。
提前致谢。
答案 0 :(得分:0)
以下XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"
version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:apply-templates select="@*|node()" />
</xsl:template>
<xsl:template match="@*|node()">
<xsl:variable name="uniqueProducts"
select="count(//ProductId[not(. = following::ProductId)])"/>
{
"StoreId": <xsl:value-of select="ProductResult/StoreId"/>,
"Locations": [
<xsl:for-each select="//ProductId[not(. = following::ProductId)]">
<xsl:sort select="."/>
{
"ProductId": "<xsl:value-of select="."/>,
"Locations": [
<xsl:call-template name="location">
<xsl:with-param name="productId" select="."/>
</xsl:call-template>
]
<xsl:if test="position() < $uniqueProducts">,</xsl:if>
</xsl:for-each>
]}
</xsl:template>
<xsl:template name="location">
<xsl:param name="productId"/>
<xsl:for-each select="//ProductResult[ProductId=$productId]">
{
"Location": "<xsl:value-of select="Location"/>",
"ModuleNumber": "<xsl:value-of select="ModuleNumber"/>"
}
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
应用于以下内容时(已更正,因为您未关闭示例中的StoreId
)
输入XML:
<ProductResults>
<ProductResult>
<ProductId>1000</ProductId>
<Location>Bangalore</Location>
<ModuleNumber>02</ModuleNumber>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>2000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Bangalore</Location>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>01</ModuleNumber>
<Location>Mumbai</Location>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>4000</ProductId>
<ModuleNumber>02</ModuleNumber>
<Location>Kolkata</Location>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Chennai</Location>
<StoreId>1234</StoreId>
</ProductResult>
</ProductResults>
产生以下
输出XML:
{
"StoreId": 1234,
"Locations": [
{
"ProductId": "1000,
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "02"
}
,
{
"Location": "Mumbai",
"ModuleNumber": "01"
}
,
{
"Location": "Chennai",
"ModuleNumber": "03"
}
]
,
{
"ProductId": "2000,
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "03"
}
]
,
{
"ProductId": "4000,
"Locations": [
{
"Location": "Kolkata",
"ModuleNumber": "02"
}
]
]}
请注意,这只是分组的一个示例,例如一个额外的for-each循环可以调整它以照顾多个StoreId
为简化起见,我刚刚为使用StoreId
提供的<xsl:value-of select="ProductResult/StoreId"/>
编写此内容,而不是检查不同的StoreId
值并处理所有这些值。
有关详细参考,您可以查看Jeni Tennison http://www.jenitennison.com/xslt/grouping/muenchian.xml关于Muenchian Grouping的文章,以及 你可以,例如看一下http://www.dpawson.co.uk/xsl/sect2/N4486.html的XSLT分组。
更新:刚刚调整了首次发布的XSLT,并说明了其工作原理 - <xsl:for-each select="//ProductId[not(. = following::ProductId)]">
循环处理所有唯一ProductId
值,并调用<xsl:template name="location">
当前ProductId
作为参数,并为与ProductId
匹配的每个位置生成输出。虽然更新的方法不使用Muenchian分组,但它可能仍然对您有价值所以我会保留参考。