Не удается удалить элемент и дочерний элемент из документа XML с помощью кода Java

Это мой документ XML:

<definitions>       
<task name="TASK1"
     class="CLASS"
     group="GROUP">
  <trigger count="3" interval="400"/>
  <property xmlns:task="URI"
            name="PROPERTY2"
            value="VALUE1"/>
  <property xmlns:task="URI"
            name="PROPERTY2"
            value="VALUE2"/>
</task>
<task name="TASK1"
     class="CLASS"
     group="GROUP">
  <trigger count="1" interval="600"/>
  <property xmlns:task="URI"
            name="PROPERTY2"
            value="VALUE1"/>
  <property xmlns:task="URI"
            name="PROPERTY2"
            value="VALUE2"/>
</task>
<another_tag name="a_name"/>
<another_tag2 name="a_name2"/>
<another_tag3>  something in the middle </another_tag3>

</definitions>

Я должен удалить все <task> теги и что внутри них. Я использовал этот код Java:

Document esb = new Document();

    SAXBuilder saxBuilder = new SAXBuilder();


    try {
       esb = saxBuilder.build(new File("C:\\...path\\file.xml")); 
    }
    catch (JDOMException ex) {
       System.err.println(ex);
    }
    catch (IOException ex) {
       System.err.println(ex);
    }
    Element root = esb.getRootElement();
    boolean b = root.removeChild("task");
    System.out.println(b);

Я не могу понять, как получить XML-файл без <task> тег и содержащий только <another_tag> тег. Я искал другие решения, но ничего полезного. Я также использовал метод removeContent(), но ничего. Я импортировал библиотеки jdom2, мне нужно использовать последние библиотеки, потому что между jdom и jdom2 существует плохое взаимодействие, поэтому я бы предпочел использовать только последние библиотеки. Любое предложение о том, как удалить какой-либо элемент из этого XML-кода?

4 ответа

Решение

Я решил эту проблему, управляя пространством имен. Есть код:`

Document doc = new Document();

SAXBuilder saxBuilder = new SAXBuilder();
try {
       doc = saxBuilder.build(new File("....path\MyXMLfile.xml")); 
    }
    catch (JDOMException ex) {
       System.err.println(ex);
    }
    catch (IOException ex) {
       System.err.println(ex);
    }


    Element root = esb.getRootElement();
    System.out.println(root.getName());  // it prints "definitions"

    Namespace namespace = Namespace.getNamespace("task","http://....myDefinitionsNamespace....");

    boolean b = root.removeChildren("task", namespace);

    System.out.println(b);

    XMLOutputter xmlOutputter = new XMLOutputter();
    xmlOutputter.setFormat(Format.getPrettyFormat());
    System.out.println(xmlOutputter.outputString(doc)); //so we can see new XML FILE

Чтобы понять этот код, нам также нужно запустить xml:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://....myDefinitionsNamespace....">
<task name="MyTask"
     class="....myClass...."
     group="....myGroup...."> 
<taskChild/>
</task>
<anotherTag1/>
<anotherTag2>
<task/>
.
.
.
</definitions>

В результате получается XML-файл без каждого тега задачи, он будет содержать только другие теги. Затем вам нужно определить вывод (например, в файл с экземпляром FileOutputStream). Спасибо @OkieOth и @rolfl.

API говорит это для функции 'removeChild': ... Это удаляет первый дочерний элемент (на один уровень глубины) с заданным локальным именем и принадлежащий без пространства имен...

Функция removeChild удаляет только одного дочернего элемента. Поэтому, если вы хотите удалить всех потомков с определенным именем, вам нужно использовать цикл. Если вызов функции не может найти узел с нужным именем, он возвращает значение false.

Если я работаю с вашим примером xml, третий вызов removeChild вернётся с false. Поэтому следующий код удалит все дочерние элементы задачи

...
    boolean b = root.removeChild("task");
    while (b)
        b = root.removeChild("task");
...

В дополнение к тому, что сказал OkieOth, вы удаляете только первое задание.

Другая проблема заключается в том, что вы больше не записываете JDOM в файл. Вам нужно сохранить поверх существующего файла, чтобы увидеть изменения.

Если вы хотите применить изменения обратно в файл, учтите это:

SAXBuilder saxBuilder = new SAXBuilder();

try {
    Document esb = saxBuilder.build(new File("C:\\...path\\file.xml")); 
    Element root = esb.getRootElement();
    boolean b = root.removeChild("task");
    System.out.println(b);
    XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
    try (OutputStream os = new FileOutputStream("C:\\...path\\file.xml")) {
        xout.output(os, esb)
    }
}
catch (JDOMException ex) {
   System.err.println(ex);
}
catch (IOException ex) {
   System.err.println(ex);
}

Вот код для использования XPath для постепенного удаления всех узлов задач с использованием vtd-xml

import com.ximpleware.*;
import java.io.*;

public class removeElement {
    public static void main(String s[]) throws VTDException,IOException{
        VTDGen vg = new VTDGen();
        if (!vg.parseFile("input.xml", false))
            return;
        VTDNav vn = vg.getNav();
        AutoPilot ap = new AutoPilot(vn);
        ap.selectXPath("/definition/task");
        XMLModifier xm = new XMLModifier(vn);
        int i=0;
        while((i=ap.evalXPath())!=-1){
            xm.remove();
        }
        xm.output("output.xml");

    }
}
Другие вопросы по тегам