XSLT 1.0按产品、账单分组生成重复表格时子上下文取值失效问题
XSLT 多分组遍历问题解决
问题背景
所用XML结构
<root> <Products name="product01"> <Instruments name="ins01"/> <Instruments name="ins02"/> <Instruments name="ins01"/> </Products> <Products name="product02"> <Instruments name="random text A"> <Bill name="A"/> </Instruments> <Instruments name="random text B and C"> <Bill name="B"> <Notes>some text</Notes> </Bill> <Bill name="C"> <Notes>some text</Notes> </Bill> </Instruments> <Instruments name="random text A and B"> <Bill name="A"> <Notes>some text</Notes> </Bill> <Bill name="B"> <Notes>some text</Notes> </Bill> </Instruments> <Instruments name="random text B"> <Bill name="B"> <Notes>some text</Notes> </Bill> </Instruments> <Instruments name="random text C"> <Bill name="C"> <Notes>some text</Notes> </Bill> </Instruments> <Instruments name="random text C and A"> <Bill name="C"> <Notes>some text</Notes> </Bill> <Bill name="A"> <Notes>some text</Notes> </Bill> </Instruments> </Products> </root>
需求
先按Products节点分组,再在组内按Bill的name属性分组,表格左列展示账单类型,右列展示该账单类型对应分组下所有关联的Instruments名称,预期输出示例:
product02 Bill Type: A random text A random text A and B random text C and A Bill Type: B random text B and C random text A and B random text B Bill Type: C random text B and C random text C random text C and A
原有模板问题
原有模板中定义的分组key是正确的,但右列遍历逻辑错误,无法取出对应账单类型下的所有Instruments名称。
修正方案
你定义的groupBilling已经实现了「产品名+账单名」的组合分组,在遍历到每个唯一账单分组节点时,直接用key函数取出同组所有Bill节点,再取其父节点Instruments的name属性即可。
只需将原有右表列的遍历逻辑:
<xsl:for-each select="../."> <fo:table-row> <fo:table-cell> <fo:block> <xsl:value-of select="@name" /> </fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each>
替换为:
<xsl:for-each select="key('groupBilling', concat(../../@name, @name))"> <fo:table-row> <fo:table-cell> <fo:block> <xsl:value-of select="../@name" /> </fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each>
完整修正后模板代码
<xsl:key name="groupProducts" match="/root/Products/Instruments/Bill" use="../../@name" /> <xsl:key name="groupBilling" match="/root/Products/Instruments/Bill" use="concat(../../@name,@name)" /> <xsl:template name="myTemplate"> <fo:block> <fo:table> <fo:table-column column-width="proportional-column-width(1)" /> <fo:table-body> <xsl:for-each select="/root/Products/Instruments/Bill[generate-id(.) = generate-id(key('groupProducts',../../@name)[1])]"> <fo:table-row> <fo:table-cell> <fo:block font-weight="bold" margin-top="4pt"> <xsl:value-of select="../../@name" /> </fo:block> <fo:block> <fo:table> <fo:table-column column-width="50.000" column-number="1" /> <fo:table-column column-width="50.000" column-number="2" /> <fo:table-body> <xsl:for-each select="/root/Products/Instruments/Bill[generate-id(.) = generate-id(key('groupBilling',concat(current()/../../@name,@name))[1])]"> <fo:table-row> <fo:table-cell> <fo:block color="blue"> Bill Type: <xsl:value-of select="@name" /></fo:block> <fo:block /> </fo:table-cell> <fo:table-cell> <fo:block> <fo:table> <fo:table-column column-width="proportional-column-width(1)" /> <fo:table-body> <!-- 修正后的遍历逻辑 --> <xsl:for-each select="key('groupBilling', concat(../../@name, @name))"> <fo:table-row> <fo:table-cell> <fo:block> <xsl:value-of select="../@name" /> </fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> </fo:table-body> </fo:table> </fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> </fo:table-body> </fo:table> </fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> </fo:table-body> </fo:table> </fo:block> </xsl:template>
内容的提问来源于stack exchange,提问作者iwasaki
相关产品推荐
相关产品推荐

