部分读取xml文件

时间:2014-04-28 15:12:21

标签: java xml parsing file-io gosu

我需要从大约100个长达200,000行的XML文件中读取前15行。有没有办法使用像BufferedReader之类的东西来有效地做到这一点? this question中列出的步骤使用DocumentBuilder.parse(String);这会尝试立即解析整个文件。

编辑:前15个元素包含有关文件的元数据(页面名称,最后编辑日期等),我想将其解析为表格。

5 个答案:

答案 0 :(得分:7)

这可能是你想要做的 - 就像我在评论中写的那样,使用SAX解析器,当你的停止条件满足时,使用这个

How to stop parsing xml document with SAX at any time?

编辑:

的test.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <first>
        <inner>data</inner>
    </first>
    <second>second</second>
    <third>third</third>
    <next>next</next>
</root>

ReadXmlUpToSomeElementSaxParser.java

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class ReadXmlUpToSomeElementSaxParser extends DefaultHandler {

    private final String lastElementToRead;

    public ReadXmlUpToSomeElementSaxParser(String lastElementToRead) {
        this.lastElementToRead = lastElementToRead;
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        // just for showing what is parsed
        System.out.println("startElement: " + qName);
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (lastElementToRead.equals(qName)) {
            throw new MySaxTerminatorException();
        }
    }

    public static void main(String[] args) throws Exception {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();

        try {
            saxParser.parse("src/test.xml", new ReadXmlUpToSomeElementSaxParser("second"));
        } catch (MySaxTerminatorException exp) {
            // nothing to do, expected
        }
    }

    public class MySaxTerminatorException extends SAXException {
    }

}

输出

startElement: root
startElement: first
startElement: inner
startElement: second

为什么这样更好?仅仅因为某些应用程序可以发送给您

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <first><inner>data</inner></first>
    <second>second</second>
    <third>third</third>
    <next>next</next>
</root>

和面向行的方法将失败......

我提供了不计算元素的解析器,以显示可以根据实现所需的业务逻辑来定义条件...

characters()警告

要读取元素中的数据,您可以使用character()方法,但请注意

  

SAX解析器可以在一个块中返回所有连续的字符数据,或者它们可以将它分成几个块

JavaDoc

中阅读更多内容

答案 1 :(得分:4)

这是一个简单的解决方案,它将逐行读取您的文件,直到它在行变量中存储15行数据(如果文件较小,则少于15行)。

File f = new File("your path");
BufferedReader br = null;
String lines = "";
try
{
    br = new BufferedReader(new FileReader(f));
    String line = null;
    int lineCount = 0;
    while((line = br.readLine()) != null)
    {
        lineCount++;
        lines += line + "\n";
        if(lineCount == 15) break;
    }
}
catch(Exception e)
{
    e.printStackTrace();
}
finally
{
    try{br.close();}catch(Exception e){}
}

答案 2 :(得分:4)

我建议查看流式XML解析器;流API的用例扩展到读取几百GB的文件,这些文件显然不适合内存。

在Java中,StAX API是本地SAX API的(相当大的)演变。在这里查看关于解析&#34;动态&#34;:

的教程

http://tutorials.jenkov.com/java-xml/stax.html

答案 3 :(得分:2)

最好像下面一样手动阅读。在你的情况下,DOM解析器将是昂贵的。如果您真的想要解析xml并提取/插入节点,则可以使用SAX解析器。

try (BufferedReader br = new BufferedReader(new FileReader("C:\\testing.txt")))
{

    String sCurrentLine;

    while ((sCurrentLine = br.readLine()) != null) {
        System.out.println(sCurrentLine);
    }

} catch (IOException e) {
    e.printStackTrace();
} 

答案 4 :(得分:2)

假设您想阅读以下内容:

<?xml ...?>
<root>
    <element>data</element>
    ...
    <otherElement>more data</otherElement>
    <ignoredElement> ... </ignoredElement>
    ... more ignored Elements
</root>

并且您只希望根目录中的前13个子元素(恰好位于非常大的文件的前15行内)。

您可以使用SAX解析器读取文件,并在读取这些元素后立即将其中止。

您可以使用标准J2SE设置SAX解析器:

SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader reader = sp.getXMLReader();

然后,您需要创建一个将成为数据处理程序的ContentHandler类。我会称之为DataSaxHandler。如果你扩展DefaultHandler,你只需要实现你感兴趣的方法。这是一个你可以用它作为起点的例子。它将检测每个元素的开始和结束并将其打印出来。它将计算15个结束标记(它不会生成格式良好的输出)并且它将忽略属性。用它作为起点(我没有测试过):

public class DataSaxHandler extends DefaultHandler {

    private int countTags = 0;
    private boolean inElement = false;

    @Override
    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
        System.out.println("<" + qName + ">");
        inElement = true;
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        countTags++;
        System.out.println("</" + qName + ">");
        inElement = false;

        if(countTags > 15) {
            // throw some exception to stop parsing
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if(inElement) {
            System.out.println(new String(ch, start, length));
        }
    }
}

您将其注册到SAX阅读器并使用它来解析文件。

    reader.setContentHandler(new DataSaxHandler());
    reader.parse(new InputSource(new FileInputStream(new File(PATH, "data.xml"))));