如何使用 JAVA 删除 XML 中的节点

Posted

技术标签:

【中文标题】如何使用 JAVA 删除 XML 中的节点【英文标题】:How to remove a node in XML using JAVA 【发布时间】:2014-07-28 18:33:04 【问题描述】:

我使用的XML文件是这样的,注意有4个'target'标签。

<?xml version="1.0" encoding="UTF-8" standalone="no"?><project basedir="." default="end" name="precompile">
<property name="charset" value="utf-8"/>

<target name="start">
</target>

<target depends="precompile-templates1,precompile-templates2" name="end">
    <echo>finish generating precompiled templates</echo>
</target>



<target name="precompile-templates1">
      <property name="outputJS1" value="jsp/jsp_2/js/templates.js"/>
      <property name="templatesPath1" value="jsp/jsp_2/js/tmpl"/>

      <java dir="$basedir" failonerror="true" fork="true" jar="lib/js.jar">
        <arg value="otherFiles/lib/rhino-handlebars-compiler.js"/>
        <arg value="--handlebars"/>
        <arg value="otherFiles/third-party/handlebars-v1.3.0.js"/>
        <arg value="--templates"/>
        <arg value="$templatesPath1"/>
        <arg value="--output"/>
        <arg value="$outputJS1"/>
      </java>
      <echo>Template Precompiled to web/js/compiled-templates.js</echo>
        <echo> is now ready to compress....</echo>
</target>

<target name="precompile-templates2">
        <property name="outputJS2" value="jsp/jsp_3/js/templates.js"/>
        <property name="templatesPath2" value="jsp/jsp_3/js/tmpl"/>

        <java dir="$basedir" failonerror="true" fork="true" jar="lib/js.jar">
        <arg value="otherFiles/lib/rhino-handlebars-compiler.js"/>
        <arg value="--handlebars"/>
        <arg value="otherFiles/third-party/handlebars-v1.3.0.js"/>
        <arg value="--templates"/>
        <arg value="$templatesPath2"/>
        <arg value="--output"/>
        <arg value="$outputJS2"/>
      </java>
      <echo>Template Precompiled to web/js/compiled-templates.js</echo>
        <echo> is now ready to compress....</echo>
</target></project>

我想保留前 2 个“目标”节点,但删除“目标”的其余 2 个节点。我该怎么办?我试图做这样的事情:

File fXmlFile = new File(subBuildFile);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder  dBuilder = dbFactory.newDocumentBuilder();
Document  doc = dBuilder.parse(fXmlFile);

Node s = doc.getElementsByTagName("target").item(1);

for(int i =2; i<doc.getElementsByTagName("target").getLength();i++)
    doc.getElementsByTagName("target").item(i).removeChild(doc.getElementsByTagName("target").item(i));

但总是有类似这样的错误:

Exception in thread "main" org.w3c.dom.DOMException: NOT_FOUND_ERR: An attempt is made to reference a node in a context where it does not exist.
at com.sun.org.apache.xerces.internal.dom.ParentNode.internalRemoveChild(Unknown Source)
at com.sun.org.apache.xerces.internal.dom.ParentNode.removeChild(Unknown Source)
at xmlReader.Test.resetXML(Test.java:52)
at xmlReader.Test.main(Test.java:39)

有什么建议吗?

加: 当我使用以下代码时有些奇怪:

System.out.println("the number of target tag is "+doc.getElementsByTagName("target").getLength());

    for(int i =2; i<targets.getLength();i++)
        root.removeChild(targets.item(2));
        System.out.println(i);


    

    System.out.println(doc.getElementsByTagName("target").getLength());

我使用的 XML 是这样的:

 <target name="start">
 </target>

<target depends="precompile-templates1,precompile-templates2" name="end">
    <echo>finish generating precompiled templates</echo>
</target>










<target id="2">
</target>
<target id="3">
</target>
<target id="4">
</target>

<target id="5">
</target>
<target id="6">
</target>

<target id="7">
</target>
<target id="8">
</target>
<target id="9">
</target>
<target id="10">
</target>
<target id="11">
</target>
<target id="12">
</target>
<target id="13">
</target>


















</project>

输出将是这样的:

the number of target tag is 8
2
3
4
5

最终输出的 XML 是这样的:

<target name="start">
</target>

<target depends="precompile-templates1,precompile-templates2" name="end">
    <echo>finish generating precompiled templates</echo>
</target>





















<target id="11">
</target>
<target id="12">
</target>
<target id="13">
</target>
</project>

【问题讨论】:

【参考方案1】:

表达式

doc.getElementsByTagName("target").item(i)

选择&lt;target&gt;,您不能从中删除&lt;target&gt;

Element root = doc.getDocumentElement(); // should be <project>
NodeList targets = doc.getElementsByTagName("target");
root.removeChild( targets.item( 3 ) );
root.removeChild( targets.item( 2 ) );

在 2 上没有硬连线的更通用的代码是:

int toKeep = 2;
int toDelete = targets.getLength() - toKeep;
for(int i = 0; i < toDelete; i++)
root.removeChild(targets.item(toKeep));

请注意(与您的代码相比)要删除的目标元素的数量是预先计算的。用列表长度的变化来限制它会产生一种奇怪的效果。

【讨论】:

这会失败,因为删除第 2 项后,只有 3 个元素。那么应该是两次root.removeChild( targets.item( 2 ) ); @mpromonet 我不确定提取列表中的索引是否会保留。交换语句应该避免这个问题。谢谢。

以上是关于如何使用 JAVA 删除 XML 中的节点的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Xpath 表达式仅删除 XML 中的空节点?

如何根据节点值使用php删除xml中的元素[重复]

使用 Linq 删除 XML 中的子节点

如何删除不在 xpath 字符串数组中的 xml 节点?

如何使用java让XML节点中的属性换行?如下所示!

如何使用 C# 从 XML 节点列表中删除节点