1、删除节点删不掉的问题

最近在写计算两个XML的差量(diff)与合并差量(patch)的逻辑,其中差量有一种情况就是删除了某个节点,但在使用dom4j的remove(Element element)方法删除某个节点时遇到删除不掉的情况,场景如下:
  • 节点的XML数据
<Node id="test" type="Control">
    <Object name="测试" as="properties">
        <Object demon="true" as="spirit"/>
        <Object as="group">
            <Array as="items">
                <Object name="item-name" defaultValue=""  description="Xxx"/>
            </Array>
        </Object>
    </Object>
</Node>
  • 代码
SAXReader reader = new SAXReader();
Document document = reader.read(XmlTest.class.getResourceAsStream("/Node.xml"));
Element root = document.getRootElement();
Element element = (Element) root.selectSingleNode("/Node/Object/Object[2]/Array/Object");
System.out.println(element.asXML());
System.out.println(root.remove(element));//false
System.out.println(root.asXML());

在上述代码中,我是直接使用root删除选中的元素的,但remove()方法返回了false,删除失败。

上网查了下dom4j的API,如下:

其中Removes the given Element if the node is an immediate child of this branch. If the given node is not an immediate child of this branch then the Node.detach()method should be used instead.使用谷歌翻译后的结果如下:

如果节点是此分支的直接子节点,则删除给定的元素。 如果给定节点不是此分支的直接子节点,则应使用Node.detach()方法。

也就是说调用remove()方法删除时,删除的节点必须是被删除节点的子节点,否则的话应该调用detach()方法。所以正确的处理方法如下:

  • 解决方法
element.getParent().remove(element);
//或
element.detach();

2、使用createCopy()后选择失效问题

还是使用上面的XML数据,程序如下:

SAXReader reader = new SAXReader();
Document document = reader.read(XmlTest.class.getResourceAsStream("/Node.xml"));
Element root = document.getRootElement();
Element element = (Element) root.selectSingleNode("/Node/Object/Object[@as=\"group\"]");
System.out.println(element);

Element copy = root.createCopy();
Node node = copy.selectSingleNode(element.getUniquePath());
System.out.println(node);//null

运行上面的程序,第二个输出为null

查了API,只是说copy后的元素与其父元素分离,getParent()方法会返回null,但不知这个对selectSingleNode()方法有何影响,最后在StackOverflow上找到了答案:选取不到是因为dom4j需要Document元素来解析命名空间及其前缀等,因此要想正确选择出元素,首先需要将copy后的元素添加到document中:

Element copy = root.createCopy();
DocumentHelper.createDocument().add(copy);
Node node = copy.selectSingleNode(element.getUniquePath());
System.out.println(node);
注:程序需要依赖dom4j和’jaxen’
参考资料