Java:给定文件名列表,确保相应的XML仅包含有关这些文件的信息

时间:2011-07-19 15:57:37

标签: java xml io xml-parsing

我有一个文件列表(20,000到50,000个文件)和一个大的xml文件。我希望文件XML仅包含List中的文件信息。

例如,假设我们的列表中只有文件XYZ,XML文件如下所示。

<?xml version="1.0" encoding="ISO-8859-1"?>
<index>
<document>
    <entry number="1">
        <commentfield>
            <name>FileName</name>
            <value>XYZ</value>
        </commentfield>
    </entry>
    <entry number="2">
        <commentfield>
            <name>Note</name>
            <value>03-000</value>
        </commentfield>
    </entry>
</document>
<document>
    <entry number="1">
        <commentfield>
            <name>FileName</name>
            <value>ABC</value>
        </commentfield>
    </entry>
</document>
...
</index>

XML包含两个文件XYZABC的信息。因此,我不希望最终的XML包含 last <document> ... ABC ... </document>,因为document ABC不在我们的列表中。我的要求在KSH脚本中成功运行,但运行速度太慢(22000个文件超过4小时。还有其他功能)。但我决定移植到Java以获得更好的性能。我所做的是逐行读取一个字符串,当我点击</document>时,我解析出文件的名称,检查我们列表中是否存在这些文件,如果是,那么写下整个{{ 1}}到另一个<document> ... </document>文件,然后再次阅读下一个xml。还有更好的方法吗?

已经能够使用DOM解析器编写代码来完成此任务。代码很长,所以如果你需要它,请发给我。 tyvm求助

4 个答案:

答案 0 :(得分:2)

使用正则表达式解析一个XML输入,或者是一个脆弱的解决方案,它会对输入文本的格式(在空白等周围)施加不必要的限制。当Java库附带多个XML解析器时,就没有必要使用它。

使用DOM可能是最简单的方法,如果你可以保证你的输入XML不会变得太大而不能一次进入内存。你可以:

  1. 将XML读入DOM结构
  2. 遍历DOM并修改它,删除不需要的节点
  3. 使用Transformer将修改后的DOM写入新文件。示例here
  4. 更有效的选项可能是StAX,它不需要立即读入整个输入。我没有使用它,但它具有读取和写入文档的能力。您可以一次读取<document>元素,如果它在列表中,则将其写回输出文件。一些教程here

答案 1 :(得分:1)

有多种方法可以解决这个问题:

XSL如果您有一个固定的输入列表,您可以编写一个仅选择有效元素并输出它们的变换,这将使这变得非常简单。这样您就不必实际编写任何代码,并且可以使用非常快的xsltproc之类的东西!

这是我首先尝试的,因为它专门为转换 XML创建了其他XML,它代码更少,代码更少,维护更少。

以下是如何开始使用的想法,这会输出<document/>元素不等于<value/>的所有ABC元素。

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml"/>

    <!-- this matches ALL nodes and ALL attributes -->
    <xsl:template match="node()|@*">
      <xsl:copy>
         <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    </xsl:template>

    <!-- this matches the entire document element where value = 'ABC' -->
    <xsl:template match="document[entry[commentfield[value[(text()='ABC')]]]]"/>

</xsl:stylesheet>

XSLT上有大量资源和好书,您需要做的就是提供受支持的<value/>元素的白名单,并反转我的示例中的逻辑。

如果你有.xsd你可以创建一个,你的输入文件看起来并不复杂,可以使用JAXB自动生成一个Object层次结构来解析输入文件然后,您可以遍历生成的对象图并删除任何不符合您标准的内容,并将其转换回文件。

如果文件大小大于适合内存的大小,则JAXB不太可行。

答案 2 :(得分:1)

暂时忽略解析和重写XML的最佳方法的细节,通过XML文件读取一次并在列表中查找每个文件名的基本策略似乎是合理的。

但是,您可以改进它们检查文件名列表中存在的方式(您没有指定如何执行此操作)。几种可能性:

  1. 将文件名放在Set中,并检查集合中是否存在,这将是O(1)或O(日志N)操作
  2. 对文件名列表进行排序并执行二进制搜索,这将是一个O(日志N)操作。
  3. 无论哪种方式都可以通过未排序的列表进行简单的线性搜索。

答案 3 :(得分:0)

您可以使用Xpath来获取元素,如果您知道xml的结构,则可以删除这些元素。根据您处理xml的方式,您可以使用DOM(对于大型XML可能不是一个好主意)