# XML vernünftig auslesen



## kevin9r (26. Feb 2018)

Hallo, 
ich arbeite derzeit an einem Programm, bei dem ich nicht um das auslesen einer XML Datei drum herum komme. Irgendwie bekomme ich es einfach nicht vernünftig hin mit Java eine XML Datei dynamisch auszulesen. Die rohen Daten habe ich in eine XML geschrieben, diese muss ich jetzt auslesen. Um folgende Datei geht es: 

```
<?xml version="1.0" encoding="UTF-8"?>

-<bookings roomid="46587" >


-<booking id="5325193" action="">

<masterId>5325193</masterId>


-<group>

<booking id="5325202"/>

<booking id="5325208"/>

</group>

<roomId>46587</roomId>
```

Mich interessieren die zwei Daten in der <group> Klammer. Wie komme ich da dran. Bin jetzt seit 3 Tagen am rumprobieren aber finde einfach keinen Weg: 

```
System.out.println("Root element " + doc.getDocumentElement().getElementsByTagName("group").item(0).getNodeName());
```

Vielen Dank!


----------



## krgewb (26. Feb 2018)

Um eine XML-Datei zu laden:

```
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser parser = saxParserFactory.newSAXParser();
DefaultHandler myHandler = new MySAXHandler(mainWindow, xmlFile);
parser.parse(xmlFile, myHandler);
```

Wobei MySAXHandler eine eigene Klasse ist, die von Default Handler erbt.
Dort muss es u.a. solch eine Methode geben:

```
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {
   ...
}
```

In "startElement" kannst du über qName abfragen und über atts.getLength() iterieren:

```
if (qName.equals("zteutf")) {
    for (int i = 0; i < atts.getLength(); i++) {
        if (atts.getQName(i).equals("irtdf")) {
            ...
        }
    }
}
```


----------



## Flown (27. Feb 2018)

Du könntest es mal mit einem ordentlichen XPath versuchen. Da das xml file nicht valide ist, kann ich dir da auch nicht näher helfen.


----------



## kevin9r (27. Feb 2018)

So sieht die XML Datei aus (hab diese jetzt irgendwo abgeschnitten, die Tags werde alle geschlossen): 


```
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<bookings bookid="5325193" propid="19034" roomid="46587">
    <booking action="" id="5325193">
        <masterId>5325193</masterId>
        <group>
            <booking id="5325202"/>
            <booking id="5325208"/>
        </group>
        <roomId>46587</roomId>
```

Das ist nicht valide? Wieso nicht? Bekomme die Daten als String, könnte noch etwas daran ändern bevor ich diese in die Datei schreibe. Dachte mir nur, dass wenn ich die Daten in eine XML Datei schreibe, ich diese schön bequem dynamisch über die Tags abrufen kann (wie in einer Datenbank). Deswegen habe ich den Weg über die XML gemacht. 

Leider klappt das nicht so wie ich mir das wünsche. 

@krgewb  den Code verstehe ich nicht. 
DefaultHandler myHandler = new MySAXHandler(mainWindow, xmlFile);

Was soll ich denn da übergeben?


----------



## Thallius (27. Feb 2018)

Also sorry aber es gibt doch tausende von Beispielen im Netz wie man sowas macht.

https://www.mkyong.com/java/jaxb-hello-world-example/

kompletter Code wie Du eine XML einliest.

Also einfacher geht es kaum

Gruß

Claus


----------



## kevin9r (27. Feb 2018)

Ja ich weiß, ich habe auch schon XML Dateien ausgelesen, und auch diese kann ich auslesen. Das Problem ist einfach, dass ich nicht weiß wie ich an die 

<masterId>5325193</masterId>
        <group>
            <booking id="5325202"/>
            <booking id="5325208"/>
        </group>

zwei booking ids in der group komme. 


```
doc.getDocumentElement().getElementsByTagName("group").item(0).getNodeName())
```

So komme ich schon mal an den Namen group. Aber ich weiß einfach nicht wie ich dann noch tiefer komme.


----------



## stg (27. Feb 2018)

kevin9r hat gesagt.:


> So komme ich schon mal an den Namen group. Aber ich weiß einfach nicht wie ich dann noch tiefer komme.



Schau z.B. hier: https://stackoverflow.com/a/5568798


----------



## Flown (27. Feb 2018)

Mit XPath ist es ganz einfach durch ein XML zu navigieren (darum gibts die API auch).

```
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
        "<bookings bookid=\"5325193\" propid=\"19034\" roomid=\"46587\">\n" +
        "    <booking action=\"\" id=\"5325193\">\n" +
        "        <masterId>5325193</masterId>\n" +
        "        <group>\n" +
        "            <booking id=\"5325202\"/>\n" +
        "            <booking id=\"5325208\"/>\n" +
        "        </group>\n" +
        "        <roomId>46587</roomId>\n" +
        "    </booking>\n" +
        "</bookings>";
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();

StringWriter writer = new StringWriter();

try (StringReader stringReader = new StringReader(xml)) {
  Transformer transformer = TransformerFactory.newInstance().newTransformer();
  transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
  transformer.setOutputProperty(OutputKeys.INDENT, "yes");

  NodeList evaluate = (NodeList) xPath.evaluate("//group/*", new InputSource(stringReader), XPathConstants.NODESET);
  for (int i = 0; i < evaluate.getLength(); i++) {
    transformer.transform(new DOMSource(evaluate.item(i)), new StreamResult(writer));
  }
} catch (XPathExpressionException | TransformerException e) {
  e.printStackTrace();
}

System.out.println(writer);
```
Transformer ist hier nur wegen der Ausgabe genutzt - in der for-Schleife kannst du dir die Nodes rauslesen.


----------



## kevin9r (28. Feb 2018)

Super! Ich danke dir. Dieses XPath ist ja genau das was ich suche, eine XML Datei, die ich wie eine Datenbank abfragen kann. Habe das jetzt geändert, dass der mir keine Datei schreibt, sondern ich sofort den String von der API übergebe. Jetzt kann ich mit deinem Code die ids herausziehen. Jetzt versuche ich aber auf die selbe Art die roomId zu erhalten. Ich nutze folgenden Befehl:
NodeList evaluate = (NodeList) xPath.evaluate("//roomId/text()", out, XPathConstants.NODESET);

Leider erhalte ich dann die Exception: 

```
javax.xml.transform.TransformerException: Unable to evaluate expression using this context
    at com.sun.org.apache.xpath.internal.XPath.execute(Unknown Source)
    at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.eval(Unknown Source)
    at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(Unknown Source)
    at keysystem.Beds24.getRoomid(Beds24.java:276)
    at keysystem.Beds24.<init>(Beds24.java:127)
    at keysystem.Keysystem.main(Keysystem.java:20)
Caused by: java.lang.RuntimeException: Unable to evaluate expression using this context
    at com.sun.org.apache.xpath.internal.axes.NodeSequence.setRoot(Unknown Source)
    at com.sun.org.apache.xpath.internal.axes.LocPathIterator.execute(Unknown Source)
    ... 6 more
---------
java.lang.RuntimeException: Unable to evaluate expression using this context
    at com.sun.org.apache.xpath.internal.axes.NodeSequence.setRoot(Unknown Source)
    at com.sun.org.apache.xpath.internal.axes.LocPathIterator.execute(Unknown Source)
    at com.sun.org.apache.xpath.internal.XPath.execute(Unknown Source)
    at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.eval(Unknown Source)
    at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(Unknown Source)
    at keysystem.Beds24.getRoomid(Beds24.java:276)
    at keysystem.Beds24.<init>(Beds24.java:127)
    at keysystem.Keysystem.main(Keysystem.java:20)
--------------- linked to ------------------
javax.xml.xpath.XPathExpressionException: javax.xml.transform.TransformerException: Unable to evaluate expression using this context
    at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(Unknown Source)
    at keysystem.Beds24.getRoomid(Beds24.java:276)
    at keysystem.Beds24.<init>(Beds24.java:127)
    at keysystem.Keysystem.main(Keysystem.java:20)
Caused by: javax.xml.transform.TransformerException: Unable to evaluate expression using this context
    at com.sun.org.apache.xpath.internal.XPath.execute(Unknown Source)
    at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.eval(Unknown Source)
    ... 4 more
Caused by: java.lang.RuntimeException: Unable to evaluate expression using this context
    at com.sun.org.apache.xpath.internal.axes.NodeSequence.setRoot(Unknown Source)
    at com.sun.org.apache.xpath.internal.axes.LocPathIterator.execute(Unknown Source)
    ... 6 more
```

Hast du eine Idee voran das liegt. 

Vielen Dank nochmal für den super Tipp!


----------



## Flown (28. Feb 2018)

Naja wie wärs denn mit:

```
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
        "<bookings bookid=\"5325193\" propid=\"19034\" roomid=\"46587\">\n" +
        "    <booking action=\"\" id=\"5325193\">\n" +
        "        <masterId>5325193</masterId>\n" +
        "        <group>\n" +
        "            <booking id=\"5325202\"/>\n" +
        "            <booking id=\"5325208\"/>\n" +
        "        </group>\n" +
        "        <roomId>46587</roomId>\n" +
        "    </booking>\n" +
        "</bookings>";
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();

try (StringReader stringReader = new StringReader(xml)) {
  String evaluate = (String) xPath.evaluate("//roomId/text()", new InputSource(stringReader), XPathConstants.STRING);
  System.out.println(evaluate);
} catch (XPathExpressionException e) {
  e.printStackTrace();
}
```


----------

