如何使用Saxon XSLT将多节点XML转换为CSV字符串?
使用Saxon XSLT将XML转换为CSV字符串的完整实现
我最近在折腾用Saxon把包含多个员工节点的XML转成CSV格式的字符串,环境已经搭好了,但卡在了实际转换的步骤上——尤其是XML里的employee内部元素顺序还可能不固定,得保证数据提取准确。下面是我整理的完整解决方案,包含正确的XSLT编写和Java代码完善:
待转换的XML示例
<employees stage="test"> <employee> <details> <name>Joe</name> <age>34</age> </details> <address> <street>test</street> <nr>12</nr> </address> </employee> <employee> <address> <street>main</street> <nr>45</nr> </address> <details> <!-- 注意元素顺序已更改! --> <age>24</age> <name>Sam</name> </details> </employee> </employees>
编写正确的XSLT转换规则
因为XML里的name和age嵌套在details节点下,street和nr在address节点下,还要提取根节点的stage属性,同时要处理换行和逗号分隔。这里用XSLT 3.0实现,不管employee内部子节点顺序都能正确提取数据:
<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 输出纯文本,省略XML声明 --> <xsl:output method="text" omit-xml-declaration="yes"/> <!-- 匹配根节点,遍历所有employee --> <xsl:template match="/employees"> <!-- 可选:如果需要表头可以放开下面这行 --> <!-- <xsl:text>stage,name,age,street,nr </xsl:text> --> <xsl:apply-templates select="employee"/> </xsl:template> <!-- 匹配单个employee节点,拼接CSV行 --> <xsl:template match="employee"> <!-- 提取根节点的stage属性 --> <xsl:value-of select="../@stage"/> <xsl:text>,</xsl:text> <!-- 提取details中的name(不管内部顺序) --> <xsl:value-of select="details/name"/> <xsl:text>,</xsl:text> <!-- 提取details中的age --> <xsl:value-of select="details/age"/> <xsl:text>,</xsl:text> <!-- 提取address中的street --> <xsl:value-of select="address/street"/> <xsl:text>,</xsl:text> <!-- 提取address中的nr,最后加换行符 --> <xsl:value-of select="address/nr"/> <xsl:text> </xsl:text> </xsl:template> </xsl:transform>
说明:通过明确的节点路径提取数据,即使details内部的name和age顺序调换,也不会影响结果;如果某个节点缺失,会自动输出空值(保留逗号),符合CSV格式规范。
完善Saxon Java代码
原来的代码只完成了环境初始化,缺少核心的转换执行和结果获取步骤,下面是完整可运行的代码:
import net.sf.saxon.Processor; import net.sf.saxon.s9api.*; import java.io.StringWriter; public class SaxonXmlToCsv { public static void main(String[] args) throws SaxonApiException { // 初始化Saxon处理器,false表示无需商业版功能 Processor processor = new Processor(false); XsltCompiler compiler = processor.newXsltCompiler(); // 编译指定的XSLT文件 XsltExecutable executable = compiler.compile(new StreamSource("transformation.xslt")); // 创建XSLT转换执行器 XsltTransformer transformer = executable.load(); // 设置待转换的XML源文件路径 transformer.setSource(new StreamSource("employees.xml")); // 创建StringWriter接收转换后的CSV字符串 StringWriter writer = new StringWriter(); Serializer serializer = processor.newSerializer(writer); // 配置序列化属性:避免XML声明、设置UTF-8编码防乱码 serializer.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes"); serializer.setOutputProperty(Serializer.Property.ENCODING, "UTF-8"); // 关联转换器与序列化器,执行转换 transformer.setDestination(serializer); transformer.transform(); // 获取最终的CSV字符串结果 String result = writer.toString(); System.out.println(result); } }
关键步骤拆解:
- 编译XSLT后创建
XsltTransformer实例,负责执行转换逻辑 - 用
StringWriter作为输出目标,直接将转换结果转为字符串 - 关联转换器与序列化器后调用
transform(),完成整个转换流程
转换结果验证
运行代码后,得到的result字符串为:
test,Joe,34,test,12 test,Sam,24,main,45
完全符合预期的CSV格式,每个employee对应一行,逗号分隔字段,换行符分隔行。
内容的提问来源于stack exchange,提问作者membersound
相关产品推荐
相关产品推荐

