通常,使用dom4j对整体XML的节点、属性等作统一处理时,会使用VisitorSupport类并扩展visit方法来实现。如要清除XML文档中的所有名称空间,我们的基本原理是:
Documentdoc =DocumentHelper.parseText(str);
doc.accept(newNamespaceCleaner());
…
其中NamespaceCleaner类为如下内容:
public classNamespaceCleaner extendsVisitorSupport {
public voidvisit(Document document) {
((DefaultElement)document.getRootElement()).setNamespace(Namespace.NO_NAMESPACE); document.getRootElement().additionalNamespaces().clear();
}
public voidvisit(Namespace namespace) {
namespace.detach();
}
public void visit(Attribute attr) {
if (attr.toString().contains("xmlns")
|| attr.toString().contains("xsi:")){
attr.detach();
}
}
public voidvisit(Element node) {
if(nodeinstanceofDefaultElement) {
((DefaultElement) node).setNamespace(Namespace.NO_NAMESPACE);
}
}
}
注意此类中的visit(Attribute attr)部分,此方法的目的是想删除名称中带有xmlns或xsi:的属性,表面上看起来与其它方法无异,且逻辑上可以理解的。
但是,此方法中attr.detach()会引起IndexOutOfBoundsException异常,原因是此方法的参数attr是由在外面的其attr.getParent().attributes()的一个List列表,当我们将attr.detach(),此时就意味着该list的size会发生变化,从而导致其运行时会越界。
对此,我们可以通过visit(Elementnode)方法去处理属性列表,我们的解决方案是:
public classNamespaceCleaner extendsVisitorSupport {
public voidvisit(Document document) {
((DefaultElement)document.getRootElement()).setNamespace(Namespace.NO_NAMESPACE);
document.getRootElement().additionalNamespaces().clear();
}
public voidvisit(Namespace namespace) {
namespace.detach();
}
public voidvisit(Element node) {
if(nodeinstanceofDefaultElement) {
((DefaultElement)node).setNamespace(Namespace.NO_NAMESPACE);
}
@SuppressWarnings("unchecked")
List<Attribute> list =node.attributes();
for( inti=0;i<node.attributes().size(); ++i ){
Attribute attr = list.get(i);
if(attr.toString().contains("xmlns")
|| attr.toString().contains("xsi:")) {
attr.detach();
--i;
}
}
}
}
记于此。