从 Java 中的 XML 删除重复的命名空间
Remove Duplicate Namespaces from XML in Java
我有以下肥皂反应示例:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:mycompany:Service:2" xmlns:urn1="urn:mycompany:Customer:2">
<soapenv:Header />
<soapenv:Body>
<urn:GetResponse>
<urn:StatusCode>002</urn:StatusCode>
<urn:StatusMessage>Pass</urn:StatusMessage>
<urn:CustomerAffiliations>
<urn:CustomerAffiliation>
<urn:CustomerID>II39642</urn:CustomerID>
<urn:CustomerContactDetails>
<ns3:Channel xmlns:ns3="urn:mycompany:Customer:2">Business Phone</ns3:Channel>
<ns3:Value xmlns:ns3="urn:mycompany:Customer:2">5553647</ns3:Value>
</urn:CustomerContactDetails>
</urn:CustomerAffiliation>
</urn:CustomerAffiliations>
</urn:GetResponse>
</soapenv:Body>
</soapenv:Envelope>
urn:mycompany:Customer:2
已作为 urn1
包含在 soapenv:Envelope
中,但在 ns3:Channel
和 ns3:Value
中重复了。
要求清理 xml 内容,以便在 soapenv:Envelope
中声明的正确命名空间用于子元素。
在 Java 中是否有办法 clean/normalize 此 xml 内容并使用正确的命名空间用法和重复删除?
以下代码将仅用元素的继承版本替换 "duplicated" 命名空间(属性也可以有自己的命名空间)....
请注意,这有一些可怕的时间复杂性,因此对于较大的 XML 文档,这可能会严重退化....所以不要在深度嵌套或大于几百的文档上使用它元素...在某些时候,时间复杂度会咬你。
另一方面,对于像您的 SOAP 示例这样的小数据包,这将绰绰有余...
private static final Namespace findFirst(List<Namespace> namespaces, String uri) {
for (Namespace ns : namespaces) {
if (ns.getURI().equals(uri)) {
return ns;
}
}
return null;
}
public static final void dedupElementNamespaces(Element node) {
List<Namespace> created = node.getNamespacesIntroduced();
if (!created.isEmpty()) {
// check anything new against other stuff...
List<Namespace> inherited = node.getNamespacesInherited();
// check out element against previous declarations....
if (node.getNamespace().getPrefix() != "") {
// never swap defaulted namespaces to anything with a prefix.
Namespace ens = node.getNamespace();
Namespace use = findFirst(inherited, node.getNamespaceURI());
if (use != null && use != ens) {
node.setNamespace(use);
}
}
}
for (Element e : node.getChildren()) {
dedupElementNamespaces(e);
}
}
你可以这样调用:
dedupElementNamespaces(doc.getRootElement());
node.getNamespacesIntroduced()
和 node.getNamespacesInherited()
方法通过向上扫描 XML 层次结构来动态计算列表...因此它们的性能取决于嵌套的深度。参见 https://github.com/hunterhacker/jdom/blob/master/core/src/java/org/jdom2/Element.java#L1753
我有以下肥皂反应示例:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:mycompany:Service:2" xmlns:urn1="urn:mycompany:Customer:2">
<soapenv:Header />
<soapenv:Body>
<urn:GetResponse>
<urn:StatusCode>002</urn:StatusCode>
<urn:StatusMessage>Pass</urn:StatusMessage>
<urn:CustomerAffiliations>
<urn:CustomerAffiliation>
<urn:CustomerID>II39642</urn:CustomerID>
<urn:CustomerContactDetails>
<ns3:Channel xmlns:ns3="urn:mycompany:Customer:2">Business Phone</ns3:Channel>
<ns3:Value xmlns:ns3="urn:mycompany:Customer:2">5553647</ns3:Value>
</urn:CustomerContactDetails>
</urn:CustomerAffiliation>
</urn:CustomerAffiliations>
</urn:GetResponse>
</soapenv:Body>
</soapenv:Envelope>
urn:mycompany:Customer:2
已作为 urn1
包含在 soapenv:Envelope
中,但在 ns3:Channel
和 ns3:Value
中重复了。
要求清理 xml 内容,以便在 soapenv:Envelope
中声明的正确命名空间用于子元素。
在 Java 中是否有办法 clean/normalize 此 xml 内容并使用正确的命名空间用法和重复删除?
以下代码将仅用元素的继承版本替换 "duplicated" 命名空间(属性也可以有自己的命名空间)....
请注意,这有一些可怕的时间复杂性,因此对于较大的 XML 文档,这可能会严重退化....所以不要在深度嵌套或大于几百的文档上使用它元素...在某些时候,时间复杂度会咬你。
另一方面,对于像您的 SOAP 示例这样的小数据包,这将绰绰有余...
private static final Namespace findFirst(List<Namespace> namespaces, String uri) {
for (Namespace ns : namespaces) {
if (ns.getURI().equals(uri)) {
return ns;
}
}
return null;
}
public static final void dedupElementNamespaces(Element node) {
List<Namespace> created = node.getNamespacesIntroduced();
if (!created.isEmpty()) {
// check anything new against other stuff...
List<Namespace> inherited = node.getNamespacesInherited();
// check out element against previous declarations....
if (node.getNamespace().getPrefix() != "") {
// never swap defaulted namespaces to anything with a prefix.
Namespace ens = node.getNamespace();
Namespace use = findFirst(inherited, node.getNamespaceURI());
if (use != null && use != ens) {
node.setNamespace(use);
}
}
}
for (Element e : node.getChildren()) {
dedupElementNamespaces(e);
}
}
你可以这样调用:
dedupElementNamespaces(doc.getRootElement());
node.getNamespacesIntroduced()
和 node.getNamespacesInherited()
方法通过向上扫描 XML 层次结构来动态计算列表...因此它们的性能取决于嵌套的深度。参见 https://github.com/hunterhacker/jdom/blob/master/core/src/java/org/jdom2/Element.java#L1753