Not sure if it's just me or the API but I am simply not able to create an XML file without having either an exception thrown at me or the thing I'm trying to set (DocType) not being set.
This is what I'm currently doing:
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();
}
However, this way I'm getting an exception. I can use the DocumentBuilderFactory and configure it like 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);
but then DocType of my finalDocument will be null.
Setting my own EntityResolver won't do the trick either:
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;
}
}
});
because if I want to set doctype.getSystemId() I really want to set doctype.getSystemId().
Is there a way to shove set it without this headache?
Essentially I want to parse this:
<?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>
and transform it into this:
<?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>
To me your code works if the dtd exists at the specified location (systemId), otherwise adding the entity resolver as in the code down makes the trick.
I don't have
xmlDocumentso I hardcoded the valuesOutput:
Also the option of setting the properties works, without entity resolver, must be done before creating the builder. Of the properties, only
http://apache.org/xml/features/nonvalidating/load-external-dtdis needed.Here is the fun thing though: It's getting set on-read as it appears:
Before accessing
docType:After accessing
docType:This can be controlled, in Xerces, using property
http://apache.org/xml/features/dom/defer-node-expansion, by defaulttrue