使用XSLT为XML的ComponentDetails标签添加ID并保留子标签
解决XML中为标签添加ID属性且保留子标签的问题
我来帮你梳理这个问题的解决过程——你想要给XML里所有<ComponentDetails>标签添加ID属性,方便后续通过ID定位到对应的Amount和YTDAmount值,但最初的XSLT虽然成功添加了ID,却意外丢失了子标签内容,调整模板匹配路径后就完美解决了这个问题。
示例XML结构
<?xml version="1.0" encoding="UTF-8"?> <root> <PayrunDetails> <PayrunNumber>000777</PayrunNumber> <PaidDate>2018-05-15</PaidDate> </PayrunDetails> <PayLocation> <LocationCode>ACT</LocationCode> <LocationDescription>ACT</LocationDescription> <CompanyDetails> <CCode>APPLE</CCode> <CName>APPLE Limited</CName> <Payslip> <StaffNumber>12345</StaffNumber> <BankDetails> <BankAccountNo>121212</BankAccountNo> </BankDetails> <PayDetails> <PayType>NORMAL</PayType> <AmountGross>9999</AmountGross> <ComponentDetails> <ComponentType>SALARY</ComponentType> <Amount>1999</Amount> <YTDAmount>10616</YTDAmount> </ComponentDetails> <ComponentDetails> <ComponentType>TAXABLE</ComponentType> <Amount>505</Amount> <YTDAmount>7703</YTDAmount> </ComponentDetails> </PayDetails> </Payslip> <Payslip> <StaffNumber>45555</StaffNumber> <BankDetails> <BankAccountNo>131313</BankAccountNo> </BankDetails> <PayDetails> <PayType>NORMAL</PayType> <AmountGross>9999</AmountGross> <ComponentDetails> <ComponentType>SALARY</ComponentType> <Amount>1999</Amount> <YTDAmount>10616</YTDAmount> </ComponentDetails> <ComponentDetails> <ComponentType>GROSS</ComponentType> <Amount>7305</Amount> <YTDAmount>76703</YTDAmount> </ComponentDetails> <ComponentDetails> <ComponentType>TAXABLE</ComponentType> <Amount>305</Amount> <YTDAmount>6703</YTDAmount> </ComponentDetails> </PayDetails> </Payslip> </CompanyDetails> </PayLocation> </root>
初始XSLT(存在子标签丢失问题)
这段代码尝试给所有<ComponentDetails>添加ID,但运行后会丢失子标签内容:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="ComponentDetails"> <xsl:copy> <xsl:attribute name="ID"> <xsl:number/> </xsl:attribute> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> </xsl:stylesheet>
修正后的可用XSLT
调整匹配路径为更具体的PayDetails/ComponentDetails,并优化模板顺序后,既能成功添加ID,又完整保留了所有子标签:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> <xsl:output method="xml" indent="yes"/> <xsl:template match="PayDetails/ComponentDetails"> <xsl:copy> <xsl:attribute name="ID"> <xsl:number/> </xsl:attribute> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
关键调整说明
- 更精准的匹配路径:将模板匹配从通用的
ComponentDetails改为PayDetails/ComponentDetails,确保只处理目标层级下的标签,避免意外影响其他位置的同名标签(如果有的话)。 - 模板顺序优化:把针对
<ComponentDetails>的具体模板放在通用复制模板前面,让XSLT优先执行具体匹配,保证ID属性被正确添加后,再通过通用模板处理所有子标签和属性,从而完整保留原有内容。
现在你可以通过类似//ComponentDetails[@ID='1']/Amount的XPath表达式,快速定位到对应ID标签下的Amount或YTDAmount值了。
内容的提问来源于stack exchange,提问作者venus
相关产品推荐
相关产品推荐

