XSLT 1.0:合并重复元素对应子元素及多文件输出需求
解决方案:XML转双CSV文件(流式输出)或合并式CSV
我来帮你搞定这个XML转CSV的需求,尤其是嵌套MatchingSubRecords的处理,先给你优先要的流式双文件方案,再补充合并到主CSV的备选方案。
一、优先方案:流式输出两个独立CSV文件
这个方案用XSLT结合exsl:document扩展,配合.NET的XslCompiledTransform实现流式写入主记录和子记录两个文件,方便后续关联分析,大XML文件也能高效处理。
1. 实现XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"> <xsl:output method="text" encoding="UTF-8" /> <!-- 主输出:主记录CSV --> <xsl:template match="/Root"> <!-- 写入主CSV表头 --> <xsl:text>Field1,Field2 </xsl:text> <xsl:apply-templates select="Record" /> <!-- 生成子记录CSV文件 --> <exsl:document href="sub_records.csv" method="text" encoding="UTF-8"> <!-- 子CSV表头(带父级关联字段) --> <xsl:text>ParentField1,ParentField2,SubField1,SubField2 </xsl:text> <xsl:apply-templates select="Record/MatchingSubRecords" mode="sub" /> </exsl:document> </xsl:template> <!-- 处理主Record行 --> <xsl:template match="Record"> <xsl:value-of select="Field1" /> <xsl:text>,</xsl:text> <xsl:value-of select="Field2" /> <xsl:text> </xsl:text> </xsl:template> <!-- 处理子记录,携带父级关联信息 --> <xsl:template match="MatchingSubRecords" mode="sub"> <xsl:value-of select="../Field1" /> <xsl:text>,</xsl:text> <xsl:value-of select="../Field2" /> <xsl:text>,</xsl:text> <xsl:value-of select="SubField1" /> <xsl:text>,</xsl:text> <xsl:value-of select="SubField2" /> <xsl:text> </xsl:text> </xsl:template> </xsl:stylesheet>
2. 用C#的XslCompiledTransform执行
using System; using System.Xml; using System.Xml.Xsl; class Program { static void Main() { XslCompiledTransform transform = new XslCompiledTransform(); // 加载你的XSLT文件 transform.Load("transform.xslt"); // 启用扩展函数支持(exsl:document需要这个设置) XsltSettings settings = new XsltSettings(true, true); // 执行转换,主输出到main_records.csv,子输出由XSLT自动生成sub_records.csv using (XmlWriter writer = XmlWriter.Create("main_records.csv")) { transform.Transform("input.xml", settings, writer); } Console.WriteLine("转换完成,已生成main_records.csv和sub_records.csv"); } }
这个方案的优势是流式处理,无需把整个XML加载到内存,两个文件用父级字段关联,后续做数据分析也更灵活。
二、备选方案:合并子记录到主CSV
如果不需要分开文件,也可以把所有子字段合并到主CSV的一个字段里,完全匹配你给出的示例格式:ABC, DEF, "SUB01,SUB11,SUB21|SUB02,SUB12,SUB22"
1. 合并版XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="UTF-8" /> <xsl:template match="/Root"> <!-- 主CSV表头 --> <xsl:text>Field1,Field2,MatchingSubRecords </xsl:text> <xsl:apply-templates select="Record" /> </xsl:template> <xsl:template match="Record"> <!-- 输出主字段 --> <xsl:value-of select="Field1" /> <xsl:text>,</xsl:text> <xsl:value-of select="Field2" /> <xsl:text>,"</xsl:text> <!-- 拼接所有SubField1的值 --> <xsl:for-each select="MatchingSubRecords"> <xsl:value-of select="SubField1" /> <xsl:if test="position() != last()"> <xsl:text>,</xsl:text> </xsl:if> </xsl:for-each> <xsl:text>|</xsl:text> <!-- 拼接所有SubField2的值 --> <xsl:for-each select="MatchingSubRecords"> <xsl:value-of select="SubField2" /> <xsl:if test="position() != last()"> <xsl:text>,</xsl:text> </xsl:if> </xsl:for-each> <xsl:text>" </xsl:text> </xsl:template> </xsl:stylesheet>
2. 执行方式
同样用XslCompiledTransform,只需要把输出指向单个文件即可,生成的CSV每行包含主字段和合并后的子记录字段,适合需要单文件的场景。
额外提示
如果你的字段内容包含逗号、引号等特殊字符,可以在XSLT里加个转义模板,比如把字段里的双引号替换成两个双引号,确保CSV格式合法。
内容的提问来源于stack exchange,提问作者Arvind S
相关产品推荐
相关产品推荐

