如何从XPath中删除所有选定的节点?

7
我在Java中使用以下XML和代码运行XPath:
<?xml version="1.0" encoding="UTF-8"?>
<list>
    <member name="James">
        <friendlist>
            <friend>0001</friend>
            <friend>0002</friend>
            <friend>0003</friend>
        </friendlist>
    </member>
    <member name="Jamie">
        <friendlist>
            <friend>0003</friend>
            <friend>0002</friend>
            <friend>0001</friend>
        </friendlist>
    </member>
    <member name="Katie">
        <friendlist>
            <friend>0001</friend>
            <friend>0003</friend>
            <friend>0004</friend>
        </friendlist>
    </member>
</list>

代码:
try {
    XPath xpath = XPathFactory.newInstance().newXPath();
    XPathExpression pathExpr = xpath.compile("/list/member/friendlist/friend[.='0003']");
} catch (XPathExpressionException e) {

当然,这之后还有更多的代码,但我没有粘贴在这里,因为我认为这样可能会更加混乱。
但是想法是,我希望从所有成员的好友列表节点中选择所有具有ID 0003的好友节点,然后将其从XML文件中删除。XPath通过选择所有具有value=0003的“friend”节点来工作。我知道我可以使用XML文档对象的removeChild()方法。但问题是如何直接删除所有内容,而不需要从其父级开始进行层层嵌套循环?removeChild()方法需要我知道父级的父级的父级。
谢谢!
更新: 这就是我使用XPath的方式:
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression pathExpr = null;
try {
    pathExpr = xpath.compile("/list/member/friendlist/friend[.='0003']");
} catch (XPathExpressionException e) {
    e.printStackTrace();
}
NodeList list = null;
try {
    list = (NodeList) pathExpr.evaluate(xmlDoc, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
    e.printStackTrace();
}

xmlDoc是一个XML文档对象,其中包含解析的XML文件。XML工作正常。问题在于它不返回引用,而是返回一个全新的节点列表,这使我无法回到原始的XML文档进行修改。

xmlDoc是一个org.w3c.Document对象吗? - jtahlborn
是的,xmlDoc是一个常规的org.w3c.Document对象。 - Carven
你是在使用JDK中的XPath支持,还是其他第三方库?(例如,你的XPath实例的实际类名是什么) - jtahlborn
我正在使用来自JDK的XPath。我从未使用过任何第三方库。我的XPath实例的类路径是javax.xml.xpath.XPath。 - Carven
不是公共API,我的意思是_actual_实现类(例如xpath.getClass()). - jtahlborn
我想我弄清楚了发生了什么。jtahlborn是正确的,他的方法有效。我得到null的原因是因为当我尝试获取一个父节点是整个文档的主根节点时,它会给出一个null文档。但这没关系,经过一些试错,只要我在列表上再创建一个虚拟节点层级,将其下移一级,我就可以获得一个有效的父节点来删除它。谢谢! - Carven
3个回答

10

对于返回的NodeList中的每个节点:

n.getParentNode().removeChild(n);

显然,当我执行n.getParentNode()时,它返回一个空的xml。因此,当我执行n.getParentNode().removeChild(n)时,由于某种原因getParentNode()返回了一个null值,我会得到一个nullpointerexception。似乎Xpath返回另一组xml数据,并没有引用实际的xml文档对象。是否有什么我必须做才能使其工作?谢谢! - Carven
@xEnOn - 嗯,既然您没有包含任何相关代码,那么很难给出更进一步的建议了... - jtahlborn
在大多数常见的XML代码中,从XML文档对象执行标准过程的n.getParentNode().removeChild(n)方法完美地工作。只有当我通过XPath从XPathFactory查询节点列表时,工厂类似乎返回了一个新的节点列表,而不是对原始XML文档对象中原始节点的引用。因此,当我使用n.getParentNode()时,返回的数据是不正确的,removeChild将无法正常工作。 - Carven
@xEnOn - 你是如何调用xpath的? - jtahlborn
我已经在帖子底部更新了如何调用xpath的问题。感谢任何帮助。 - Carven

3
我不明白为什么返回的节点列表中parentNode()为null。
但你可以先使用以下XPath表达式选择要删除的节点的所有父节点:
"/list/member/friendlist[friend[.='0003']]"

或者等价物,
"/list/member/friendlist[friend = '0003']]"

然后遍历生成的节点列表,并在每个节点的上下文中查询与XPath表达式匹配的节点。
"friend[.='0003']"

那会给你一个父节点和一个子节点,可以与 removeChild() 一起使用。

1
谢谢!我也尝试了你的方法,它也有效!聪明的技巧! - Carven

1

看一下XUpdate。它不够美观,但是它能用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接