XML Transformer设置OutputKeys.DOCTYPE_SYSTEM额外生成双引号如何解决?
问题根源
你遇到的报错是因为OutputKeys.DOCTYPE_SYSTEM参数的使用方式不符合规范:
OutputKeys.DOCTYPE_SYSTEM仅用于传入DOCTYPE声明中SYSTEM标识符的取值,也就是你示例里的MLP_SVC_RESULT_320.DTD部分- 你把DTD内部子集
[<!ENTITY % extension ...]也一同填入该参数后,Transformer会自动将你传入的完整字符串当作SYSTEM ID,在头尾拼接双引号,最终生成的DOCTYPE就出现了多余的双引号,违反XML语法规则。
解决方法
方案1:字符串替换修复(兼容性最好,实现简单)
保留原有Transformer逻辑,生成基础XML后直接替换DOCTYPE为符合要求的版本,代码示例如下:
private String transformToString(Document document) { if (document == null) { return null; } document.setXmlStandalone(true); // 避免输出standalone="no"属性 TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans; try { trans = tf.newTransformer(); trans.setOutputProperty(OutputKeys.INDENT, "no"); // 仅传入正确的SYSTEM ID本身 trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "MLP_SVC_RESULT_320.DTD"); StringWriter sw = new StringWriter(); trans.transform(new DOMSource(document), new StreamResult(sw)); String result = sw.toString(); // 替换整段DOCTYPE为带内部子集的规范版本 result = result.replace("<!DOCTYPE svc_result SYSTEM \"MLP_SVC_RESULT_320.DTD\">", "<!DOCTYPE svc_result SYSTEM \"MLP_SVC_RESULT_320.DTD\" [<!ENTITY % extension SYSTEM \"company_mlp320_slia_extension.dtd\"> %extension;]>"); // 原有空行清理逻辑 result = result.replaceAll("\\n\\s*\\n", "\n"); return result; } catch (TransformerException e) { LOG.error("Cannot transform response document to String. ", e); return null; } }
方案2:使用Transformer扩展属性(依赖Xalan实现)
如果你使用的是Xalan系列Transformer(包括JDK内置的默认Transformer),可以用其专有扩展属性直接设置内部子集,无需后续字符串处理:
// 仅传入正确的SYSTEM ID trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "MLP_SVC_RESULT_320.DTD"); // 通过Xalan专有属性设置DTD内部子集 trans.setOutputProperty("http://xml.apache.org/xalan/properties/doctype-internal-subset", "<!ENTITY % extension SYSTEM \"company_mlp320_slia_extension.dtd\"> %extension;");
该方案不需要修改生成后的字符串,但如果更换了其他Transformer实现(比如Saxon)可能不支持该专有属性。
内容的提问来源于stack exchange,提问作者WesternGun
相关产品推荐
相关产品推荐

