代码之家  ›  专栏  ›  技术社区  ›  WesternGun

XML转换器-设置OutputKeys。具有复杂外部实体声明的DOCTYPE_SYSTEM:无法删除最后的双引号

  •  0
  • WesternGun  · 技术社区  · 3 年前

    在我的变压器中,我有这样的配置:

    trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "MLP_SVC_RESULT_320.DTD [<!ENTITY % extension SYSTEM \"company_mlp320_slia_extension.dtd\"> %extension;]");
    

    这给了我一个错误:

    [Fatal Error] :1:121: The document type declaration for root element type "svc_result" must end with '>'.
    org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: xxx; The document type declaration for root element type "svc_result" must end with '>'.
    

    因为它增加了一个额外的 " 在我的DOCTYPE行的末尾:

    <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svc_result SYSTEM "MLP_SVC_RESULT_320.DTD [<!ENTITY % extension SYSTEM "company_mlp320_slia_extension.dtd"> %extension;]">
    

    注意最后一个 " ,它不可能存在;正确的XML不包含它。

    但我不知道如何在正确的配置下删除它。

    一个正确的XML示例:

    <?xml version="1.0" ?>
    <!DOCTYPE svc_result SYSTEM "MLP_SVC_RESULT_320.DTD" [<!ENTITY % extension SYSTEM "company_mlp320_slia_extension.dtd"> %extension;]>
    <svc_result ver="3.2.0">
        <slia ver="3.0.0">
            <pos>
                <msid type="MSISDN" enc="ASC">200853000105614</msid>
                <gsm_net_param>
                    <cgi>
                        <mcc>100</mcc>
                        <mnc>01</mnc>
                        <lac>2222</lac>
                        <cellid>10002</cellid>
                    </cgi>
                    <neid>
                        <vmscid>
                            <vmscno>00004946000</vmscno>
                        </vmscid>
                        <vlrid>
                            <vlrno>99994946000</vlrno>
                        </vlrid>
                    </neid>
                </gsm_net_param>
            </pos>
            <company_mlp320_slia>
                <company_netinfo>
                    <company_ms_netinfo type="CGI">
                        <msid type="MSISDN" enc="ASC">200853000105614</msid>
                        <time utc_off="+0200">20210521170211</time>
                    </company_ms_netinfo>
                </company_netinfo>
            </company_mlp320_slia>
        </slia>
    </svc_result>
    
    

    完整代码:

        private String transformToString(Document document) {
            if (document == null) {
                return null;
            }
            document.setXmlStandalone(true); // make document to be standalone, so we can avoid outputing standalone="no" in first line
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer trans;
            try {
                trans = tf.newTransformer();
                trans.setOutputProperty(OutputKeys.INDENT, "no"); // no extra indent; file already has intent of 4
                trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "MLP_SVC_RESULT_320.DTD [<!ENTITY % extension SYSTEM \"company_mlp320_slia_extension.dtd\"> %extension;]");
                StringWriter sw = new StringWriter();
                trans.transform(new DOMSource(document), new StreamResult(sw));
                // Spaces between tags are considered as text node, so when outputing we need to remove the extra empty lines
                return sw.toString().replaceAll("\\n\\s*\\n", "\n");
            } catch (TransformerException e) {
                LOG.error("Cannot transform response document to String. ", e);
                return null;
            }
        }
    
    0 回复  |  直到 3 年前
        1
  •  1
  •   Michael Kay    3 年前

    序列化属性DOCTYPE_SYSTEM用于输出DOCTYPE声明中的系统ID。您试图滥用它来注入整个DTD,而处理器不会让您逃脱惩罚。

    XSLT没有将DTD注入序列化输出的内置机制。除非你数 disable-output-escaping ,这是一个破解,但可能会解决问题。

    Saxon(PE及以上)有扩展指令 saxon:doctype 绕过这个限制(尽管这不是一个完美的解决方案,但它也有自己的局限性)。