XSL 1.0实现将多个属性值合并到单个属性中:页面序列合并异常问题求助
问题排查与修复:XSLT循环合并页面属性值不符合预期
问题背景
你现在遇到的问题是:用XSLT处理XML时,想给每个Product生成对应的组件,并把该Product下的Page的Number属性合并成空格分隔的字符串,但结果却把所有页面都合并到每个组件里了。
先回顾下你的输入XML:
<?xml version="1.0" encoding="UTF-8"?> <Project> <ProductPool> <Product Type="A"> <PagePool> <Page Number="1"/> <Page Number="2"/> </PagePool> </Product> <Product Type="B"> <PagePool> <Page Number="1"/> <Page Number="2"/> </PagePool> </Product> </ProductPool> </Project>
期望输出是每个组件只对应自身Product下的页面:
<?xml version="1.0" encoding="UTF-8"?> <Project> <UnboundComponent PageSequence="1 2"/> <BoundComponent PageSequence="1 2"/> </Project>
但当前你的XSLT输出的两个组件PageSequence都是1 2 1 2,显然不符合预期。
错误原因分析
问题出在你内部的xsl:for-each路径上:
<xsl:for-each select="/Project/ProductPool/Product/PagePool/Page">
这里用的是绝对路径,意味着每次循环都会遍历整个XML里所有Product下的Page元素,完全忽略了当前正在处理的Product上下文。所以每个组件都会把所有页面的Number都拼起来,导致结果重复叠加。
你需要切换为相对路径,基于当前处理的Product元素来选择它下面的Page节点。
正确的XSLT实现方案
修改内部的for-each路径,同时优化空格处理(避免最后多一个多余的空格):
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <Project> <xsl:for-each select="//Product"> <xsl:variable name="elem-name"> <xsl:choose> <xsl:when test='@Type="B"'>BoundComponent</xsl:when> <xsl:otherwise>UnboundComponent</xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:element name="{$elem-name}"> <xsl:attribute name="PageSequence"> <xsl:for-each select="PagePool/Page"> <!-- 除第一个元素外,在前面添加空格,避免末尾多余空格 --> <xsl:if test="position() > 1"> <xsl:text> </xsl:text> </xsl:if> <xsl:value-of select="@Number"/> </xsl:for-each> </xsl:attribute> </xsl:element> </xsl:for-each> </Project> </xsl:template> </xsl:stylesheet>
关键修改点
- 将内部
for-each的路径从绝对路径改为PagePool/Page,这样只会选择当前Product节点下的Page元素 - 添加了
<xsl:if test="position() > 1">来控制空格输出,确保只有在非第一个元素前才添加空格,避免出现末尾多余空格的情况
验证结果
用这个XSLT处理你的输入XML,就能得到你期望的输出,每个组件的PageSequence只对应自身Product下的页面编号。
内容的提问来源于stack exchange,提问作者Bronko
相关产品推荐
相关产品推荐

