【问题标题】:Transform xml to cvs将 xml 转换为 csv
【发布时间】:2019-12-27 09:58:49
【问题描述】:

我开发了通过 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);       
}

【问题讨论】:

  • 您需要准确解释问题所在,即第一个样本得到的结果以及第二个结果有何不同,以及您得到的任何确切错误。
  • @MartinHonnen 已编辑,成功运行没有错误
  • 显示您的 XSL 文件。
  • @mentallurg 增加了 xsl 的短版本
  • 很难从截图中看出哪里出了问题,但如果不需要的缩进/空白是问题,那么您通常可以使用例如修复它。 <xsl:text>Case</xsl:text> 在模板中显式输出文字。

标签: java xml xslt sax


【解决方案1】:

我认为您可能只是遇到了有关正确使用 XSLT 选择命名空间中的元素的最常见问题的变体,我认为默认的 Java DocumentBuilder 不支持命名空间,因此您的 XSLT 代码可能会在默认情况下看到元素命名空间为没有命名空间,以便您的路径像root/rootnode/name 工作。另一方面,使用 Sax,我认为 XSLT 处理器会看到您所说的默认命名空间中的元素,然后您的路径不再起作用,因为它们选择了没有命名空间中的元素。

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • xml 大小不同(200kb-20mb)。我已经在重用解析器(编辑了第一条消息)。好的,我怎样才能提高性能?
    • 在性能方面,魔鬼总是在细节中。您首先需要告诉我们您正在实现的绩效数字以及这些数字如何不符合您的业务需求。也许你已经做得尽可能好。也许您需要重新考虑整个流程/工作流程:如果我是以顾问的身份进来的,我会问您为什么要将所有这些 XML 转换为 CSV,您可以用 CSV 做什么而不能用 XML 做什么?但这使得 StackOverflow 的问题过于宽泛。
    • 转换 100000 xml 需要 1 小时。我可以将 Cvs 发送到 Postgres dB 并保存到表中,而使用 xml 我无法做到这一点。在星期一,我正在尝试使用 sax api 并查看花费了多少时间。我必须在 20 分钟内处理 100000 个 xml。
    • 我通常认为每分钟 1Gb 是处理 XML 的合理速度;如果您在 1 小时内处理 100K * 1Mb 文档,则符合该目标(100Gb/小时)。如果你想加快速度,剪掉中间的 CSV 形式:编写一个读取 XML 并使用 JDBC 直接写入数据库的 Java 应用程序。
    • 另请注意,Saxon(-PE 和更高版本)提供了一个扩展,允许您从 XSLT 代码直接写入数据库(请参阅saxonica.com/documentation/index.html#!sql-extension)我不保证相对于您当前的代码,但值得做一个实验。
    猜你喜欢
    • 2013-06-20
    • 2013-10-04
    • 2017-09-09
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    • 2019-02-02
    • 1970-01-01
    相关资源
    最近更新 更多