使用Java与XSL将XML和XSD转换为指定格式CSV文件
解决方案:结合XSD约束生成指定格式CSV
问题背景
已通过Java+XSL实现XML到CSV的转换,现需结合XSD中元素的*minOccurs*、*maxOccurs*约束,生成包含约束信息的特定结构CSV。尝试在XSL中导入XSD未成功,需可行方案。
现有代码及示例:
Java转换代码
public static void xmlToCSV() throws Exception{ File stylesheet = new File("style.xsl"); File xmlSource = new File("xmlData.xml"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(xmlSource); StreamSource stylesource = new StreamSource(stylesheet); Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource); Source source = new DOMSource(document); Result outputTarget = new StreamResult(new File("output.csv")); transformer.transform(source, outputTarget); }
原XSL文件(style.xsl)
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsl:template match="Person"> <xsl:value-of select="Name"/> <xsl:text>,</xsl:text> <xsl:value-of select="Gender"/> <xsl:text>,</xsl:text> <xsl:value-of select="Age"/> <xsl:text> </xsl:text> </xsl:template> </xsl:stylesheet>
源XML(xmlData.xml)
<?xml version="1.0" encoding="UTF-8"?> <Document> <Person> <Name>Bob</Name> <Gender>m</Gender> <Age>19</Age> </Person> </Document>
XSD约束片段
<xs:element maxOccurs="1" minOccurs="1" name="Name"> <xs:element maxOccurs="1" minOccurs="1" name="Gender"> <xs:element maxOccurs="1" minOccurs="0" name="Age">
期望输出CSV
name,min,max,value Bob,1,1,Name m,1,1,Gender 19,0,1,Age
实现方案
XSLT 1.0无法直接导入XSD并解析约束,但可以通过*document()*函数加载XSD文件,在处理XML元素时查询对应的约束属性。以下是具体步骤:
1. 修改XSL文件(style.xsl)
更新后的XSL会先输出CSV表头,然后遍历Person下的所有子元素,从XSD中匹配对应元素的*minOccurs*和*maxOccurs*值,按格式输出每行内容:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- 定义XSD文件路径,确保和XML文件同目录,或使用绝对路径 --> <xsl:variable name="xsdDoc" select="document('schema.xsd')"/> <!-- 匹配根节点,输出CSV表头 --> <xsl:template match="/"> <xsl:text>name,min,max,value </xsl:text> <xsl:apply-templates select="Document/Person/*"/> </xsl:template> <!-- 处理Person下的每个子元素 --> <xsl:template match="Person/*"> <!-- 获取当前元素的名称 --> <xsl:variable name="elemName" select="local-name()"/> <!-- 从XSD中查找对应元素的minOccurs和maxOccurs --> <xsl:variable name="xsdElem" select="$xsdDoc//xs:element[@name=$elemName]"/> <!-- 输出当前元素值、minOccurs、maxOccurs、元素名称 --> <xsl:value-of select="."/> <xsl:text>,</xsl:text> <xsl:value-of select="$xsdElem/@minOccurs"/> <xsl:text>,</xsl:text> <xsl:value-of select="$xsdElem/@maxOccurs"/> <xsl:text>,</xsl:text> <xsl:value-of select="$elemName"/> <xsl:text> </xsl:text> </xsl:template> </xsl:stylesheet>
2. 调整Java代码(可选)
如果XSD文件路径不是相对路径,或者遇到文件加载问题,可以给Transformer设置URIResolver来指定XSD的加载路径:
public static void xmlToCSV() throws Exception{ File stylesheet = new File("style.xsl"); File xmlSource = new File("xmlData.xml"); File xsdSource = new File("schema.xsd"); // 你的XSD文件 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(xmlSource); StreamSource stylesource = new StreamSource(stylesheet); TransformerFactory transformerFactory = TransformerFactory.newInstance(); // 设置URIResolver,确保XSL能正确加载XSD transformerFactory.setURIResolver(new URIResolver() { @Override public Source resolve(String href, String base) throws TransformerException { if ("schema.xsd".equals(href)) { return new StreamSource(xsdSource); } return null; } }); Transformer transformer = transformerFactory.newTransformer(stylesource); Source source = new DOMSource(document); Result outputTarget = new StreamResult(new File("output.csv")); transformer.transform(source, outputTarget); }
3. 注意事项
- 确保XSD文件的路径在XSL的
*document()*函数中能正确访问,建议将XSD、XML、XSL放在同一目录下。 - 如果XSD中有命名空间,需要在XSL中正确声明并调整XPath查询(比如
$xsdDoc//xs:element[@name=$elemName]可能需要加上命名空间前缀的匹配)。 - 若XSD中元素嵌套在复杂类型内,需要调整XPath表达式来定位到对应的
xs:element节点。
内容的提问来源于stack exchange,提问作者Akito The Duck
相关产品推荐
相关产品推荐

