【问题标题】:How to load a relative system DTD into a StAX parser?如何将相关系统 DTD 加载到 StAX 解析器中?
【发布时间】:2012-05-27 23:28:35
【问题描述】:

我正在使用woodstox 为XML 文件实现StAX 解析器。假设我在文件系统的公共目录中的某处有一个有效的 XML 文件,该文件具有匹配的 DTD。

/path/to/test.xml
/path/to/test.dtd

使用如下的相对系统标识符声明对其 DTD 的 XML 引用:

<!DOCTYPE test SYSTEM "test.dtd">

从验证的角度来看,我觉得一切都很好。 (是吗?xmllint 不会抱怨。)但是,当我尝试使用下面的代码解析文件时,woodstox 会抛出 java.io.FileNotFoundException,因为它找不到相关的 DTD 文件。在我看来,该实现尝试访问相对于工作目录而不是相对于 XML 文件对象的 DTD 文件。

import java.io.FileInputStream;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

public class Test {

    public static void main( String[] args ) throws Exception {

        FileInputStream fileInputStream = new FileInputStream( args[0] );
        XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
        XMLStreamReader xsr = xmlInputFactory.createXMLStreamReader(fileInputStream);

        while( xsr.hasNext() ) {
            if( xsr.next() == XMLStreamConstants.DTD ) {
                System.err.println( xsr.getText() );
            }
        }
    }
}
  1. 这是故意的吗?
  2. 是否有一种方便的方法可以说服 StAX 解析器加载相对于给定 XML 文件而不是相对于工作目录的 DTD?

【问题讨论】:

    标签: xml dtd stax woodstox


    【解决方案1】:

    您将需要提供自己的XMLResolver 接口实现(在SAX 世界中它被称为EntityResolver)来帮助解析器找到DTD。 XMLInputFactorysetXMLResolver() 方法可以为你做这件事。

    有关该主题的更多信息:

    当解析器需要解析 SYSTEM URI 时,深入了解一下到底发生了什么也是一个好主意。例如,伍德斯托克斯有 an internal (and a default) implementation of the XMLResolver(以及 a proxy between the SAX's EntityResolver and a StAX XMLResolver)。看看它对你的 DTD“文件名”做了什么,你就会明白为什么它会这样工作。

    【讨论】:

      【解决方案2】:

      @Pavel Veller 的回答是正确的。下面是一个具体的使用示例:

      /**
       * Responsible for parsing the specified XML file and creating objects for
       * insertion into the MySQL database.
       * 
       * @author cameronhudson
       *
       */
      public class Parser {
      
        /**
         * Creates a new XMLStreamReader from the specified file.
         * 
         * @param file The relative path of the file to load.
         * @return An XMLStreamReader to be used for parsing.
         */
        private static XMLStreamReader getXmlReader(String filename) {
      
          // Initialize an XMLStreamReader
          XMLStreamReader reader;
      
          // Instantiate an XMLInputFactory and set an XMLResolver
          XMLInputFactory factory = XMLInputFactory.newInstance();
          factory.setXMLResolver(new XMLResolver() {
      
            @Override
            public Object resolveEntity(String publicID, String systemID,
                String baseURI, String namespace) throws XMLStreamException {
      
              /*
               * The systemID argument is the same dtd file specified in the xml file
               * header. For example, if the xml header is <!DOCTYPE dblp SYSTEM
               * "dblp.dtd">, then systemID will be "dblp.dtd".
               * 
               */
              return Parser.filenameToStream(systemID);
            }
      
          });
      
          // Get the XML file as an InputStream.
          InputStream stream = Parser.filenameToStream(filename);
      
          // Instantiate a new XMLStreamReader.
          try {
            reader = factory.createXMLStreamReader(stream);
          } catch (XMLStreamException e) {
            System.err.println(e);
            return null;
          }
          return reader;
        }
      
        /**
         * Converts a local resource filename into a path dependent on the runtime
         * environment.
         * 
         * @param filename The local path of the resource within /src/main/resources/.
         * @return An input stream of the file.
         */
        private static InputStream filenameToStream(String filename) {
          return Thread.currentThread().getContextClassLoader()
              .getResourceAsStream(filename);
        }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-13
        • 2010-09-23
        • 1970-01-01
        • 1970-01-01
        • 2016-10-30
        • 2016-01-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多