如何防止DOM库规范化XML命名空间?

时间:2015-03-27 11:40:51

标签: xml normalization transformation xml-namespaces jdom

我有一个这样的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);

我发现如果我转储 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>

两个名称空间声明 sec ser 已被移动到第一次使用它们的位置。 虽然这种规范化是正确的,但我希望DOM和JDOM停止这样做,并保留我的文档: - )

有关如何实现这一目标的任何建议吗?

1 个答案:

答案 0 :(得分:0)

我不确定我是否相信你,至少在谈到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);
}

将您的文档作为&#34; soap.xml&#34;,我得到输出:

<?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声明,但是,如果你&#34;移动&#34;将元素放入未继承命名空间的位置,它将在需要的位置声明它。让我解释一下......

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

以上将输出虚拟文档两次,一次使用命名空间的as-need声明,第二次将声明添加到根元素:

<?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非常有能力做你想做的事。