java - 如何在不验证或检查 DTD 的情况下设置系统和公共(public) ID?

标签 java xml dtd

不确定是我的问题还是 API 的问题,但我无法在没有抛出异常或我尝试设置的东西 (DocType) 的情况下创建 XML 文件未设置。

这是我目前正在做的:

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
stringBuilder.append("<!DOCTYPE document>");

String xmlString = AnnotatedDocumentTree.toString(annotatedDocumentTree, new SimpleAnnotatedDocumentTreeXmlConverter(), stringBuilder);

DocumentBuilderFactory icFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder icBuilder;          
Document finalDocument = null;                 

StringWriter writer = new StringWriter();

try {

    icBuilder = icFactory.newDocumentBuilder(); 

    finalDocument = icBuilder.parse(new InputSource(new ByteArrayInputStream(xmlString.getBytes("UTF-8"))));                

    Transformer transformer = TransformerFactory.newInstance().newTransformer();

    DocumentType doctype = xmlDocument.getDoctype();                    

    transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doctype.getSystemId());
    transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, doctype.getPublicId());
    transformer.transform(new DOMSource(finalDocument), new StreamResult(writer));

    finalDocument = icBuilder.parse(new InputSource(new ByteArrayInputStream(writer.toString().getBytes("UTF-8"))));


} catch (Exception e) {
    e.printStackTrace();
}

但是,这样我得到了一个异常(exception)。我可以使用 DocumentBuilderFactory 并将其配置为 this :

icFactory.setValidating(false);
icFactory.setNamespaceAware(true);
icFactory.setFeature("http://xml.org/sax/features/namespaces", false);
icFactory.setFeature("http://xml.org/sax/features/validation", false);
icFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
icFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

但是我的 finalDocumentDocType 将是 null

Setting my own EntityResolver也不会成功:

builder.setEntityResolver(new EntityResolver() {
    @Override
    public InputSource resolveEntity(String publicId, String systemId)
            throws SAXException, IOException {
        if (systemId.contains(".dtd")) {
            return new InputSource(new StringReader(""));
        } else {
            return null;
        }
    }
});

因为如果我想设置 doctype.getSystemId()真的想设置 doctype.getSystemId()

有没有办法在没有这种头痛的情况下插入它?


本质上我想解析这个:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE document>
<ds>
    ABGB <cue>: §§ 786 , 810 , 812 </cue>Die Kosten der ... 
    <cue>von</cue>
    <Relation bewertung="1">7 Ob 56/10a </Relation>= 
    <Relation bewertung="1">Zak 2010/773 , 440 </Relation>. 
</ds>

并将其转化为:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ds PUBLIC "-//MBO//DTD artikel-at 1.0//DE" "http://dtd.company.de/dtd-at/artikel.dtd">
<ds>
    ABGB <cue>: §§ 786 , 810 , 812 
    </cue>Die Kosten der ... <cue>
    von 
    </cue><Relation bewertung="1">7 Ob 56/10a </Relation>= 
    <Relation bewertung="1">Zak 2010/773 , 440 </Relation>. 
</ds>

最佳答案

对我来说,如果 dtd 存在于指定位置 (systemId),您的代码就可以工作,否则按照下面的代码添加实体解析器就可以了。

我没有 xmlDocument 所以我硬编码了这些值

    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
    stringBuilder.append("<!DOCTYPE document><document/>");

    String xmlString = stringBuilder.toString(); // AnnotatedDocumentTree.toString(annotatedDocumentTree, new SimpleAnnotatedDocumentTreeXmlConverter(), stringBuilder);

    DocumentBuilderFactory icFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder icBuilder;          
    Document finalDocument = null;                 

    StringWriter writer = new StringWriter();

    try {

        icBuilder = icFactory.newDocumentBuilder(); 

        finalDocument = icBuilder.parse(new InputSource(new ByteArrayInputStream(xmlString.getBytes("UTF-8"))));                

        Transformer transformer = TransformerFactory.newInstance().newTransformer();

        //DocumentType doctype = xmlDocument.getDoctype();                    

        transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "xdtd.dtd"); // doctype.getSystemId());
        transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "xxxx"); //doctype.getPublicId());
        transformer.transform(new DOMSource(finalDocument), new StreamResult(writer));

        icBuilder.setEntityResolver(new EntityResolver() {
            @Override
            public InputSource resolveEntity(String publicId, String systemId)
                    throws SAXException, IOException {
                if (systemId.contains(".dtd")) {
                    return new InputSource(new StringReader(""));
                } else {
                    return null;
                }
            }
        });
        finalDocument = icBuilder.parse(new InputSource(new ByteArrayInputStream(writer.toString().getBytes("UTF-8"))));

        System.out.println(finalDocument.getDoctype().getPublicId());
        System.out.println("-----------");
        System.out.println(writer.toString());

    } catch (Exception e) {
        e.printStackTrace();
    }

输出:

      xxxx
     -----------


     <?xml version="1.0" encoding="UTF-8"?>
     <!DOCTYPE document PUBLIC "xxxx" "xdtd.dtd">
     <document/>

此外,设置属性的选项也可以在没有实体解析器的情况下工作,必须在创建构建器之前完成。在这些属性中,只有 http://apache.org/xml/features/nonvalidating/load-external-dtd 是必需的。


不过有趣的是:它在显示时设置为已读:

在访问 docType 之前:

enter image description here

访问docType后:

enter image description here


这可以在 Xerces 中使用 property http://apache.org/xml/features/dom/defer-node-expansion 进行控制, 默认情况下 true

关于java - 如何在不验证或检查 DTD 的情况下设置系统和公共(public) ID?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41222663/

相关文章:

java - SWT 调整大小错误

java - 为什么此代码出现 "unreachable statement"错误?

xml - XSLT 通过 for-each-group 和 group-starting-with 进行分组?

xpath: contains() 一组答案

xml - 如何使用 IDREF

java - 为什么以下案件的执行流程不同?

java - 使用 Jmeter 对消费者和生产者进行测试

java - 我看不到应用栏中的项目

java - 如何使用 JPA (Java EE) 将 XML 数据结构映射到数据库

xml - 如何在外部文件中将转义字符声明为 DTD 实体并在 XML 文件中导入