# XML-Daten mit SAX auslesen



## yafoe (12. Juli 2005)

Hallo Java-Freunde,

ich möchte mit SAX-Parser Daten aus XML-Datei lesen.
Aber ich habe ein Problem und zwar: XML-Daten von Elementen mit gleicher Name mit SAX auszulesen. 

Beispiel:
<person>
<mitarbeiter>
      <name>Krause</name>
      <age>42</age>
      <adress typ=email> krause@tutorials.de</adress>
</mitarbeiter>
<mitarbeiter>
       <name>Ullrich</name>
       <age>27</age>
       <adress typ=post>ruhrweg 12, 23112 Kiel</adress>
</mitarbeiter>
</person>

*Da sax-reader xml-dokumente sequentiell durchlauft, wie programmiere ich es mit java damit ich sowohl die <name>  als auch die <adresse> von beiden Mitarbeitern auslese und wiedergebe?* Danke schön, Daniel.

Hier ist schon der Anfang meiner java-Quellcode:

public class XmlLeser implements ContentHandler {

public XmlLeser(String fileName) {
	try {
	 XMLReader myParser = new SAXParser(); 
	)
	myParser.setContentHandler(this); 				myParser.parse(fileName); // starten zum Parsen
	} catch (Exception e) {System.out.println("Erreur " + e);	}

} // Ende des Konstructors

public static void main(String args[]) {
	String xmlFileName = "";
	if (args.length == 0) {

	System.out.println("Usage::java XmlLeser path/xmlFilename");
	System.exit(0);
	} else {xmlFileName = args[0];}

XmlLeser pux = new XmlLeser(xmlFileName);

} // end main()

//****************************************HANDLER****************************************
public void startDocument() {
System.out.println(" Anfang des Parsens " );
} // startDocument()

public void endDocument() {
System.out.println(" Ende des Parsens " );
} // endDocument()

public void startElement(String namespaceURI, String localName, String qName) throws SAXException {  	//WIE GEHT ES WEITER?	} 

public void endElement(String namespaceURI, String localName, String qName) throws SAXException {  	//WIE GEHT ES WEITER?	} 


public void processingInstruction(String target, String data) {  		} 


} //end class


----------



## Thomas Darimont (12. Juli 2005)

Hallo!

    schau mal hier:

```
/**
  * 
  */
 package de.tutorials;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParserFactory;
 
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
 /**
  * @author Tom
  * 
  */
 public class SaxParserExample {
 
 	/**
 	 * @param args
 	 * @throws ParserConfigurationException
 	 * @throws IOException
 	 * @throws SAXException
 	 */
 	public static void main(String[] args) throws SAXException, IOException,
 			ParserConfigurationException {
 		String xml = "<?xml version=\"1.0\" ?><personen>" + "<mitarbeiter>"
 		    	+ "<name>Krause</name>" + "<age>42</age>"
 		    	+ "<adress typ=\"email\">krause@tutorials.de</adress>"
 		    	+ "</mitarbeiter>" + "<mitarbeiter>" + "<name>Ullrich</name>"
 				+ "<age>27</age>"
 		    	+ "<adress typ=\"post\">ruhrweg 12, 23112 Kiel</adress>"
 				+ "</mitarbeiter>" + "</personen>";
 
 	    SAXParserFactory.newInstance().newSAXParser().parse(new ByteArrayInputStream(xml.getBytes()), new DefaultHandler() {
 					
 			boolean skip;
 
 			public void startElement(String uri,
 		    		    			 String localName, 
 		    		    			 String qName, 
 		    		    		     Attributes attributes)
 		    		    			 throws SAXException {
 						
 				skip = false;
 			
 				if (qName.equals("name")) {
 					System.out.println("Name: ");
 				} else if (qName.equals("adress")) {
 					System.out.println("Adress: ");
 				} else {
 					skip = true;
 				}
 			}
 
 			public void characters(char[] ch, 
 		    		    		   int start, 
 		    		    		   int length)
 		    		    		   throws SAXException {
 				if (skip) {
 					return;
 				}
 
 				System.out.println(new String(ch, start, length));
 			}
 		});
 	}
 }
```
 
    Gruß tom


----------



## yafoe (13. Juli 2005)

Danke sehr Tom ich habe deine Quellcode benutzt und es hat geklappt. Übrigens ich habe danach nicht wie du das String xml definiert und dann als ByteStream gelesen, sondern direkt aus der XML-Datei (Beispiel.xml) gelesen und dargestellt. 

Aber ein Problem hätte ich noch. Zwar: nehmen wir an, ich möchte die <Element>-Daten aussortiert auslesen je nach Eltern-Element. Wie sollte ich umgehen. Zum Beispiel, ich habe die folgende XML-Datei: *(Siehe unten für Problemstellung)*


```
<?xml version="1.0" encoding="ISO-8859-1" ?> 
<person>
<mitarbeiter>
<name>Krause</name>
<age>42</age>
<adress> krause@tutorials.de</adress>
</mitarbeiter>
<mitarbeiter>
<name>Ullrich</name>
<age>27</age>
<adress>ruhrweg 12, 23112 Kiel</adress>
</mitarbeiter>
<student>
<name>Davenport</name>
<age>27</age>
<adress> dav@tutorials.de</adress>
</student>
<student>
<name>Rutherford</name>
<age>22</age>
<adress> ford@tutorials.de</adress>
</student>
<student>
<name>Moore</name>
<age>29</age>
<adress>moore@tutorials.de</adress>
</student>
</person>
```

*Problemstellung: Ich möchte ich für die Element <Mitarbeiter> nur die (Unterelement-daten) <name>- und <adress> auslesen; 
Und für die Element <Student> nur die (unterelement-Daten) <name> und <age> auslesen.Dabei muss nur die o.g. Studenten-daten (genannt "davenport" und "moore") auslesen. Könntest du mir dafür eine Code-Beispiel geben
Bemerkung: Wenn ich diese Programmiere habe ich immer unerwarte Ergebnisse, deswegen die Bitte um Hilfe. Danke sehr !*



Hier ist meine aktuelle Java-Code:

```
import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

 public class TestSaxReader implements ContentHandler {
	 	 	 
public TestSaxReader(String fileName) {
	try {
	XMLReader myParser = new SAXParser(); // SAXParser (Xerces)
	myParser.setContentHandler((ContentHandler) this); 
	myParser.parse(fileName); // starten zum Parsen
	} catch (Exception e) {System.out.println("Erreur " + e);	}
}							
		 
public static void main(String args[]) {
	String xmlFileName = "";
	if (args.length == 0) {
								System.out.println("Usage::java XmlLeser path/xmlFilename");
	System.exit(0);
	} else {xmlFileName = args[0];	}

	TestSaxReader pux = new TestSaxReader(xmlFileName);
								
}// end main()	 	

//************************HÄNDLER***********************************	 			
public void startDocument() throws SAXException { 	}

public void endDocument() throws SAXException {	}
			
	boolean skip;
	 			
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
	skip = false;

	 if(localName.equals("name")){
	 System.out.println("Name: ");
	 }else if(localName.equals("adress")){
	 System.out.println("Adress: ");
	 }else{
	 skip = true;}
	 	 		
}//endElement
 			
 public void characters(char[] ch, int start, int length) throws SAXException {
	 					 				if(skip){ return; }
		char[] buffer = new char[length];
	 	System.arraycopy(ch,start,buffer,0,length);
	 	System.out.println(new String(buffer));
}//endCharacters

} //class
```


----------



## Thomas Darimont (13. Juli 2005)

Hallo!


```
/**
  * 
  */
 package de.tutorials;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParserFactory;
 
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
 /**
  * @author Tom
  * 
  */
 public class SaxParserExample {
 
 	/**
 	 * @param args
 	 * @throws ParserConfigurationException
 	 * @throws IOException
 	 * @throws SAXException
 	 */
 	public static void main(String[] args) throws SAXException, IOException,
 			ParserConfigurationException {
 		String xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>"
 		    	+ "<employees>" + "<employee>" + "<name>Krause</name>"
 		    	+ "<age>42</age>" + "<adress> krause@tutorials.de</adress>"
 		    	+ "</employee>" + "<employee>" + "<name>Ullrich</name>"
 		    	+ "<age>27</age>" + "<adress>ruhrweg 12, 23112 Kiel</adress>"
 		    	+ "</employee>" + "<student>" + "<name>Davenport</name>"
 		    	+ "<age>27</age>" + "<adress> dav@tutorials.de</adress>"
 		    	+ "</student>" + "<student>" + "<name>Rutherford</name>"
 		    	+ "<age>22</age>" + "<adress> ford@tutorials.de</adress>"
 		    	+ "</student>" + "<student>" + "<name>Moore</name>"
 		    	+ "<age>29</age>" + "<adress>moore@tutorials.de</adress>"
 				+ "</student>" + "</employees>";
 
 		SAXParserFactory.newInstance().newSAXParser().parse(
 		    	new ByteArrayInputStream(xml.getBytes()), new DefaultHandler() {
 
 					boolean skip;
 
 					boolean isStudent;
 
 		    		public void startElement(String uri, String localName,
 		    		    	String qName, Attributes attributes)
 		    		    	throws SAXException {
 
 						skip = false;
 						
 		    		    if(qName.equals("student")){
 		    		    	isStudent = true;
 		    			}else if(qName.equals("employee")){
 		    		    	isStudent = false;
 						}
 						
 		    		    if(qName.equals("name")){
 		    		    	System.out.print("Name: ");
 		    			}else if(qName.equals("adress") && !isStudent){
 		    		    	System.out.print("Adress: ");
 		    			}else if(qName.equals("age") && isStudent){
 		    		    	System.out.print("Age: ");
 						}else {
 		    		    	skip = true;
 						}
 						
 					}
 
 		    		public void characters(char[] ch, int start, int length)
 		    		    	throws SAXException {
 						if (skip) {
 		    		    	return;
 						}
 
 		    		    System.out.println(new String(ch, start, length));
 					}
 				});
 	}
 }
```
 
 Gruß Tom


----------



## yafoe (13. Juli 2005)

Es hat toll geklappt. Du bist der beste.Danke Tom.
Bei der Übung mit deiner Quelle-Coden verstehe ich die Sache besser. D.h. Parsen und manipulieren von XML-Daten. Ich hoffe, du hast noch "Geduld und Lust" und machst weiter (Lächeln).
Übrigens: die Unterelemente <name>+<adress> von <employee> bzw. <name>+<age> von <student> wurden bisher direkt mit der Methode System.println() dargestellt. 
Neu Problemstellung:
Nun möchte ich eher diese XML-Daten in Objekten (z.B. employee und student) bilden; (Dadurch ist es einfacher neu <student>- bzw. <employee>-Datensätze in XML-datei hinzufügen,ohne in java-Quellcode viel schreiben zu müssen).
Und erst später die jeweilige Objekte aufrufen und mit System.out.println() wiedergeben.

*Ich würde mich gern auf dein Quelle-Code dafür freuen wenn es dir nicht zu umständlich bist.* Thanks in advance


----------



## sportingt (13. November 2006)

Hallo,

gehört zwar nicht ganz direkt dazu aber...

Nutze den SAXParser ganz ähnlich. ich habe jetzt nur ein Problem bei Entity-Referenzen.
Enthält mein Wert ein & kommte es zu Problemen.

Name z.B.
Heinrich & Müller GmbH

in XML-Schreibweise....
<name>Heinrich &amp; Müller GmbH</name>

Der Parser liefert mir das Ergebnis dann in mehreren Stücken.

public void characters(char[] ch, int start, int length)
 		    		    	throws SAXException {
 						if (skip) {
 		    		    	return;
 						}

 		    		    System.out.println(new String(ch, start, length));
 					}
 				});


Der Code Liefert mir dann als Ausgabe nur die zweite Hälfte...
Müller GmbH 

Wie kann man das dann wieder zu einem String zusammenbauen?
Habe das mal mit folgendem probiert.



String value;
public void characters(char[] ch, int start, int length)
 		    		    	throws SAXException {
 						if (skip) {
 		    		    	return;
 						}
value += new String(ch, start, length);

 		    		    System.out.println(value);
 					}
 				});

Das funktioniert auch nicht, da dann alle Inhalte zu einem String zusammengeführt werden. Qulitativ sollten ja nur alle zu dem Tag <name> gehörenden Teile addiert werden.

mfg 
sportingt


----------



## takidoso (13. November 2006)

grob gesagt müsste man den oder die events, die einen tag bzw Element umrahmen verwende um den zusammengesetzten String wieder zu löschen. vermutlich ist di eVerewndung eines Stringbuffers heir angebracht


----------



## Anime-Otaku (14. November 2006)

Nur als kleine Nebenbemerkung....es gibt noch den sogenannnten JAXB von Sun mit dem man aus einer xsd eine Objektstruktur erstellen kann und aus einer xml Datei direkt auslesen kann bzw. aus den Objekten eine xml Datei erstellen kann.


----------



## Thomas Darimont (14. November 2006)

Hallo!



> Der Code Liefert mir dann als Ausgabe nur die zweite Hälfte...
> Müller GmbH


Dieses Verhalten ist übrigens hier beschrieben:
http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/4_refs.html

Wenn du Kontrolle über das XML hast, solltest du den Text einfach als CDATA Section halten:

```
<?xml version="1.0" encoding="ISO-8859-1" ?><name><![CDATA[Heinrich & Müller GmbH]]></name>
```

...damit liefert:

```
/**
 *
 */
package de.tutorials;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * @author Tom
 */
public class SaxParserExample {

  /**
   * @param args
   * @throws ParserConfigurationException
   * @throws IOException
   * @throws SAXException
   */
  public static void main(String[] args) throws SAXException, IOException, ParserConfigurationException {
    String xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>" + "<name><![CDATA[Heinrich & Müller GmbH]]></name>";
    SAXParserFactory.newInstance().newSAXParser().parse(new ByteArrayInputStream(xml.getBytes()),
      new DefaultHandler() {

        public void characters(char[] ch, int start, int length) throws SAXException {
          System.out.println(String.valueOf(ch, start, length).trim());
        }
      });
  }
}
```

Auch:

```
Heinrich & Müller GmbH
```

Btw.:


> Nur als kleine Nebenbemerkung....es gibt noch den sogenannnten JAXB von Sun mit dem man aus einer xsd eine Objektstruktur erstellen kann und aus einer xml Datei direkt auslesen kann bzw. aus den Objekten eine xml Datei erstellen kann.


Eine Alternative dazu wäre übrigens XMLBeans:
http://xmlbeans.apache.org/

Gruß Tom


----------



## sportingt (21. November 2006)

Hallo,


<![CDATA[Heinrich & Müller GmbH]]>

Die Lösung ist wohl die beste.

Grundsätzlich habe ich den Eindruck, dass der SAXParser eh nicht so ganz sauber läuft.
Manchmal habe ich auch den Effekt wenn gar kein von den verbotenen Zeichen (< > & " ') im ganzen XML vorhanden ist, dass dann nur ein Teil des Wertes eingelesen wird.
Makiert man dann den Inhalt wie oben beschrieben geht es.

Da solche Probleme öfters zwischen dem Wechsel von Unix zu Windows auftreten vermute ich das es auch an der Codierung liegen kann.
Gibt es da eigendlich ne Möglichkeit zu prüfen wie eine bestimmte Datei kodiert ist?
wenn ich z.B. ne XML mit vi unter Linux erzeuge, sie dann nach Windows kopiere und mit dem Editor öffne, ändere und speichere. Muß ich dann auch im XML-Header die Codierung ändern?
Bis jetzt habe ich auf beiden Systemen  immer 
encoding="UTF-8" angegeben un es ging bisher fast immer. Wie gesagt fast immer.

mfg

sportingt


----------



## takidoso (22. November 2006)

sportingt hat gesagt.:


> Hallo,
> 
> 
> <![CDATA[Heinrich & Müller GmbH]]>
> ...



Also so wie ich SAX verstehe ist es doch so, dass es der Parserimplementierung hier überlassen wird, wie viele Zeichen in der characters-Routine mitgegeben wird. Hat vermutlich Performancegründe, die von Implementation zu Implementation verschieden gelöst sein kann. Alles was man da tun muss ist den String so lange sammeln bis das erwartete Ende (vermutlich durch einen Ende-Tag -Event gekennzeichnet) auftaucht. 

Die anderen Lösungen wie z.B. JAXB sind mitunter vielleicht ganz bequem, aber siei verbratzen halt auch erheblich mehr resourcen, vor allem wenn es sich um sehr große Dateien handelt.
Ich glaube dass die Codierung der XML vielleicht Einfluß haben kann, aber eigetnlich sollte dass dennoch kein Hindernisgrund sein, da mit der richtigen Zeichensammelmimik sollte das bei allen Codierungen auch unabhängig vom Betriebssystem funktionieren.

Takidoso


----------



## maddos (28. November 2006)

Hallo
Ich habe eine Frage und zwar geht es darum, die ausgelesene Parameter in eine neue oder bereits exestierende XML Datei zu schreiben, ohne dabei irgendwas noch zu ändern, also nur die Attribute und Parameter zu ändern. Ich habe die Attribute und Parameter mit SAXPArser gelesen und in eine Map gespeichert:

```
import com.sun.org.apache.xerces.internal.parsers.SAXParser;
import java.util.HashMap;
import java.util.Map;
import org.xml.sax.AttributeList;
import org.xml.sax.DocumentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

public class XMLSaxParser implements DocumentHandler {
    
    private String ATTRIBUTE = "";
    private String VALUE = "";
    private static Map<String, String> map = new HashMap<String, String>();
    /** Konstruktor für Objekte der Klasse XMLSaxParser */
    public XMLSaxParser(String uri) {
        parse(uri);
    }
    
    private void parse(String file) {
        SAXParser parser = new SAXParser();
        parser.setDocumentHandler(this);
        try {
            parser.parse(file);
        } catch (Exception e) {
            System.err.println("Fehler beim Parsen");
            System.err.println(e);
        }
    }
    
    public void setDocumentLocator(Locator locator) {
    }
    
    public void startDocument() throws SAXException {
    }
    
    public void endDocument() throws SAXException {
    }
    
    public void startElement(String name, AttributeList attrs) throws SAXException {
        if (attrs != null) {
            int length = attrs.getLength();
            for (int i = 0; i < length; i++) {
//                System.out.println(attrs.getValue(i));
                setATTRIBUTE(attrs.getValue(i));
            }
        }
    }
    
    public void endElement(String name) throws SAXException {
    }
    
    public void characters(char[] ch, int start, int length) throws SAXException {
        String temp = new String(ch, start, length);
//        System.out.print(new String(ch, start, length));
        if (!temp.equals("")) {
            setVALUE(new String(ch, start, length));
            saveToMap(getATTRIBUTE(), getVALUE());
        }
    }
    
    
    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
//        characters(ch, start, length);
    }
    
    public void processingInstruction(String target, String data) throws SAXException {
    }
    
    public String getATTRIBUTE() {
        return ATTRIBUTE;
    }
    
    public void setATTRIBUTE(String ATTRIBUTE) {
        this.ATTRIBUTE = ATTRIBUTE;
    }
    
    public String getVALUE() {
        return VALUE;
    }
    
    public void setVALUE(String VALUE) {
        this.VALUE = VALUE;
    }
    
    public void saveToMap(String element, String value) {
        map.put(element, value);
    }
    
    public Map<String, String> getMap() {
        return map;
    }
```

Beispiel von XML datei:

```
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>
        <property name="Das ist Attribute">Das ist Wert</property>
        <property name="Das ist Attribute2">Das ist Wert2</property>
        u s.w.
    </session-factory>

</hibernate-configuration>
```
So, jetzt will ich z.B die Attribute und deren Werte ändern und speichern (in diese oder eine neue Datei) und das klap irgendwie nicht. Ich bitte um Hilfe.


----------



## maddos (29. November 2006)

Ok, ich habs selber geschafft. Ich habe die Library JDOM verwendet: http://www.jdom.com
Damit kann man das sehr komfortabel und einfach ohne viel quell code machen.


----------

