没有命名空间和前缀的克隆 XML
Clone XML without Namespace and prefix
我有 xml 个带有命名空间和前缀的文件。我想删除那些名称空间和前缀,并使用 java 将其转换为纯 xml。
在过去的几天里,我已经厌倦了使用公理。到目前为止还没有成功。
由于 axiom 不支持删除命名空间(declaredNamespace iterator.remove() 不起作用)我尝试克隆并删除命名空间。这不适用于遍历迭代器。
OMElement oe = fac.createOMElement(new QName(omElement.getQName().getLocalPart()));
Iterator internalIt = omElement.getChildren();
if (internalIt.hasNext()) {
while (internalIt.hasNext()) {
OMNode onode = (OMNode) ((OMNode) internalIt.next()).clone(new OMCloneOptions());
oe.addChild((OMNode) onode);
omElement.getParent().addChild(oe);
}
} else {
omElement.getParent().addChild(oe);
}
现在我想在遍历原始文档的同时创建其他文档。值应该相同,唯一的区别是删除 namespace/prefix 并将主元素键属性值连接到每个元素。
来源
<root>
<a key="A">
<c:b xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">
<c>
<c:x xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">111</c:x>
<c:y xmlns:c="http://abc">2222</c:y>
<z>33333</z>
</c>
<c:d xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">sss</c:d>
</c:b>
<e>
<K></K>
<L></L>
</e>
</a>
<a key="B">
<c:b xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">
<c>
<c:x xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">3333</c:x>
<c:y xmlns:c="http://abc">6666</c:y>
<z>aaaaa</z>
</c>
<c:d xmlns:c="http://schemas.xmlsoap.org/soap/envelope/"></c:d>
</c:b>
<e>
<K>54</K>
<L>fff</L>
</e>
</a>
预期输出
<root>
<a>
<A_b>
<A_c>
<A_x>111</A_x>
<A_y>2222</A_y>
<A_z>33333</A_z>
</A_c>
<A_d>sss</A_d>
</A_b>
<A_e>
<A_K></A_K>
<A_L></A_L>
</A_e>
</a>
<a>
<B_b>
<B_c>
<B_x>3333</B_x>
<B_y>6666</B_y>
<B_z>aaaaa</B_z>
</B_c>
<B_d></B_d>
</B_b>
<B_e>
<B_K>54</B_K>
<B_L>fff</B_L>
</B_e>
</a>
如果我可以使用 AXIOM 执行此操作会更好,因为它是已经批准的库。但我可以在任何图书馆完成这项工作。任何帮助将不胜感激。
这是我的答案,大量使用了 XPath 和 VTD-XML...
import com.ximpleware.*;
import java.io.*;
public class removeNameSpaces {
public static void main(String[] args) throws VTDException,IOException {
// TODO Auto-generated method stub
VTDGen vg = new VTDGen();
AutoPilot ap = new AutoPilot(),
ap3=new AutoPilot(),
ap4=new AutoPilot(),
ap5= new AutoPilot();
ap.selectXPath("/root/a");
ap3.selectXPath("@key");
ap4.selectXPath("descendant::*");
ap5.selectXPath("//@*");
if (!vg.parseFile("d:\xml\oo.xml", false))
return;
VTDNav vn = vg.getNav();
ap.bind(vn);ap3.bind(vn);
ap4.bind(vn);ap5.bind(vn);
XMLModifier xm = new XMLModifier(vn);
// remove all attribute from xml file
int i=0,j=0;
while((i=ap5.evalXPath())!=-1){
xm.remove();
}
String keyName;String elementName;
// update names of all the element nodes under /root/a
while((i=ap.evalXPath())!=-1){
keyName= ap3.evalXPathToString();
vn.push();
while((j=ap4.evalXPath())!=-1){
elementName = vn.toRawString(j);
int offset = elementName.indexOf(':');
String newElementName = keyName+"_"+((offset==-1)?elementName: elementName.substring(offset+1)) ;
xm.updateElementName(newElementName);
}
ap4.resetXPath();
vn.pop();
}
xm.output("d:\xml\ooo.xml");
}
}
我的 XML 的输出是
<root>
<a >
<A_b >
<A_c>
<A_x >111</A_x>
<A_y >2222</A_y>
<A_z>33333</A_z>
</A_c>
<A_d >sss</A_d>
</A_b>
<A_e>
<A_K></A_K>
<A_L></A_L>
</A_e>
</a>
<a >
<B_b >
<B_c>
<B_x >3333</B_x>
<B_y >6666</B_y>
<B_z>aaaaa</B_z>
</B_c>
<B_d ></B_d>
</B_b>
<B_e>
<B_K>54</B_K>
<B_L>fff</B_L>
</B_e>
</a>
</root>
删除命名空间声明是不够的,因为树中的 OMElement
实例仍然保留它们的命名空间(并且在序列化期间,Axiom 自动生成必要的命名空间声明,以便它们在输出文档中具有这些命名空间).您还需要调用 setNamespace
来更改它们:
OMDocument document = ...
for (Iterator it = document.getDescendants(false); it.hasNext(); ) {
OMNode node = (OMNode)it.next();
if (node instanceof OMElement) {
OMElement element = (OMElement)node;
element.setNamespace(null, false); // <-- this actually changes the namespace of the element
for (Iterator it2 = element.getAllDeclaredNamespaces(); it2.hasNext(); ) {
it2.next();
it2.remove();
}
}
}
我有 xml 个带有命名空间和前缀的文件。我想删除那些名称空间和前缀,并使用 java 将其转换为纯 xml。 在过去的几天里,我已经厌倦了使用公理。到目前为止还没有成功。 由于 axiom 不支持删除命名空间(declaredNamespace iterator.remove() 不起作用)我尝试克隆并删除命名空间。这不适用于遍历迭代器。
OMElement oe = fac.createOMElement(new QName(omElement.getQName().getLocalPart()));
Iterator internalIt = omElement.getChildren();
if (internalIt.hasNext()) {
while (internalIt.hasNext()) {
OMNode onode = (OMNode) ((OMNode) internalIt.next()).clone(new OMCloneOptions());
oe.addChild((OMNode) onode);
omElement.getParent().addChild(oe);
}
} else {
omElement.getParent().addChild(oe);
}
现在我想在遍历原始文档的同时创建其他文档。值应该相同,唯一的区别是删除 namespace/prefix 并将主元素键属性值连接到每个元素。
来源
<root>
<a key="A">
<c:b xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">
<c>
<c:x xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">111</c:x>
<c:y xmlns:c="http://abc">2222</c:y>
<z>33333</z>
</c>
<c:d xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">sss</c:d>
</c:b>
<e>
<K></K>
<L></L>
</e>
</a>
<a key="B">
<c:b xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">
<c>
<c:x xmlns:c="http://schemas.xmlsoap.org/soap/envelope/">3333</c:x>
<c:y xmlns:c="http://abc">6666</c:y>
<z>aaaaa</z>
</c>
<c:d xmlns:c="http://schemas.xmlsoap.org/soap/envelope/"></c:d>
</c:b>
<e>
<K>54</K>
<L>fff</L>
</e>
</a>
预期输出
<root>
<a>
<A_b>
<A_c>
<A_x>111</A_x>
<A_y>2222</A_y>
<A_z>33333</A_z>
</A_c>
<A_d>sss</A_d>
</A_b>
<A_e>
<A_K></A_K>
<A_L></A_L>
</A_e>
</a>
<a>
<B_b>
<B_c>
<B_x>3333</B_x>
<B_y>6666</B_y>
<B_z>aaaaa</B_z>
</B_c>
<B_d></B_d>
</B_b>
<B_e>
<B_K>54</B_K>
<B_L>fff</B_L>
</B_e>
</a>
如果我可以使用 AXIOM 执行此操作会更好,因为它是已经批准的库。但我可以在任何图书馆完成这项工作。任何帮助将不胜感激。
这是我的答案,大量使用了 XPath 和 VTD-XML...
import com.ximpleware.*;
import java.io.*;
public class removeNameSpaces {
public static void main(String[] args) throws VTDException,IOException {
// TODO Auto-generated method stub
VTDGen vg = new VTDGen();
AutoPilot ap = new AutoPilot(),
ap3=new AutoPilot(),
ap4=new AutoPilot(),
ap5= new AutoPilot();
ap.selectXPath("/root/a");
ap3.selectXPath("@key");
ap4.selectXPath("descendant::*");
ap5.selectXPath("//@*");
if (!vg.parseFile("d:\xml\oo.xml", false))
return;
VTDNav vn = vg.getNav();
ap.bind(vn);ap3.bind(vn);
ap4.bind(vn);ap5.bind(vn);
XMLModifier xm = new XMLModifier(vn);
// remove all attribute from xml file
int i=0,j=0;
while((i=ap5.evalXPath())!=-1){
xm.remove();
}
String keyName;String elementName;
// update names of all the element nodes under /root/a
while((i=ap.evalXPath())!=-1){
keyName= ap3.evalXPathToString();
vn.push();
while((j=ap4.evalXPath())!=-1){
elementName = vn.toRawString(j);
int offset = elementName.indexOf(':');
String newElementName = keyName+"_"+((offset==-1)?elementName: elementName.substring(offset+1)) ;
xm.updateElementName(newElementName);
}
ap4.resetXPath();
vn.pop();
}
xm.output("d:\xml\ooo.xml");
}
}
我的 XML 的输出是
<root>
<a >
<A_b >
<A_c>
<A_x >111</A_x>
<A_y >2222</A_y>
<A_z>33333</A_z>
</A_c>
<A_d >sss</A_d>
</A_b>
<A_e>
<A_K></A_K>
<A_L></A_L>
</A_e>
</a>
<a >
<B_b >
<B_c>
<B_x >3333</B_x>
<B_y >6666</B_y>
<B_z>aaaaa</B_z>
</B_c>
<B_d ></B_d>
</B_b>
<B_e>
<B_K>54</B_K>
<B_L>fff</B_L>
</B_e>
</a>
</root>
删除命名空间声明是不够的,因为树中的 OMElement
实例仍然保留它们的命名空间(并且在序列化期间,Axiom 自动生成必要的命名空间声明,以便它们在输出文档中具有这些命名空间).您还需要调用 setNamespace
来更改它们:
OMDocument document = ...
for (Iterator it = document.getDescendants(false); it.hasNext(); ) {
OMNode node = (OMNode)it.next();
if (node instanceof OMElement) {
OMElement element = (OMElement)node;
element.setNamespace(null, false); // <-- this actually changes the namespace of the element
for (Iterator it2 = element.getAllDeclaredNamespaces(); it2.hasNext(); ) {
it2.next();
it2.remove();
}
}
}