使用Java将XML文件转换为CSV文件

18

我需要帮助理解使用Java将XML文件转换为CSV文件所涉及的步骤。以下是一个XML文件的示例:

<?xml version="1.0"?>
<Sites>
<Site id="101" name="NY-01" location="New York">
    <Hosts>
        <Host id="1001">
           <Host_Name>srv001001</Host_Name>
           <IP_address>10.1.2.3</IP_address>
           <OS>Windows</OS>
           <Load_avg_1min>1.3</Load_avg_1min>
           <Load_avg_5min>2.5</Load_avg_5min>
           <Load_avg_15min>1.2</Load_avg_15min>
        </Host>
        <Host id="1002">
           <Host_Name>srv001002</Host_Name>
           <IP_address>10.1.2.4</IP_address>
           <OS>Linux</OS>
           <Load_avg_1min>1.4</Load_avg_1min>
           <Load_avg_5min>2.5</Load_avg_5min>
           <Load_avg_15min>1.2</Load_avg_15min>
        </Host>
        <Host id="1003">
           <Host_Name>srv001003</Host_Name>
           <IP_address>10.1.2.5</IP_address>
           <OS>Linux</OS>
           <Load_avg_1min>3.3</Load_avg_1min>
           <Load_avg_5min>1.6</Load_avg_5min>
           <Load_avg_15min>1.8</Load_avg_15min>
        </Host>
        <Host id="1004">
           <Host_Name>srv001004</Host_Name>
           <IP_address>10.1.2.6</IP_address>
           <OS>Linux</OS>
           <Load_avg_1min>2.3</Load_avg_1min>
           <Load_avg_5min>4.5</Load_avg_5min>
           <Load_avg_15min>4.2</Load_avg_15min>
        </Host>     
    </Hosts>
</Site>
</Sites>

这是生成的CSV文件。

site_id, site_name, site_location, host_id, host_name, ip_address, operative_system, load_avg_1min, load_avg_5min, load_avg_15min
101, NY-01, New York, 1001, srv001001, 10.1.2.3, Windows, 1.3, 2.5, 1.2
101, NY-01, New York, 1002, srv001002, 10.1.2.4, Linux, 1.4, 2.5, 1.2
101, NY-01, New York, 1003, srv001003, 10.1.2.5, Linux, 3.3, 1.6, 1.8
101, NY-01, New York, 1004, srv001004, 10.1.2.6, Linux, 2.3, 4.5, 4.2

我考虑使用DOM解析器来读取XML文件。我遇到的问题是需要按名称在代码中指定特定元素,但我希望能够在不这样做的情况下解析它。

有没有Java中的工具或库可以帮助我实现这一点。

如果我有以下格式的XML文件,并且想要将InitgPty的值添加到与MSgId相同的行中(请注意:InitgPty在下一个标签级别中,因此它会在下一行打印值)

<?xml version="1.0"?>
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>XYZ07/ABC</MsgId>
<NbOfTxs>100000</NbOfTxs>
<InitgPty>
<Nm>XYZ</Nm>
</InitgPty>
6个回答

36

这里是一个可用的示例,data.xml 包含您的数据:

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

class Xml2Csv {

    public static void main(String args[]) throws Exception {
        File stylesheet = new File("src/main/resources/style.xsl");
        File xmlSource = new File("src/main/resources/data.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("/tmp/x.csv"));
        transformer.transform(source, outputTarget);
    }
}

style.xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" >
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
Host_Name,IP_address,OS,Load_avg_1min,Load_avg_5min,Load_avg_15min
<xsl:for-each select="//Host">
<xsl:value-of select="concat(Host_Name,',',IP_address,',',OS,Load_avg_1min,',',Load_avg_5min,',',Load_avg_15min,'&#xA;')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

输出:

Host_Name,IP_address,OS,Load_avg_1min,Load_avg_5min,Load_avg_15min
srv001001,10.1.2.3,Windows1.3,2.5,1.2
srv001002,10.1.2.4,Linux1.4,2.5,1.2
srv001003,10.1.2.5,Linux3.3,1.6,1.8
srv001004,10.1.2.6,Linux2.3,4.5,4.2

我试图绕过这段代码,只构建一个csv文件,但是失败了。您有什么提示可以帮助我完成这个任务吗?我有100多个XML文件需要转换成单个csv文件。 - user3270763
我尝试了这个,但是我只得到了列名...我应该改变什么? - ZIA ANSARI
所以,如果您没有style.xsl文件,您需要手动创建它吗?如果您不想在CSV中包含标题,会发生什么?如何实现这一点? - IoT user
@iot-user,编辑style.xsl应该可以让您得到想要的结果。请在其中删除标题行。 - codester
如何将子节点数据提取到 CSV?例如:<m:properties xmlns:m="" rel = "nofollow noreferrer">http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"> <d:ContentTypeID>0z342bvff</d:ContentTypeID> <d:Name>world_catalon</d:Name> <d:Title>Catalon</d:Title> - Nagarjuna Yalamanchili

3
你最好使用XSLT将XML转换为CSV。在Stack Overflow上有一些问答(例如这里)涵盖了如何进行此操作。关键是为源数据提供模式,以便XSLT转换过程知道如何读取它,从而可以正确地格式化结果。

然后,您可以使用Xalan输入XML,读取XSLT并输出结果。


这是我认为应该这样做的方式。 - djangofan

2

1

已经有Pedantic(使用类DOM方法)和Jono(这次使用SAX方法)在一月份提供了答案。

我认为两种方法对于小文件都很有效,但后者更适合处理大型XML文件。您没有提到XML文件的实际大小,但应该考虑到这一点。

无论使用哪种方法,一个特定的程序(可以检测到与本地XML相适应的特殊标签)将更容易编写,但在另一种XML格式下不起作用,而更通用的程序将更难设计,但将适用于所有XML文件。 您说您希望能够解析文件而不指定特定的元素名称,因此我想您更喜欢通用方法,我也同意这一点,但请注意这比说起来容易做起来难。 事实上,我在1月份也遇到了同样的问题,这次涉及一个大型XML文件(>>100Mo),我很惊讶迄今为止互联网上还没有可用的解决方案。 把挫折变成更好的东西总是一件好事,所以我决定以最通用的方式自己解决这个特定的问题,特别关注大型XML文件问题。

你可能会感兴趣知道,我编写的通用Java库现在已经作为免费软件发布,以-x -u模式(请参阅文档以获取更多信息)将您的XML文件转换为CSV,符合您的期望。
所以,对于您问题的最后一部分的答案是:是的,至少有一个库可以帮助您实现目标,就是我的库,名为“XML2CSV-Generic-Converter”。当然也可能有其他的库,而且肯定有更好的库,但我自己找不到任何像样的(免费)库。
我不会在这里提供任何链接,以遵守Peter Foti明智的评论-但如果您在喜欢的搜索引擎中键入“XML2CSV-Generic-Converter”,您应该很容易找到它。

0

0

你的文件看起来非常平面和简单。你不一定需要一个XML解析器来转换它。 只需使用LineNumberReader.readLine()解析它,并使用regexp提取特定字段。

另一个选择是使用StAX,这是一个用于XML处理的流API。它非常简单,而且你不需要将整个文档加载到RAM中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接