java – 如果在输入文件中没有指定一个SAX解析器,如何强制使用DTD?

如果在输入文档中没有任何文字类型的情况下解析文档时,如何强制使用SAX解析器(特别是 Java中的Xerces)来使用DTD?这是甚么可能吗?

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

我们有一堆XML文档符合由多个不同系统生成的相同DTD(我不能更改).其中一些系统在其输出文档中添加一个doctype,另一些则不会.有些使用命名字符实体,有些不行.有些使用命名字符实体,而不声明一个doctype.我知道这不是犹太教,但这是我必须合作的.

我正在使用需要在Java中解析这些文件的系统.目前,它正在处理上述情况,首先将XML文档作为流读取,尝试检测是否定义了一个doctype,如果尚未存在,则添加一个doctype声明.问题是这个代码错误的,我想用更清洁的东西替换它.

文件很大,所以我不能使用基于DOM的解决方案.我也试图解决字符实体,所以它不利于使用XML模式.

如果你有一个解决方案,你可以直接发布,而不是链接到它?如果在未来有一个正确的解决方案与死链接,它不会做堆栈溢出很好.

解决方法

我认为设置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
}

相关文章

应用场景 C端用户提交工单、工单创建完成之后、会发布一条工...
线程类,设置有一个公共资源 package cn.org.chris.concurre...
Java中的数字(带有0前缀和字符串)
在Java 9中使用JLink的目的是什么?
Java Stream API Filter(过滤器)
在Java中找到正数和负数数组元素的数量