使用XSLT将XML转CSV时处理传递依赖的技术求助
用XSLT实现XML到CSV转换并筛选特定关联Party
首先先确认下你提供的XML里relation节点的hid属性可能存在笔误(比如H100应该是H_100,才能和hold的id对应上),我先修正后展示你的源XML:
<root> <hold id="H_100"> <value1>A</value1> </hold> <hold id="H_200"> <value1>B</value1> </hold> <hold id="H_300"> <value1>C</value1> </hold> <party id="C_100"> <value2>D</value2> </party> <party id="C_200"> <value2>E</value2> </party> <party id="C_300"> <value2>F</value2> </party> <party id="A_100"> <value2>G</value2> </party> <party id="A_300"> <value2>H</value2> </party> <relation hid="H_100" pid="C_100"/> <relation hid="H_100" pid="A_100"/> <relation hid="H_200" pid="C_200"/> <relation hid="H_300" pid="A_300"/> </root>
你的期望CSV输出是:
Hold,Party A,G B, C,H
下面是实现这个需求的XSLT代码,我会一步步解释它的逻辑:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="UTF-8"/> <!-- 建立索引:通过party的id快速定位对应的节点,避免重复遍历 --> <xsl:key name="party-by-id" match="party" use="@id"/> <!-- 建立索引:通过hold的id快速找到所有关联的relation --> <xsl:key name="relations-by-hid" match="relation" use="@hid"/> <xsl:template match="/root"> <!-- 先输出CSV表头 --> <xsl:text>Hold,Party </xsl:text> <!-- 遍历每个hold节点,生成一行CSV记录 --> <xsl:for-each select="hold"> <!-- 输出当前hold的value1值 --> <xsl:value-of select="value1"/> <xsl:text>,</xsl:text> <!-- 筛选当前hold关联的、pid以A_开头的relation --> <xsl:variable name="matching-a-relations" select="key('relations-by-hid', @id)[starts-with(@pid, 'A_')]"/> <!-- 如果找到匹配的relation,取出对应的party的value2;否则输出空 --> <xsl:choose> <xsl:when test="$matching-a-relations"> <xsl:value-of select="key('party-by-id', $matching-a-relations/@pid)/value2"/> </xsl:when> <xsl:otherwise> <xsl:text></xsl:text> </xsl:otherwise> </xsl:choose> <!-- 换行,生成下一条记录 --> <xsl:text> </xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
代码逻辑说明:
- 索引优化:用
xsl:key建立两个索引,分别用来快速查找party和关联的relation,这样比嵌套循环遍历要高效得多,尤其是当XML数据量较大时。 - 表头输出:先输出CSV的第一行表头,用
表示换行(兼容大多数操作系统的换行格式)。 - 遍历hold节点:逐个处理每个hold,先输出它的
value1,然后输出逗号分隔符。 - 筛选特定Party:通过
key('relations-by-hid', @id)找到当前hold的所有关联relation,再用starts-with(@pid, 'A_')过滤出pid以A_开头的那些。 - 处理空值场景:如果当前hold没有匹配的A类Party,就输出空字符串,保证CSV的格式不会混乱。
- 换行处理:每个hold处理完成后输出换行符,确保每条记录单独占一行。
如果你的实际XML里relation的hid属性本来就是正确的(和hold的id一致),直接用这段代码就可以得到你想要的CSV输出啦。
内容的提问来源于stack exchange,提问作者Aniruddha P
相关产品推荐
相关产品推荐

