【问题标题】:How can I force a SAX parser to use a DTD if one is not specified in the input file?如果输入文件中未指定 DTD,如何强制 SAX 解析器使用 DTD?
【发布时间】:2011-01-25 15:40:04
【问题描述】:

如何强制 SAX 解析器(特别是 Java 中的 Xerces)在解析文档时使用 DTD,而输入文档中没有 any doctype?这甚至可能吗?

以下是我的场景的更多细节:

我们有一堆符合相同 DTD 的 XML 文档,这些 DTD 由多个不同的系统生成(我都无法更改)。其中一些系统将文档类型添加到其输出文档中,而其他系统则没有。有些使用命名字符实体,有些则不使用。 有些人使用命名的字符实体而不声明文档类型。我知道这不符合规定,但这是我必须使用的。

我正在开发需要用 Java 解析这些文件的系统。目前,它通过首先将 XML 文档作为流读取来处理上述情况,尝试检测它是否定义了 doctype,如果还没有,则添加一个 doctype 声明。问题是这段代码有问题,我想用更干净的代码替换它。

文件很大,所以我不能使用基于 DOM 的解决方案。我也在尝试解析字符实体,因此没有帮助使用 XML Schema。

如果您有解决方案,能否请您直接发布而不是链接到它?如果将来有一个带有死链接的正确解决方案,它对 Stack Overflow 并没有多大好处。

【问题讨论】:

    标签: java dtd sax doctype xerces


    【解决方案1】:

    如果文档没有,我认为设置 DOCTYPE 是不明智的。可能的解决方案是写一个假的,就像你已经做的那样。如果您使用的是 SAX,则可以使用这个假 InputStream 和假 DefaultHandler 实现。 (仅适用于 latin1 单字节编码)

    我知道这个解决方案也很丑陋,但它只有一个适用于大数据流。

    这是一些代码。

    private enum State {readXmlDec, readXmlDecEnd, writeFakeDoctipe,  writeEnd};
    
    private class MyInputStream extends InputStream{
    
        private final InputStream is;
        private StringBuilder sb = new StringBuilder();
        private int pos = 0;
        private String doctype = "<!DOCTYPE register SYSTEM \"fake.dtd\">";
        private State state = State.readXmlDec;
    
        private MyInputStream(InputStream source) {
            is = source;
        }
        @Override
        public int read() throws IOException {
            int bit;
    
            switch (state){ 
                case readXmlDec:
                    bit = is.read();
                    sb.append(Character.toChars(bit));
                    if(sb.toString().equals("<?xml")){
                        state = State.readXmlDecEnd;
                    }
                    break;
                case readXmlDecEnd:
                    bit = is.read();
                    if(Character.toChars(bit)[0] == '>'){
                        state = State.writeFakeDoctipe;
                    }
                    break;
                case writeFakeDoctipe:
                    bit =  doctype.charAt(pos++);
                    if(doctype.length() == pos){
                        state = State.writeEnd;
                    }
                    break;
                default:
                    bit = is.read();
                    break;
            }
            return bit;
        }
    
        @Override
        public void close() throws IOException {
            super.close();
            is.close();
        }
    }
    
    private static class MyHandler extends DefaultHandler {
    
        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException {
            System.out.println("resolve "+ systemId);
            // get real dtd
            InputStream is = ClassLoader.class.getResourceAsStream("/register.dtd");
            return new InputSource(is);
        }
    
     ... // rest of code
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-19
      • 2011-09-21
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 2014-12-11
      相关资源
      最近更新 更多