求助:使用XSLT将同级节点XML转换为父子分组结构
处理同级Result_HEADER与交易节点的XSLT方案
嘿,刚上手XSLT碰到这种节点布局确实有点挠头——明明是一组的节点却被放在同级,没关系,咱们用XSLT的节点轴和模板匹配就能轻松把它们归拢到一起。
首先得明确咱们的目标:把每个Result_HEADER和它对应的Result_Y、Result_Addendum(紧跟在Header后面的同级节点)包装成一个逻辑上的交易组,让结构更清晰。
第一步:处理命名空间
你的原始XML带有默认命名空间http://peak.company.com,所以XSLT里必须正确声明这个命名空间,不然根本匹配不到节点。咱们可以用xpath-default-namespace属性来简化操作,不用给每个节点加前缀。
完整XSLT代码示例
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://peak.company.com"> <!-- 匹配根节点,初始化输出结构 --> <xsl:template match="/Peak"> <Peak> <xsl:copy-of select="OffTime"/> <!-- 保留原有的OffTime节点 --> <!-- 遍历所有Result_HEADER节点,每个Header对应一组交易数据 --> <xsl:for-each select="Result_HEADER"> <Transaction> <!-- 复制当前Header节点 --> <xsl:copy-of select="."/> <!-- 获取紧跟在当前Header后面的第一个Result_Y节点 --> <xsl:copy-of select="following-sibling::Result_Y[1]"/> <!-- 获取紧跟在当前Header后面的第一个Result_Addendum节点 --> <xsl:copy-of select="following-sibling::Result_Addendum[1]"/> </Transaction> </xsl:for-each> </Peak> </xsl:template> <!-- 匹配其他未处理的节点,默认复制(如果需要保留其他节点的话) --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
代码关键点解释
xpath-default-namespace="http://peak.company.com":告诉XSLT,所有不带前缀的XPath表达式默认使用这个命名空间,不用每次写prefix:Result_HEADER这种繁琐形式。following-sibling::Result_Y[1]:使用following-sibling轴获取当前节点后面的同级节点,[1]确保只取第一个匹配的Result_Y,刚好对应当前Header的交易详情。<Transaction>:咱们自定义的包装节点,把一组Header和交易节点归在一起,让输出结构更符合逻辑。
转换后的示例输出
假设原始XML是:
<?xml version="1.0" encoding="UTF-8"?> <Peak xmlns="http://peak.company.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <OffTime>2024-05-20</OffTime> <Result_HEADER> <Suffix>001</Suffix> <Status>Success</Status> </Result_HEADER> <Result_Y> <Amount>100.00</Amount> <Date>2024-05-20</Date> </Result_Y> <Result_Addendum> <Note>First transaction</Note> </Result_Addendum> <Result_HEADER> <Suffix>002</Suffix> <Status>Success</Status> </Result_HEADER> <Result_Y> <Amount>200.00</Amount> <Date>2024-05-21</Date> </Result_Y> <Result_Addendum> <Note>Second transaction</Note> </Result_Addendum> </Peak>
转换后会变成:
<?xml version="1.0" encoding="UTF-8"?> <Peak xmlns="http://peak.company.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <OffTime>2024-05-20</OffTime> <Transaction> <Result_HEADER> <Suffix>001</Suffix> <Status>Success</Status> </Result_HEADER> <Result_Y> <Amount>100.00</Amount> <Date>2024-05-20</Date> </Result_Y> <Result_Addendum> <Note>First transaction</Note> </Result_Addendum> </Transaction> <Transaction> <Result_HEADER> <Suffix>002</Suffix> <Status>Success</Status> </Result_HEADER> <Result_Y> <Amount>200.00</Amount> <Date>2024-05-21</Date> </Result_Y> <Result_Addendum> <Note>Second transaction</Note> </Result_Addendum> </Transaction> </Peak>
如果你的实际场景里每个Header对应多个交易节点,还可以调整following-sibling的匹配条件,比如用following-sibling::Result_Y[preceding-sibling::Result_HEADER[1] = current()]来精准绑定属于当前Header的所有交易节点,不过从你的描述来看,一对一的场景用上面的代码就完全够用啦。
内容的提问来源于stack exchange,提问作者Phil B.
相关产品推荐
相关产品推荐

