RE: 大型XML文件

5

对于大型XML文件的跟进问题:

首先感谢您的答复。 接下来...我做错了什么? 这是使用SAX的我的类:

public class SAXParserXML extends DefaultHandler {
  public static void ParcourXML() {

      DefaultHandler handler = new SAXParserXML();
      SAXParserFactory factory = SAXParserFactory.newInstance();
      try {
          String URI = "dblp.xml";
          SAXParser saxParser = factory.newSAXParser();
          saxParser.parse(URI,handler);
      } catch (Throwable t) {
     t.printStackTrace ();
       }
  }



  public void startElement (String namespaceURI,String simpleName,String qualifiedName,Attributes attrs) throws SAXException {
  }
  public void endElement (String namespaceURI,String simpleName,String qualifiedName) throws SAXException {

  }
}

您可以看到,我对我的XML文件什么都没做,但它却出现了这个错误:

java.lang.OutOfMemoryError: Java heap space
    at com.sun.org.apache.xerces.internal.util.XMLStringBuffer.append(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.refresh(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.invokeListeners(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.peekChar(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at javax.xml.parsers.SAXParser.parse(Unknown Source)
    at javax.xml.parsers.SAXParser.parse(Unknown Source)
    at SAXParserXML.ParcourXML(SAXParserXML.java:30)
    at Main.main(Main.java:28)

我也尝试了Stax...出现了相同的错误...我该怎么办? 此外,我将Java堆大小增加到1260M。

java -Xmx1260M SAXParserXML

XML文件的格式如下所示:

<dblp> 
   <incollection> 
      <author>... </author> 
      .... 
      <author>... </author> 
      #other tags-i'm interested only by <author>#
      ... 
   </incollection> 
   <incollection> 
   # the same thing# 
   </incollection> 
   .... 
</dblp> 

你可以在以下链接找到原始文件:http://dblp.uni-trier.de/xml/。谢谢。

如果您能告诉我们您正在解析哪种类型的XML,那将会很有帮助。 - Paul Tomblin
5个回答

6

有一个与Java 1.6相关的错误,它显示完全相同的堆栈跟踪,并且目前尚未修复。较新的Xerces版本似乎没问题。

对于这么大的文档,仍然包含相当数量的结构,您可以考虑使用部分结构的解析方法,例如使用StAX进行拉式解析。


如果它给出相同的堆栈跟踪,那么你没有使用StAX。StAX的堆栈跟踪是什么? - lavinio
我认为我和主题发起者有相同的问题。错误页面显示该错误已关闭...但它真的被修复了吗?我在Windows XP上使用JDK 6 Update 23。 - Marco Eckstein

2

好的,考虑到:

public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String argv[]) {
        Writer out;

        // Use an instance of ourselves as the SAX event handler
        Echo handler = new Echo();
        // Use the default (non-validating) parser
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            // Set up output stream
            out = new OutputStreamWriter(System.out, "UTF8");
            // Parse the input 
            SAXParser saxParser = factory.newSAXParser();
            saxParser.parse(new File("/tmp/dblp.xml"), handler);
        } catch (Throwable t) {
            t.printStackTrace();
        }
        System.out.println("Incollections = " + handler.cnt);
        System.exit(0);
    }

    static class Echo extends DefaultHandler {
        public int cnt = 0;
        @Override
        public void startElement(String namespaceURI,
                String sName, // simple name
                String qName, // qualified name
                Attributes attrs)
                throws SAXException {
            if (qName.equals("incollection")) {
                cnt = cnt + 1;
            }
        }
    }
}

这在我使用Java 5时有效,但在使用Java 6时会出现OOM错误。
我是这样运行的:
java -DentityExpansLimit=512000 -jar xmltest.jar

并且它会打印:

Incollections = 8353

哪个更方便:

grep "<incollection" /tmp/dblp.xml | wc -l
8353

所以,FYI,数据点等等。

非常感谢...那就是问题所在,我应该使用Java 5进行编译并扩展实体限制: Java -DentityExpansionLimit=512000 Main - user61652

0

你的代码中似乎存在HTML实体的问题,特别是在第一个块中的"Jos&eacute;"。当我打开文件时,我的浏览器告诉我它存在问题,并且XMLEntityScanner出现在堆栈跟踪中。虽然我不是XML专家,但是HTML实体是否在XML中没有被定义呢?

编辑 是的,就是这样。根据Wikipedia,像&eacute;这样的实体在HTML DTD中被定义;而XML只有非常少量的预定义实体。


所有实体都在dblp.dtd中定义。 - user61652
但这会导致内存错误吗?我也不是XML专家,但我认为像é这样的坏实体会导致SAXExceptions而不是内存异常。 - Michael

0

我不知道这个的正确术语,但是你的 XML 有多“深”?例如,在你的示例中,“作者”标签是2个元素深。如果你有非常深的标签,也许这就是为什么你会遇到内存问题的原因?


嵌套实际上并不重要:对于 SAX 和 Stax,每个级别使用的内存量非常小。我是说,除非它有成千上万个级别:) - StaxMan

0

看起来 XML 文件中的一个文本段落(或 CDATA、处理指令或注释)非常长,解析器无法将其分成多个段落。 或者可能是解析器没有正确解析 DOCTYPE 声明:如果是这样,它可能会尝试将所有 XML 内容读取为 DTD 子集的一部分。

但这只是猜测。您提到您已经尝试过 Stax:使用哪个实现?JDK 1.6 自带 Sun Sjsxp。但您也可以尝试 Woodstox(http://woodstox.codehaus.org),它通常以更稳健的方式处理事情。 因此,如果您没有使用 Woodstox,则可以查看发生了什么。它将文本段落拆分成较小的块,除非您强制使用文本合并(不是默认设置)。

哦,以防万一,您正在使用 Stax 引用实现(http://stax.codehaus.org)进行测试;它很不幸地知道存在许多错误。因此,这可能会导致问题。 Sjsxp 和 Woodstox 都是与 Stax 配合更好的选择。


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