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

时间:2016-12-19 12:31:41

标签: java xml dtd

不确定它是仅仅是我还是API但是我根本无法创建XML文件而没有抛出异常或者我试图设置(DocType)没有设置的东西

这就是我目前正在做的事情:

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();
}

然而,这样我得到了一个例外。我可以使用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);

但我的DocType的{​​{1}}将为finalDocument

Setting my own EntityResolver也不会这样做:

null

因为如果我想设置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>

2 个答案:

答案 0 :(得分:2)

对我来说,如果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

虽然这是有趣的事情:它会在出现时设置为on-read:

在访问docType之前:

enter image description here

访问docType后:

enter image description here

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

答案 1 :(得分:2)

试试这个:

Transformer t = TransformerFactory.newInstance().newTransformer();
Source s = new StreamSource(new StringReader(inputXML));
StringWriter sw = new StringWriter();
t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "my.system.id");
t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "my/public/id");
t.transform(s, new StreamResult(sw));

根本不需要通过DOM。