【问题标题】:How do I prevent DOM libraries from normalizing XML namespaces?如何防止 DOM 库规范化 XML 命名空间?
【发布时间】:2015-03-27 11:40:50
【问题描述】:

我有一个这样的 XML 文档:

 <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:sec="http://namespace1" xmlns:ser="http://namespace2">
    <soap:Header>
        <sec:RequestHeader>
            <sec:SenderId>ABCD</sec:SenderId>
            <sec:SignerId1>ABCD</sec:SignerId1>
            <sec:SignerId2></sec:SignerId2>
            <sec:SignerId3></sec:SignerId3>
            <sec:DBCryptId></sec:DBCryptId>
            <sec:RequestId>CPMDDEV4110066</sec:RequestId>
            <sec:Timestamp>2015-03-24T15:40:00Z</sec:Timestamp>
            <sec:Language>DA</sec:Language>
        </sec:RequestHeader>
    </soap:Header>
    <soap:Body>
        <ser:GetStatus>
            <ser:dacGetStatusInput>
                <ser:MerchantId>A</ser:MerchantId>
                <ser:OrderId>B</ser:OrderId>
                <ser:CustomerId></ser:CustomerId>
                <ser:ActionCode>C</ser:ActionCode>
                <ser:Test>Y</ser:Test>
            </ser:dacGetStatusInput>
        </ser:GetStatus>
    </soap:Body>
</soap:Envelope>

无论我做什么,我都无法让 org.w3c.dom 或 JDom 停止对源文档中的命名空间进行规范化。

如果我尝试将顶部节点元素添加到新文档中,例如:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
org.w3c.dom.Document doc = builder.newDocument();
document = doc.importNode(document, true);
doc.appendChild(document);

我发现如果我dump了doc的内容,内容已经变成:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Header>
        <sec:RequestHeader xmlns:sec="http://namespace1">
            <sec:SenderId>ABCD</sec:SenderId>
            <sec:SignerId1>ABCD</sec:SignerId1>
            <sec:SignerId2/>
            <sec:SignerId3/>
            <sec:DBCryptId/>
            <sec:RequestId>CPMDDEV4110066</sec:RequestId>
            <sec:Timestamp>2015-03-24T15:40:00Z</sec:Timestamp>
            <sec:Language>DA</sec:Language>
        </sec:RequestHeader>
    </soap:Header>
    <soap:Body>
        <ser:GetStatus xmlns:ser="http://namespace2">
            <ser:dacGetStatusInput>
                <ser:MerchantId>A</ser:MerchantId>
                <ser:OrderId>B</ser:OrderId>
                <ser:CustomerId/>
                <ser:ActionCode>C</ser:ActionCode>
                <ser:Test>Y</ser:Test>
            </ser:dacGetStatusInput>
        </ser:GetStatus>
    </soap:Body>
</soap:Envelope>

secser 这两个命名空间声明已移至第一次使用的位置。 虽然这种规范化是正确的,但我希望 DOM 和 JDOM 停止这样做,让我的文档不理会 :-)

关于如何实现这一点的任何建议?

【问题讨论】:

    标签: xml normalization transformation xml-namespaces jdom


    【解决方案1】:

    我不确定我是否相信你,至少在 JDOM 方面是这样。如果我运行以下代码:

    public static void main(String[] args) throws JDOMException, IOException {
        Document doc = new SAXBuilder().build("soap.xml");
    
        XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
        xout.output(doc, System.out);
    }
    

    您的文档为“soap.xml”,我得到输出:

    <?xml version="1.0" encoding="UTF-8"?>
    <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:sec="http://namespace1" xmlns:ser="http://namespace2">
      <soap:Header>
        <sec:RequestHeader>
          <sec:SenderId>ABCD</sec:SenderId>
          <sec:SignerId1>ABCD</sec:SignerId1>
          <sec:SignerId2 />
          <sec:SignerId3 />
          <sec:DBCryptId />
          <sec:RequestId>CPMDDEV4110066</sec:RequestId>
          <sec:Timestamp>2015-03-24T15:40:00Z</sec:Timestamp>
          <sec:Language>DA</sec:Language>
        </sec:RequestHeader>
      </soap:Header>
      <soap:Body>
        <ser:GetStatus>
          <ser:dacGetStatusInput>
            <ser:MerchantId>A</ser:MerchantId>
            <ser:OrderId>B</ser:OrderId>
            <ser:CustomerId />
            <ser:ActionCode>C</ser:ActionCode>
            <ser:Test>Y</ser:Test>
          </ser:dacGetStatusInput>
        </ser:GetStatus>
      </soap:Body>
    </soap:Envelope>
    

    这是我所期望的。

    JDOM 尊重声明它们的元素上的xmlns 声明,但是,如果您将元素“移动”到不继承命名空间的位置,它将在需要的位置声明它。让我解释得更好......

        Document doc = new SAXBuilder().build("soap.xml");
        XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
        xout.output(doc, System.out);
    

    上面的代码只是读取并转储整个文档,但是,如果我们这样做(读取文档,提取子集,将子集添加到新文档,然后打印):

        Document doc = new SAXBuilder().build("soap.xml");
    
        XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
        //xout.output(doc, System.out);
    
        Namespace soap = Namespace.getNamespace("soap", "http://www.w3.org/2003/05/soap-envelope");
        Namespace sec = Namespace.getNamespace("sec", "http://namespace1");
    
        // locate, and extract rhead
        Element rhead = doc.getRootElement().getChild("Header", soap).getChild("RequestHeader", sec);
        rhead.detach();
    
        // add it to a new Soap doc.
        Element nroot = new Element("Dummy", soap);
        nroot.addContent(rhead);
        Document ndoc = new Document(nroot);
    
        // Print the new document
        xout.output(ndoc, System.out);
    
        //Now force-declare the namespace on the root element:
        nroot.addNamespaceDeclaration(sec);
    
        System.out.println("\nForced\n");
    
        xout.output(ndoc, System.out);
    

    上面将输出虚拟文档两次,一次是带有命名空间的按需声明,第二次是添加到根元素的声明:

    <?xml version="1.0" encoding="UTF-8"?>
    <soap:Dummy xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
      <sec:RequestHeader xmlns:sec="http://namespace1">
        <sec:SenderId>ABCD</sec:SenderId>
        <sec:SignerId1>ABCD</sec:SignerId1>
        <sec:SignerId2 />
        <sec:SignerId3 />
        <sec:DBCryptId />
        <sec:RequestId>CPMDDEV4110066</sec:RequestId>
        <sec:Timestamp>2015-03-24T15:40:00Z</sec:Timestamp>
        <sec:Language>DA</sec:Language>
      </sec:RequestHeader>
    </soap:Dummy>
    
    Forced
    
    <?xml version="1.0" encoding="UTF-8"?>
    <soap:Dummy xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:sec="http://namespace1">
      <sec:RequestHeader>
        <sec:SenderId>ABCD</sec:SenderId>
        <sec:SignerId1>ABCD</sec:SignerId1>
        <sec:SignerId2 />
        <sec:SignerId3 />
        <sec:DBCryptId />
        <sec:RequestId>CPMDDEV4110066</sec:RequestId>
        <sec:Timestamp>2015-03-24T15:40:00Z</sec:Timestamp>
        <sec:Language>DA</sec:Language>
      </sec:RequestHeader>
    </soap:Dummy>
    

    JDOM 完全有能力做你想做的事。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-05
      • 2012-08-30
      • 1970-01-01
      • 2014-03-31
      • 1970-01-01
      • 2021-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多