将 xml 转换为 cvs

Transform xml to cvs

我开发了通过 xsl 将 xml 转换为 cvs 的应用程序。我使用了 DOM API,但它的性能很差(在输入中我有 100000 xml 大小为 200kb-20mb)我尝试使用 SAX API,但我收到错误的结果转换后的输出。 Dom api:

@PostConstruct
public void init() throws ParserConfigurationException, TransformerConfigurationException {
    styleSheet = new File("1.xsl");
    builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    stylesource = new StreamSource(styleSheet);
    transformer = TransformerFactory.newInstance().newTransformer(stylesource);
}

public String transformXmlToCsv(String inputXml) {
    String csv = null;

    try {
        InputSource is = new InputSource(new StringReader(inputXml));

        Document document = builder.parse(is);

        StringWriter writer = new StringWriter();

        transformer.transform(new DOMSource(document), new StreamResult(writer));
        csv = writer.toString();
        writer.close();
    } catch (Exception e) {
        LOGGER.error("Exception during transorming", e);
    }
    return csv;
}

}

SAX API:

 public static void main(String[] args) throws Exception {
    TransformerFactory transFact = TransformerFactory.newInstance( );
    File xml = new File("019dc124-5057-43f3-aa5d-1d840536b1b5-1558467374000.xml");
    File styleSheet = new File("1.xsl");
    Result outputTarget = new StreamResult(new File("C:\proj\xmlparser\result.csv"));
    Source stylesource = new StreamSource(styleSheet);
    Transformer trans = transFact.newTransformer(stylesource);
    InputSource is = new InputSource(new FileReader(xml));   
    Source xmlSource = new SAXSource(is);
    trans.transform(xmlSource, outputTarget);       
}

如果性能是您的问题,那么不要为您正在转换的每个文件创建新的 TransformerFactoryDocumentBuilderFactory 等。实例化这些 JAXP 工厂 类 是出了名的昂贵,因为它涉及搜索类路径。您没有说文件的大小,但是如果您正在解析数十万个非常小的 XML 文件,那么性能的关键是重用同一个解析器; DOM-vs-SAX 的差异可以忽略不计。

我认为您可能只是 运行 成为关于正确使用 XSLT 到名称空间中的 select 元素的最常见问题的变体,我认为默认的 Java DocumentBuilder不识别名称空间,因此您的 XSLT 代码可能会将默认名称空间中的元素视为不在任何名称空间中,这样您的路径 root/rootnode/name 就可以工作。另一方面,使用 Sax,我认为 XSLT 处理器将看到您所说的默认命名空间中的元素,然后您的路径不再起作用,因为它们 select 没有命名空间中的元素。

要解决此问题,有两种方法:通过将 Saxon 9 HE(最新版本为 9.9)放在类路径中切换到 XSLT 2/3,然后使用例如xpath-default-namespace="http://example.com/ns" 作为 xsl:stylesheetxsl:transform 根元素的属性。

或者,如果您坚持使用 XSLT 1,唯一的解决方法是在样式表中为该命名空间(例如 http://example.com/ns)声明一个前缀(例如 pf1),例如xmlns:pf1="http://example.com/ns" 然后更改所有 XPath 表达式和匹配模式以使用前缀,因此 root/rootnode/name 变为 pf1:object/pf1:rootnode/pf1:name.