使用dom4j清理命名空间处理

Ant*_*val 8 java namespaces dom4j

我们正在使用dom4j 1.6.1来解析来自某个地方的XML.有时,应答器提到了命名空间(例如:),有时候没有().并且它调用Element.selectSingleNode(String s)失败.

目前我们有3个解决方案,我们对它们不满意

1 - 在对xml文档执行任何操作之前删除所有命名空间

xml = xml .replaceAll("xmlns=\"[^\"]*\"","");
xml = xml .replaceAll("ds:","");
xml = xml .replaceAll("etm:","");
[...] // and so on for each kind of namespace
Run Code Online (Sandbox Code Playgroud)

2 - 在获取节点之前删除命名空间通过调用

Element.remove(Namespace ns)
Run Code Online (Sandbox Code Playgroud)

但它仅适用于节点和第一级子节点

3 - 使代码混乱

node = rootElement.selectSingleNode(NameWithoutNameSpace)
if ( node == null )
    node = rootElement.selectSingleNode(NameWithNameSpace)
Run Code Online (Sandbox Code Playgroud)

所以你怎么看 ?女巫一个是不是更糟糕?你有其他解决方案吗?

mes*_*chs 6

我想删除任何名称空间信息(声明和标记)以简化xpath评估.我最终得到了这个解决方案:

String xml = ...
SAXReader reader = new SAXReader();
Document document = reader.read(new ByteArrayInputStream(xml.getBytes()));
document.accept(new NameSpaceCleaner());
return document.asXML();
Run Code Online (Sandbox Code Playgroud)

NameSpaceCleaner是dom4j访问者:

private static final class NameSpaceCleaner extends VisitorSupport {
    public void visit(Document document) {
        ((DefaultElement) document.getRootElement())
                .setNamespace(Namespace.NO_NAMESPACE);
        document.getRootElement().additionalNamespaces().clear();
    }
    public void visit(Namespace namespace) {
        namespace.detach();
    }
    public void visit(Attribute node) {
       if (node.toString().contains("xmlns")
        || node.toString().contains("xsi:")) {
        node.detach();
      }
    }

    public void visit(Element node) {
        if (node instanceof DefaultElement) {
        ((DefaultElement) node).setNamespace(Namespace.NO_NAMESPACE);
        }
         }
 }
Run Code Online (Sandbox Code Playgroud)


Abh*_*hek 5

以下是我发现并现在使用的一些代码。如果要寻找通用方法,从dom4j文档中删除所有名称空间可能很有用。

    public static void removeAllNamespaces(Document doc) {
        Element root = doc.getRootElement();
        if (root.getNamespace() !=
                Namespace.NO_NAMESPACE) {            
                removeNamespaces(root.content());
        }
    }

    public static void unfixNamespaces(Document doc, Namespace original) {
        Element root = doc.getRootElement();
        if (original != null) {
            setNamespaces(root.content(), original);
        }
    }

    public static void setNamespace(Element elem, Namespace ns) {

        elem.setQName(QName.get(elem.getName(), ns,
                elem.getQualifiedName()));
    }

    /**
     *Recursively removes the namespace of the element and all its
    children: sets to Namespace.NO_NAMESPACE
     */
    public static void removeNamespaces(Element elem) {
        setNamespaces(elem, Namespace.NO_NAMESPACE);
    }

    /**
     *Recursively removes the namespace of the list and all its
    children: sets to Namespace.NO_NAMESPACE
     */
    public static void removeNamespaces(List l) {
        setNamespaces(l, Namespace.NO_NAMESPACE);
    }

    /**
     *Recursively sets the namespace of the element and all its children.
     */
    public static void setNamespaces(Element elem, Namespace ns) {
        setNamespace(elem, ns);
        setNamespaces(elem.content(), ns);
    }

    /**
     *Recursively sets the namespace of the List and all children if the
    current namespace is match
     */
    public static void setNamespaces(List l, Namespace ns) {
        Node n = null;
        for (int i = 0; i < l.size(); i++) {
            n = (Node) l.get(i);

            if (n.getNodeType() == Node.ATTRIBUTE_NODE) {
                ((Attribute) n).setNamespace(ns);
            }
            if (n.getNodeType() == Node.ELEMENT_NODE) {
                setNamespaces((Element) n, ns);
            }            
        }
    }
Run Code Online (Sandbox Code Playgroud)

希望这对需要它的人有用!


Jhe*_*ico 1

选项 1 很危险,因为如果不预先解析文档,就无法保证给定命名空间的前缀,并且最终可能会导致命名空间冲突。如果您正在使用文档并且不输出任何内容,则可能没问题,具体取决于文档的来源,但否则它只会丢失太多信息。

选项 2 可以递归应用,但它有许多与选项 1 相同的问题。

选项 3 听起来是最好的方法,但不要让代码变得混乱,而是创建一个执行这两项检查的静态方法,而不是在整个代码库中放置相同的 if 语句。

最好的方法是让向您发送错误 XML 的人修复它。当然,这引出了一个问题:它是否真的坏了。具体来说,您是否正在获取默认命名空间定义为 X 的 XML,然后为代表 X 的命名空间赋予前缀“es”?如果是这种情况,则 XML 格式良好,您只需要与前缀无关的代码,但仍使用限定名称来获取元素。我对 Dom4j 不太熟悉,不知道创建带有 null 前缀的命名空间是否会导致它匹配具有匹配 URI 的所有元素或仅匹配那些没有前缀的元素,但它值得尝试。