鉴于此数据:
<?xml version='1.0' encoding='utf-8'?>
<data>
<pricePoint>
<optionGroup id='g1'>
<option id='a1'>a1</option>
<option id='a2'>a2</option>
</optionGroup>
<optionGroup id='g2'>
<option id='b1'>b1</option>
<option id='b2'>b2</option>
</optionGroup>
<optionGroup id='g3'>
<option id='c1'>c1</option>
<option id='c2'>c2</option>
</optionGroup>
</pricePoint>
</data>
我正在寻找的结果是:
<result>
<variant>
<option id='a1'>a1</option>
<option id='b1'>b1</option>
<option id='c1'>c1</option>
</variant>
<variant>
<option id='a1'>a1</option>
<option id='b1'>b1</option>
<option id='c2'>c2</option>
</variant>
<variant>
<option id='a1'>a1</option>
<option id='b2'>b2</option>
<option id='c1'>c1</option>
</variant>
<variant>
<option id='a1'>a1</option>
<option id='b2'>b2</option>
<option id='c2'>c2</option>
</variant>
<variant>
<option id='a2'>a2</option>
<option id='b1'>b1</option>
<option id='c1'>c1</option>
</variant>
<variant>
<option id='a2'>a2</option>
<option id='b1'>b1</option>
<option id='c2'>c2</option>
</variant>
<variant>
<option id='a2'>a2</option>
<option id='b2'>b2</option>
<option id='c1'>c1</option>
</variant>
<variant>
<option id='a2'>a2</option>
<option id='b2'>b2</option>
<option id='c2'>c2</option>
</variant>
</result>
即,
<optionGroup>
。<option>
,遍历所有其他<optionGroup>
并将“{1}}与”当前“一起”加入“ - 在结果文档中生成包含所有这些<option>
的单个元素。任何<option>
元素中<optionGroup>
元素的数量未知(一个或多个),任何<pricePoint>
元素中的<option>
元素数量也是未知的(一个或多个)。
据我所知,这是制作笛卡尔产品的经典案例,但我对如何使用XSLT 1.0正确实现这一点缺乏想法。
到目前为止,我的(相当无助的)尝试围绕着应用模板匹配<optionGroup>
元素的想法,同时处理其中一个元素并尝试将其排除在进一步处理之外,如下所示:
<optionGroup>
当然,在应用模板时,我迄今为止的所有尝试都失败了,无法递归。
答案 0 :(得分:3)
这是一种方法,虽然我不确定它的效率,因为它必须重复创建以前节点的副本。
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="pricePoint">
<xsl:apply-templates select="optionGroup[1]/option" />
</xsl:template>
<xsl:template match="optionGroup[following-sibling::*]/option">
<xsl:param name="previous" />
<xsl:apply-templates select="../following-sibling::optionGroup[1]/option">
<xsl:with-param name="previous">
<xsl:if test="$previous">
<xsl:copy-of select="$previous" />
</xsl:if>
<xsl:copy-of select="." />
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="option">
<xsl:param name="previous" />
<variant>
<xsl:copy-of select="$previous" />
<xsl:copy-of select="." />
</variant>
</xsl:template>
</xsl:stylesheet>
首先选择第一个option
下的optionGroup
元素,然后递归调用下一个组中option
个元素的模板,并将option
作为一个参数,允许它建立一个以前的option
元素列表。
当谈到最后option
下的optionGroup
元素时,它可以输出所有以前的元素以及当前的元素。
编辑:回应Martin Honnen的评论,这是一种稍微改进的方式,不依赖于传递的副本
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="pricePoint">
<xsl:apply-templates select="optionGroup[1]/option" />
</xsl:template>
<xsl:template match="optionGroup[following-sibling::*]/option">
<xsl:param name="previous" select="/.." />
<xsl:apply-templates select="../following-sibling::optionGroup[1]/option">
<xsl:with-param name="previous" select="$previous | ." />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="option">
<xsl:param name="previous" />
<variant>
<xsl:copy-of select="$previous" />
<xsl:copy-of select="." />
</variant>
</xsl:template>
</xsl:stylesheet>