# XML-Element komplett löschen



## Wambui (27. Aug 2014)

Hallo,

in folgender XML-Datei möchte ich beispielsweise das Element "city" mit dem Attribut "name=Aalen" komplett löschen, also inklusive aller Kindselemente von "Aalen".


```
<?xml version="1.0" encoding="UTF-8"?>
<costcalculator>
  <city name="München">
    <distance>221.357</distance>
    <duration>2.3294444444444444</duration>
    <monthlyticket>547.00</monthlyticket>
    <roundtripticket>114.0</roundtripticket>
    <hotelcosts>0.00</hotelcosts>
    <publictransport>false</publictransport>
  </city>
  <city name="Frankfurt">
    <distance>204.365</distance>
    <duration>2.0494444444444446</duration>
    <monthlyticket>467.00</monthlyticket>
    <roundtripticket>126.00</roundtripticket>
    <hotelcosts>0.00</hotelcosts>
    <publictransport>false</publictransport>
  </city>
  <city name="Köln">
    <distance>367.153</distance>
    <duration>3.4047222222222224</duration>
    <monthlyticket>292.40</monthlyticket>
    <roundtripticket>185.00</roundtripticket>
    <hotelcosts>49.00</hotelcosts>
    <publictransport>false</publictransport>
  </city>
  <city name="Aalen">
    <distance>78.111</distance>
    <duration>0.9852777777777778</duration>
    <monthlyticket>233.30</monthlyticket>
    <roundtripticket>88.56</roundtripticket>
    <hotelcosts>50.00</hotelcosts>
  </city>
```

Dazu habe ich folgende Java-Klasse erstellt:

```
package com.example.exercise;


import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

public class Remove {

	public static void main(String[] args) {
		String xmlFile = "/home/wambui/Data/City.xml";
		String cityName = "Aalen";
		try {
			SAXBuilder builder = new SAXBuilder();
			Document doc = (Document) builder.build(xmlFile);

			Element costCalculator = doc.getRootElement();
			Iterator<Element> cities = costCalculator.getChildren("city").iterator();
			while (cities.hasNext()) {
				Element city = (Element) cities.next();
				if (cityName.equals(city.getAttribute("name").getValue())) {
					costCalculator.removeContent(city);
				}
				
			}
				
			
		} catch (JDOMException | IOException e) {
			e.printStackTrace();
		} 
	}
}
```

Als Fehlermeldung bekomme ich 
*Exception in thread "main" java.util.ConcurrentModificationException: The ContentList supporting the FilterList this iterator is processing has been modified by something other than this Iterator.
	at org.jdom2.ContentList$FilterListIterator.checkConcurrent(ContentList.java:1309)
	at org.jdom2.ContentList$FilterListIterator.next(ContentList.java:1357)
	at org.jdom2.ContentList$FilterListIterator.next(ContentList.java:1260)
	at com.linuxmaker.calculator.exercise.Remove.main(Remove.java:25)*

Jetzt bin ich etwas überfragt, wie ich ein XML-Element komplett löschen kann.

Grüße
Wambui


----------



## Harry Kane (28. Aug 2014)

Wenn du Elemente aus einer Collection löscht, über die du gerade iterierst, wirst du in den allermeisten Fällen eine ConcurrentModificationException bekommen. Dieses Verhalten wird grundsätzlich beobachtet, nicht nur bei deinem konkreten Fall.
Um das zu umgehen, könntest du die gefundenen Elemente z. B. in einer ArrayList speichern und nach der Iteration die Elemente in der ArrayList aus dem costCalculator entfernen.


----------



## Joose (28. Aug 2014)

Harry Kane hat zwar recht mit der Beschreibung warum es zum Fehler kommt.
Auch die mögliche Behebung durch eine extra Liste und dem Löschen danach ist zwar möglich aber unschön.

Dein Fehler liegt daran das du die Element auf der eigentlichen Liste entfernst. Rufe stattessen die "remove" Methode auf dem Iterator Objekt auf. So entfernst wird das Objekt vom Iterator und der Liste entfernt.


----------



## Wambui (28. Aug 2014)

Joose hat gesagt.:


> Harry Kane hat zwar recht mit der Beschreibung warum es zum Fehler kommt.
> Auch die mögliche Behebung durch eine extra Liste und dem Löschen danach ist zwar möglich aber unschön.
> 
> Dein Fehler liegt daran das du die Element auf der eigentlichen Liste entfernst. Rufe stattessen die "remove" Methode auf dem Iterator Objekt auf. So entfernst wird das Objekt vom Iterator und der Liste entfernt.



Erst einmal Danke für die beiden Erklärungen. Wobei mich die von Harry Kane durcheinander gebracht hatte. Denn ich hatte zum Ändern von Inhalten in der XML-Datei folgenden Code geschrieben:

```
SAXBuilder builder = new SAXBuilder();
			Document doc = (Document) builder.build(xmlFile);

			Element costCalculator = doc.getRootElement();
			
			Iterator<?> cityList = costCalculator.getChildren("city").iterator();
			while (cityList.hasNext()) {
				Element city = (Element) cityList.next();
				if (cityName.equals(city.getAttribute("name").getValue())) {
					Element monthlyTicket = new Element("monthlyticket");
					monthlyTicket.addContent(varMonthlyTicket);
					city.removeChild("monthlyticket");
					city.addContent(monthlyTicket);
					Element roundTripTicket = new Element("roundtripticket);
					roundTripTicket.addContent(varRoundTripTicket);
					city.removeChild("roundtripticket);
					city.addContent(roundTripTicket);
					Element hotelCost = new Element("hotelcosts");
					hotelCost.addContent(varHotel);
					city.removeChild("hotelcosts");
					city.addContent(hotelCost);
					city.removeChild("publictransport");
					city.addContent(publictransport);
				}
				
			}
```
Und das funktioniert definitiv, obwohl ich über im selben Moment über eine Collection iteriere.

Wenn ich jetzt Deinem Ansatz versuche umzusetzen

```
Element costCalculator = doc.getRootElement();
			Iterator<Element> cities = costCalculator.getChildren("city").iterator();
			while (cities.hasNext()) {
				Element city = (Element) cities.next();
				if (cityName.equals(city.getAttribute("name").getValue())) {
					cities.remove();
				}
				
			}
```
dann kommt die ConcurrentModificationException tatsächlich nicht mehr. Allerdings wird in der XML-Datei auch nichts entfernt.
Entferne ich hiermit lediglich aus dem Iterator-Objekt besagten Eintrag? Wie aber bekomme ich ihn auch aus der XML-Datei heraus?


----------



## Harry Kane (28. Aug 2014)

In deinem Beispiel, wo du über eine Liste iterierst und gleichzeitig Veränderungen vornimmst, löschst du zwar Informationen aus den Objekten in der Liste, löschst aber nicht die Objekte in der Liste!
Anders ausgedrückt: Objekte in einer Liste können durchaus verändert werden, während du über die Liste iterierst, aber nicht die Liste selbst.
Hast du die XML Datei nach den Änderungen auch gespeichert? Wenn ja, und wenn dann trotzdem keine Änderung kommt, verhält sich die remove() Funktion aus dem Iterator ev. nicht so wie erwartet.


----------



## Wambui (29. Aug 2014)

Harry Kane hat gesagt.:


> Hast du die XML Datei nach den Änderungen auch gespeichert? Wenn ja, und wenn dann trotzdem keine Änderung kommt, verhält sich die remove() Funktion aus dem Iterator ev. nicht so wie erwartet.


Nein, das habe ich tatsächlich komplett vergessen, bei dem gesamten gedanklichen Abstraktieren von XML nach Java. Vielen Dank für den Hinweis und die Erklärungen. Jetzt funktioniert Joose's Vorschlag.


----------

