糟糕的性能解析XHTML文件与Doctype作为XML文档

时间:2012-03-09 04:31:46

标签: java xml xhtml

当我将此xhtml文件解析为xml时,在这样一个简单的文件上进行解析大约需要2分钟。我发现如果删除doctype声明,它会立即解析。导致此文件花费这么长时间解析的错误是什么?

Java示例

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware( true );
DocumentBuilder bob = dbf.newDocumentBuilder();
Document template = bob.parse( new InputSource( new FileReader( xmlFile ) ) );

XHTML示例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ex="http://www.example.com/schema/v1_0_0">
    <head><title>Test</title></head>
    <body>
        <h1>Test</h1>
        <p>Hello, World!</p>
        <p><ex:test>Text</ex:test></p>
    </body>
</html>

由于

编辑:解决方案

为了根据提供的有关原因的问题实际解决问题,我做了以下基本步骤:

  1. 将与DTD相关的文件下载到src / main / resources文件夹
  2. 创建自定义EntityResolver以从类路径中读取这些文件
  3. 告诉我的DocumentBuilder使用我的新EntityResolver
  4. 我这样做引用了这个答案:how to validate XML using java?

    New EntityResolver

    import java.io.IOException;
    
    import org.xml.sax.EntityResolver;
    import org.xml.sax.InputSource;
    import org.xml.sax.SAXException;
    
    public class LocalXhtmlDtdEntityResolver implements EntityResolver {
    
        /* (non-Javadoc)
         * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String)
         */
        @Override
        public InputSource resolveEntity( String publicId, String systemId )
                throws SAXException, IOException {
            String fileName = systemId.substring( systemId.lastIndexOf( "/" ) + 1 );    
            return new InputSource( 
                    getClass().getClassLoader().getResourceAsStream( fileName ) );
        }
    
    }
    

    如何使用新的EntityResolver:

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware( true );
    DocumentBuilder bob = dbf.newDocumentBuilder();
    bob.setEntityResolver( new LocalXhtmlDtdEntityResolver() );
    Document template = bob.parse( new InputSource( new FileReader( xmlFile ) ) );
    

2 个答案:

答案 0 :(得分:3)

Java正在下载指定的DTD及其包含的文件,以验证您的xhtml文件是否服从指定的DTD。使用Charles代理我记录了以下请求,并指定了要加载的数量:

答案 1 :(得分:2)

实际上,你很幸运能得到这些文件。 W3C故意对这些文档的请求没有响应,因为它们无法处理大量请求。您需要为解析器提供本地副本。

在Java世界中执行此操作的常用方法是使用Apache / Oasis目录解析器。

最新版本的Saxon具有这些常用DTD和实体文件的内置知识,如果您允许Saxon提供XML解析器,它将自动配置为使用本地副本。即使您没有使用XSLT或XQuery来处理数据,也可以利用这一点:只需创建一个Saxon Configuration对象并调用其getSourceParser()方法来获取XMLReader。

(也许这也是摆脱DOM的好时机。在Java中处理XML的众多选择中,DOM可能是最差的。如果必须使用低级导航API,请选择一个像样的一个像JDOM或XOM。)