# XML auslesen, benötige Hilfe



## beta20 (21. Aug 2016)

Hallo,

ich möchte gerne folgende XML auslesen:

```
<?xml version="1.0" encoding="UTF-8"?>
<myapp version="1.0">
<photo_information>
  <date>2016/08/20</date>
  <time>17:21:59</time>
  <user_data></user_data>
  <prints>1</prints>
  <photos>
    <photo image="1">IMG_0001.JPG</photo>
    <photo image="2">IMG_0002.JPG</photo>
    <photo image="3">IMG_0003.JPG</photo>
    <photo image="4">IMG_0004.JPG</photo>
    <output>prints\160820_172159.jpg</output>
  </photos>
</photo_information>
</myapp>
```

Hier mal mein Test:

```
package my.app.test;

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

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

public class TestXML {

    public static void main(String[] args) {

        Document doc = null;

        String filePath = "/myPath/IMG_0001.xml";
        File f = new File(filePath);

        try {
            // Das Dokument erstellen
            SAXBuilder builder = new SAXBuilder();
            doc = builder.build(f);
            XMLOutputter fmt = new XMLOutputter();

            // komplettes Dokument ausgeben
            fmt.output(doc, System.out);

            // Wurzelelement ausgeben
            Element element = doc.getRootElement();
            System.out.println("\nWurzelelement: " + element);

            // Wurzelelementnamen ausgeben
            System.out.println("Wurzelelementname: " + element.getName());

            // Eine Liste aller direkten Kindelemente eines Elementes erstellen
            List alleKinder = (List) element.getChildren();
            System.out.println("Erstes Kindelement: "
                    + ((Element) alleKinder.get(0)).getName());

            // Eine Liste aller direkten Kindelemente eines benannten
            // Elementes erstellen
            List benannteKinder = element.getChildren("photos");

            // Das erste Kindelement ausgeben
            System.out.println("benanntes Kindelement: "
                    + ((Element) benannteKinder.get(0)).getName());

            // Wert eines bestimmten Elementes ausgeben
            Element kind = element.getChild("bw_mode");
            System.out.println("Photo: " + kind.getValue());

            // Attribut ausgeben
            Element kind2 = element.getChild("photo");
            System.out.println("Photo: " + kind2.getAttributeValue("name"));
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
```

Ich benötige die Infos:
- prints
- Die einzelnen Fotos (IMG_0001.JPG, IMG_0002.JPG, IMG_0003.JPG, IMG_0004.JPG)
- Output (prints\160820_172159.jpg)

Leider klappt das nicht so ganz wie ich mir das vorstelle:


----------



## thecain (21. Aug 2016)

Was passiert denn stattdessen?


----------



## beta20 (21. Aug 2016)

Bekomme folgende Fehlermeldung

```
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 3 Size: 3
    at org.jdom.ContentList.get(ContentList.java:377)
    at org.jdom.ContentList$FilterList.get(ContentList.java:582)
    at my.app.test.TestXML.main(TestXML.java:49)
```


----------



## beta20 (22. Aug 2016)

So ich habe den Code nun überarbeitet, habe aber immer noch ein Problem


```
try {

            Document document = (Document) builder.build(xmlFile);
            Element rootNode = document.getRootElement();
            List list = rootNode.getChildren("photo_information");
           
            Element node = (Element) list.get(0);
            System.out.println("Date : " + node.getChildText("date"));
            System.out.println("Prints : " + node.getChildText("prints"));

            for (int i = 0; i < list.size(); i++) {

                List list2 = node.getChildren("photos");
                for (int l = 0; l < list2.size(); l++) {
                    Element node2 = (Element) list2.get(l);
                    System.out.println("Photo : " + node2.getChildText("photo"));
                }
            }

        } catch (IOException io) {
            System.out.println(io.getMessage());
        } catch (JDOMException jdomex) {
            System.out.println(jdomex.getMessage());
        }
```

Mein Output:


```
Date : 2016/08/20
Prints : 1
Photo : IMG_0001.JPG
```


Wie bekomme ich aber noch die anderen Photos + Output?
Derzeit bekomme ich nur ein Photo.
Also sprich, wie bekomme ich noch die Werte von:



```
<photo image="2">IMG_0002.JPG</photo>
    <photo image="3">IMG_0003.JPG</photo>
    <photo image="4">IMG_0004.JPG</photo>
    <output>prints\160820_172159.jpg</output>
```


----------



## Flown (23. Aug 2016)

Wieso verwendest du jdom in erster Linie und nicht eine Bibliothek aus Java selbst?


----------



## beta20 (23. Aug 2016)

Was schlägst Du vor?
Ich kenne mich nicht gut mit XML und JAVA aus. JDom war die erste Empfehlung, was mir Google ausspuckte...


----------



## tommysenf (23. Aug 2016)

Ich denke dein Denkfehler liegt hier:

List list2 = node.getChildren("photos");

list2 enthält danach genau ein Element und nicht die einzelnen "photo" Elemente wie du vermutlich annimmst.


----------



## Harry Kane (23. Aug 2016)

Den äußeren for-loop kannst du dir sparen, da du die Laufvaruiable "i" gar nicht verwendest.
"list2" ist eine Liste mit allen "photos"-Kindelementen von "photo_information". Da es nur eine "photos"-Kindelement gibt, gehst du nur 1x durch den inneren for-loop. Die Logik stimmt ausserdem nicht, da du mit node2.getChildText("photo") nur den Textknoten unterhalb des ersten "photo"-Kindelements bekommts. Du willst aber an die Textknoten unterhalb aller "photo"-Kindelemente. So z. B. geht das:

```
public static void main(String[] args) throws Exception {

  String filePath = "IMG_0001.xml";
  File f = new File(filePath);

  try {
  SAXBuilder builder = new SAXBuilder();
  Document document = (Document) builder.build(f);
  Element rootNode = document.getRootElement();
  List list = rootNode.getChildren("photo_information");

  Element node = (Element) list.get(0);
  System.out.println("Date : " + node.getChildText("date"));
  System.out.println("Prints : " + node.getChildText("prints"));

  List list2 = node.getChildren("photos");
  Element photos = (Element) list2.get(0);
  List list3 = photos.getChildren("photo");
  for (int l = 0; l < list3.size(); l++) {
  Element node2 = (Element) list3.get(l);
  System.out.println("Photo : " + node2.getText());
  }

  } catch (IOException io) {
  System.out.println(io.getMessage());
  } catch (JDOMException jdomex) {
  System.out.println(jdomex.getMessage());
  }
  }

}
```


----------



## Flown (23. Aug 2016)

Vanilla Java DOM + XPath:

```
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class Test {
  public static void main(String... args) throws Exception {
    
    String xml ="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + 
        "<myapp version=\"1.0\">\r\n" + 
        "<photo_information>\r\n" + 
        "  <date>2016/08/20</date>\r\n" + 
        "  <time>17:21:59</time>\r\n" + 
        "  <user_data></user_data>\r\n" + 
        "  <prints>1</prints>\r\n" + 
        "  <photos>\r\n" + 
        "    <photo image=\"1\">IMG_0001.JPG</photo>\r\n" + 
        "    <photo image=\"2\">IMG_0002.JPG</photo>\r\n" + 
        "    <photo image=\"3\">IMG_0003.JPG</photo>\r\n" + 
        "    <photo image=\"4\">IMG_0004.JPG</photo>\r\n" + 
        "    <output>prints\\160820_172159.jpg</output>\r\n" + 
        "  </photos>\r\n" + 
        "</photo_information>\r\n" + 
        "</myapp>";
    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
    
    Document document = documentBuilder.parse(new InputSource(new StringReader(xml)));
    
    XPathFactory xPathFactory = XPathFactory.newInstance();
    XPath xPath = xPathFactory.newXPath();
    NodeList nodes = (NodeList) xPath.evaluate("//photos/*", document, XPathConstants.NODESET);
    StringWriter sw = new StringWriter();
    Transformer t = TransformerFactory.newInstance().newTransformer();
    t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
    t.setOutputProperty(OutputKeys.INDENT, "yes");
    for(int i = 0; i< nodes.getLength(); i++) {
      t.transform(new DOMSource(nodes.item(i)), new StreamResult(sw));
    }
    System.out.println(sw.toString());
  }
}
```


----------



## beta20 (23. Aug 2016)

Perfekt, das wars. Vielen vielen Dank.
Habe es noch erwartet um den output zu erweitern.


```
{
            SAXBuilder builder = new SAXBuilder();
            Document document = (Document) builder.build(f);
            Element rootNode = document.getRootElement();
            List list = rootNode.getChildren("photo_information");

            Element node = (Element) list.get(0);
            System.out.println("Date : " + node.getChildText("date"));
            System.out.println("Prints : " + node.getChildText("prints"));

            List list2 = node.getChildren("photos");
            Element photos = (Element) list2.get(0);
            List list3 = photos.getChildren("photo");
            for (int l = 0; l < list3.size(); l++) {
                Element node2 = (Element) list3.get(l);
                System.out.println("Photo : " + node2.getText());
            }
            List list4 = photos.getChildren("output");
            for (int l = 0; l < list4.size(); l++) {
                Element node2 = (Element) list4.get(l);
                System.out.println("Photo : " + node2.getText());
            }
```


----------



## tommysenf (24. Aug 2016)

So sollte es etwas sauberer aussehen:


```
SAXBuilder builder = new SAXBuilder();
            Document document = (Document) builder.build(f);
            Element rootNode = document.getRootElement();

            Element node =  rootNode.getChild("photo_information");
            System.out.println("Date : " + node.getChildText("date"));
            System.out.println("Prints : " + node.getChildText("prints"));

            Element photos = node.getChild("photos");
            for (Element photo: photos.getChildren("photo")) {
                System.out.println("Photo : " + photo.getText());
            }
            System.out.println("Output : " + photos.getChildText("output"));
```


----------



## Steven Hachel (29. Aug 2016)

Gucke dir bitte mal JaxB an. Das, was du/ihr da macht, ist gruselig.  Es ist nicht falsch, was ihr da vor schlagt, aber mit JaxB ist es sauberer.  Und zusätzlich erlernst du zugleich, dass evtl. spätere komplexe Abbildungen von XML Strukturen kinderleicht zu verarbeiten sind.

viele Grüße
Steven


----------



## Flown (29. Aug 2016)

Steven Hachel hat gesagt.:


> Das, was du/ihr da macht, ist gruselig.  Es ist nicht falsch, was ihr da vor schlagt, aber mit JaxB ist es sauberer.


Aha, ich muss also eine ganze Objektstruktur herum bauen, wenn ich nur einen ganz kleinen Teil einer XML haben möchte?

Ich meine es ist das sauberste nach genannten Elementen zu suchen und nur diese zu verarbeiten.


----------



## Steven Hachel (29. Aug 2016)

Ich glaube nicht, dass der Code mit JaxB unvesentlich größer wird, aber ich bin mir sicher, das der Code sauberer, wartbarer und lesbarer sein wird. 
Ich meine es nicht böse, aber warum  sich nicht das JaxB Framework aneignen, um spätere komplexere Verabeitungen schnell umsetzen zu können...


----------

