繁体   English   中英

加载 XML 非常慢

[英]Loading XML is VERY slow

我继承了一个数据存储,它使用简单的文本文件来保存文档。

文档有一些属性(日期、标题和文本),这些属性被编码在一个文件名中:<date>-<title>.txt,文件的主体是文本。

然而实际上系统中的文档有更多的属性,甚至更多的被提议添加。

切换到 XML 格式似乎是合乎逻辑的,我已经这样做了,现在每个文档都编码在它自己的 XML 文件中。

但是,从 XML 读取文件现在非常慢! (2000 篇 .txt 格式的文章需要几秒钟,而现在 2000 篇 .xml 格式的文章需要 10 多分钟)。

我使用的是 DOM 解析器,在我发现读取速度很慢后,我切换到了 SAX 解析器,但它仍然很慢(好吧,更快,但仍然是 10 分钟)。

XML 只是那么慢,还是我在做一些奇怪的事情? 任何想法将不胜感激。

该系统是用 JavaSE 1.6 编写的。 解析器是这样创建的:


/*
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
*/
  SAXParserFactory factory = SAXParserFactory.newInstance();
  SAXParser saxParser;
  try {
    saxParser = factory.newSAXParser();
    ArticleSaxHandler handler = new ArticleSaxHandler();
    saxParser.parse(is, handler);
    return handler.getArticle();
  } catch (ParserConfigurationException e) {
    throw new IOException(e);
  } catch (SAXException e) {
    throw new IOException(e);
  } finally { 
    if (is != null) {
      try {
        is.close();
      } catch (IOException e) {
        logger.error(e);
      }
    }
  }
}

private class ArticleSaxHandler extends DefaultHandler {
        private URI uri = null;
        private String source = null;
        private String author = null;
        private DateTime articleDatetime = null;
        private DateTime processedDatetime = null;
        private String title = null;
        private String text = null;
        private ArticleElement currentElement;
        private final StringBuilder builder = new StringBuilder();

        public Article getArticle() {
            return new Article(uri, source, author, articleDatetime, processedDatetime, title, text);
        }

        /** Receive notification of the start of an element. */
        public void startElement(String uri, String localName, String qName, Attributes attributes) {
            if (builder.length() != 0) {
                throw new RuntimeException(new SAXParseException(currentElement + " was not finished before " + qName + " was started", null));
            }
            currentElement = ArticleElement.getElement(qName);
        }

        public void endElement(String uri, String localName, String qName) {
            final String elementText = builder.toString();
            builder.delete(0, builder.length());
            if (currentElement == null) {
                return;
            }
            switch (currentElement) {
                case ARTICLE:
                    break;
                case URI:
                    try {
                        this.uri = new URI(elementText);
                    } catch (URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                    break;
                case SOURCE:
                    source = elementText;
                    break;
                case AUTHOR:
                    author = elementText;
                    break;
                case ARTICLE_DATE_TIME:
                    articleDatetime = getDateTimeFormatter().parseDateTime(elementText);
                    break;
                case PROCESSED_DATE_TIME:
                    processedDatetime = getDateTimeFormatter().parseDateTime(elementText);
                    break;
                case TITLE:
                    title = elementText;
                    break;
                case TEXT:
                    this.text = elementText;
                    break;
                default:
                    throw new IllegalStateException("Unexpected ArticleElement: " + currentElement);
            }
            currentElement = null;
        }

        /** Receive notification of character data inside an element. */
        public void characters(char[] ch, int start, int length) {
            builder.append(ch, start, length);
        }

        public void error(SAXParseException e) {
            fatalError(e);
        }

        public void fatalError(SAXParseException e) {
            logger.error("currentElement: " + currentElement + " ||builder: " + builder.toString() + "\n\n" + e.getMessage(), e);
        }
    }

    private enum ArticleElement {
        ARTICLE(ARTICLE_ELEMENT_NAME), URI(URI_ELEMENT_NAME), SOURCE(SOURCE_ELEMENT_NAME), AUTHOR(AUTHOR_ELEMENT_NAME), ARTICLE_DATE_TIME(
                ARTICLE_DATETIME_ELEMENT_NAME), PROCESSED_DATE_TIME(PROCESSED_DATETIME_ELEMENT_NAME), TITLE(TITLE_ELEMENT_NAME), TEXT(TEXT_ELEMENT_NAME);
        private String name;

        private ArticleElement(String name) {
            this.name = name;
        }

        public static ArticleElement getElement(String qName) {
            for (ArticleElement element : ArticleElement.values()) {
                if (element.name.equals(qName)) {
                    return element;
                }
            }
            return null;
        }
    }

从无缓冲流中读取数据可以解释这些性能问题。 这与从文本到 XML 的更改没有直接关系,但可能您的新实现不再使用BufferedInputStream


Follwing这条道路,在详细检查,如果这is缓冲:

saxParser.parse(is, handler);

我也遇到了这个问题,使用 SAX 解析器加载缓慢。 该问题实际上与我的 XML 文件有关,该文件具有来自 W3C 的 DTD 引用:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
<html xmlns="http://www.w3.org/TR/1999/REC-html-in-xml" xml:lang="en"
      lang="en">

“Core Java, Volume II”第 2 章关于 SAX 和 XML 的摘录描述了正在发生的事情以及如何解决:

XHTML 文件以包含 DTD 引用的标记开始,解析器将要加载它。 可以理解,W3C 不太乐意提供数十亿份文件副本,例如 www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd。 有一次,他们完全拒绝了,但在撰写本文时,他们以极快的速度为 DTD 服务。 如果您不需要验证文档,只需调用

SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

这为我修好了。 此外,我使用 IntelliJ IDE 显示我的 XML 文件有一个额外的(不必要的) <HTML>标记和一个额外的<meta charset="UTF-8"/> 这帮助我摆脱了一些 SAX 异常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM