XML-Daten mit SAX auslesen

yafoe

Grünschnabel
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
 
Hallo!

schau mal hier:
Code:
/**
  * 
  */
 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
 
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)

Code:
<?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:
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
 
Hallo!

Code:
 /**
  * 
  */
 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
 
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
 
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
 
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
 
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.
 
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:
<?xml version="1.0" encoding="ISO-8859-1" ?><name><![CDATA[Heinrich & Müller GmbH]]></name>

...damit liefert:
Java:
/**
 *
 */
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:
Code:
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
 
Zuletzt bearbeitet von einem Moderator:
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
 
Zurück