XML auslesen, benötige Hilfe

beta20

Top Contributor
Hallo,

ich möchte gerne folgende XML auslesen:
Code:
<?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:
Code:
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:
 
Bekomme folgende Fehlermeldung
Code:
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)
 
So ich habe den Code nun überarbeitet, habe aber immer noch ein Problem

Code:
        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:

Code:
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:


Code:
    <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>
 
Was schlägst Du vor?
Ich kenne mich nicht gut mit XML und JAVA aus. JDom war die erste Empfehlung, was mir Google ausspuckte...
 
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.
 
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:
Java:
  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());
  }
  }

}
 
Vanilla Java DOM + XPath:
Java:
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());
  }
}
 
Perfekt, das wars. Vielen vielen Dank.
Habe es noch erwartet um den output zu erweitern.

Code:
 {
            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());
            }
 
So sollte es etwas sauberer aussehen:

Java:
            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"));
 
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
 
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...
 

Zurück
Oben