Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
ich habe im Unterforum Java Anfänger gepostet, wie man Informationen aus dem Internet abfragt.
Leider habe ich noch keine Lösung finden können. Ich arbeite gerade im Buch JAXB 2.0 vom Hanser Verlag und von Galileo Computing Einstieg in XML.
Leider ist es viel und umfangreich und zur Erstellung eines Abfragemoduls würde ich gerne wissen wie man da am besten vorgeht.
So wie ich das erkennen konnte habe ich in meinem Java Programm der Klasse Buch, die Instanzvariablen enthalten und die durch die Datenbank über die "Deutsche Nationalbibliothek" gefüllt werden sollen.
Ich habe die Instanzvariable ISBN, einen Inhalt, den ich an die Datenbank sende.
Wie ich das verstanden haben, muss ich diese Information an die Datenbank senden. DNB - SRU-Schnittstelle
Diese muss formuliert werden, so das der Inhalt der Instnazvariable in die URL an die Datenbank eingeflochten wird.
Ich denke mal das es ungefähr so aussehen muss?
Dann erhalte ich eine Antwort die mir ein XML zurückgibt.
Wie das genau funktioniert, weiss ich noch nicht! Ist die XML dann im Hautspeicher, auf Festplatte???
Also diese XML gilt es dann zu konvertieren und zwar so das es dann zu Java Passt und die Werte in die Instanzvariablen übergeben werden können. Ich glaube das heisst dann Unmarshall.
Das ganze wird dann realisiert, indem man XML-Schema definiert, in dem die XML als SchemaInstanz zurückgibt?
Ich habe schon einiges gelesen, aber der Zusammenhang ist noch nicht so ganz klar?
Was mache ich also als erstes?
1. Die Klasse Buch mit den Instanzvariablen anschauen und dazu ein XML Schema bauen?
Wenn man das als Link im Browser eingibt bekommt man:
[XML]<diagnostics>
<diag:diagnostic>
<diag:uri>info:srw/diagnostic/1/68</diag:uri>
<diag:details>Not authorized to send record in this schema</diag:details>
<diag:message>Not authorized to send record in this schema / MARC21-xml. No Account for IpAddress: DEINE IP ADRESSE</diag:message>
</diag:diagnostic>
</diagnostics>[/XML]
Das heißt das du dich dort registrieren mußt. Dann wird entweder eine ip Adresse, wenn du eine Feste besitzt mit deinem Konto verknüpft oder du bekommst ein Token mit dem du dich authentifizieren kannst. Du mußt dich allerdings erst registrieren.
Dann sieht ein Aufruf so aus: xXxX steht für das Token
Normalerweise wird mittels java.net.URL("Die URL die aufgerufen werden soll"); ein URL Objekt erstellt.
Vergleichbar mit einem Link auf dem Desktop. Das URL Objekt bietet dann eine Methode openStream an die einen InputStream zurückliefert. Dieser kann dann ausgelesen werden. Aber man kann davon ausgehen, daß der Stream Inhalt dann irgendwo im Speicher landet.
Dieser InputStream läßt sich so ziemlich gleich behandeln wie ein FileInputStream, oder System.in, falls du diese schonmal verwendet hast.
In Java und überhaupt gibt es viele Möglichkeiten XML zu verarbeiten.
Un/Marshalling beschreibt den Prozess XML in Java-Objekte und Umgekehrt zu konvertieren.
Das XML Schema entspricht dann den Java Klassen.
Das XML Dokument entspricht dann einer Menge von Java Objekt Instanzen.
Je nachdem in welche Richtung man gehen möchte, so unterscheidet sich auch deren Vorgehensweise
den Input-Stream habe ich noch nicht benutzt, werde mich aber damit auseinander setzen.
Wenn die URL ein Objekt erzeugt, und der Stream als XML Format zurückgegeben wird, dann wäre die weitere Verfahrensweise, den erhaltenen Inhalt zu konvertieren (Unmarshall) und in die Objektinstanzen der Klasse Buch zu überführen. :rtfm:
Ich habe ein Token und auch schon erfolgreich eine Suchanfrage über den Browser gemacht und eine gültige Rückanwort erhalten, die auch alle Informationen beinhaltet.
Als nächstes gilt wohl das Unmarshall zu machen.
Ich lese ausser in dem JAX buch noch XML-XSL für professionelle Einsteiger.
Das erlernen von XML ist ja genau wie bei Java ziemlich umfangreich und auch eine eigene Beschreibungssprache mit eigenen Datentypen und so.
Ich denke das wird noch ein ganze weile dauern.
Jetzt lerne ich erst mal das erstellen eines Schemas.
Ein XML Datenmodell werd eich wahrscheinlich nicht benötigen.
Dann erhalte ich eine Antwort die mir ein XML zurückgibt.
Wie das genau funktioniert, weiss ich noch nicht! Ist die XML dann im Hautspeicher, auf Festplatte???
Du denkst zu kompliziert... Du meinst wahrscheinlich für XML muss man ein bauch lesen... das ist dazu da daten für maschine und menschen lesbar zu machen... da reicht ein 5 min tutorial...
hauptspeicher, festplatte... ja das kommt darauf an, wie du das ließst...
unmarshalling.... du kannst dir das ganze auch mit einfachen String operationen auslesen... oder bisschen komplexer dom oder ganz profi mäßig mit jaxb...
schick mir nochmal dein amazon dings projekt ich hab das nicht bekommen, ich hab morgen einwenig zeit, freundin ist auf einer hochzeit, da kann ich mir das ansehen...
Da ich der Meinung bin ein Buch lesen zu müssen, liegt daran das ich weder HTML gut kann noch weiss wie XML funktioniert.
Deshalb dachte ich mir mich mal mit den Grundlegenden Dingen vertraut zu machen.
Nach all der Recherche im Internet bin ich auf JAX gestossen.
Ich gebe zu es ist ziemlich umfangreich, aber ich dachte das wird so gemacht.
Da ich auch gerade in Java eingestiegen bin, war ich auch nicht sonderlich begeistert noch nebenbei XML zu machen. Ich denke aber das die Abfrage von Informationen aus dem Internet für mich bestimmt noch öfters von Bedeutung sein kann und deshalb möchte ich auch die Deutsche National Bibliothek abrufen können.
Hi Mittlerweile habe ich es mit dem Tutorial geschafft aus einem XML Dokument ein paar Elemente auf die Konsole aus zu geben.
Ich habe da mal eine Frage bezüglich der Kindelemente die eine Reihe tiefer sitzen.
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.XMLOutputter;
public class JDOMBuchLesen
{
public static void main(String[] args)
{
// initialisieren JDOM Objekt
Document buchObjekt = null;
// File Objekt Erzeugen
File buchFile = new File("buch.xml");
try
{
// Das SAX Buch-Dokument erstellen
SAXBuilder jdomBuchDokument = new SAXBuilder();
// JDOM Objekt den Inhalt der XML einlesen
buchObjekt = jdomBuchDokument.build(buchFile);
// XML Inhalt in die Variable schreiben (Writer)
// XMLOutputter xmlAusgabe = new XMLOutputter();
// komplettes XML Dokument ausgeben
// xmlAusgabe.output(buchObjekt, System.out);
// Wurzelelement erzeugen
Element element = buchObjekt.getRootElement();
System.out.println("\nWurzelelement: " + element);
// Name aus dem Wurzelelement ausgeben
System.out.println("Wurzelelementname: " + element.getName());
// Liste aller direkten Kindelemente eines elementes erstellen
List alleKinder = (List) element.getChildren();
// Alle Kindelemente nacheinander ausgeben
for (int i=0; i<15; i++)
{
System.out.println(i + ". Kindelement: " + ((Element) alleKinder.get(i)).getName());
}
// Eine Liste aller direkten Kindelemente eines benannten Elementes Erstellen
List benannteKinder = element.getChildren("verfasser");
// Das erste Kindelement ausgeben
System.out.println("benanntes Kindelement: " + ((Element) benannteKinder.get(0)).getName());
}
catch (JDOMException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Es soll dann eine Liste der Kindelemente von den benannten Element Verfasser ausgeben.
Wenn ich den Wert 0 lasse, gibt es verfasser aus, gerechnet hatte ich mit name(0) und vorname(1)
Du brauchst die Kinderelemente von dem Knoten "Verfasser" momentan gibst du nur den Namen des 0. Element der Liste von Knoten im Rootelement mit Namen "Verfasser" aus.
Vielen Dank,
das habe ich auch gesehen, als ich den code ausgeführt habe.
Im Tutorial wird das auch nicht gezeigt, wie mann dann die weiteren Kindelemente heran kommt. ???:L
Auch die Syntax ist mir neu: ((Element) alleKinder.get(0)).getName())
Ist wohl abhängig der Klassenbiblothek ob der Typ in Klammern geschrieben wird oder nicht.
Die XML-Datei, die ich jetzt mal erstellt habe ist relativ kurz.
Wenn eine andere XML eingelesen wird, die länger ist, so bildet sich die Modellstruktur anders ab.
[XML]
<?xml version="1.0" encoding="UTF-8"?><collection xmlns="http://www.loc.gov/MARC21/slim">
<record type="Bibliographic">
<leader>01347pam a2200409 c 4500</leader>
<controlfield tag="001">989219313</controlfield> <?-- Kontrollnummer -->
<controlfield tag="003">DE-101</controlfield> <?-- Kontrollunmmer-Identifier -->
<controlfield tag="005">20081104235231.0</controlfield> <?-- Datum und Zeit der letzten Transaktion -->
<controlfield tag="007">tu</controlfield> <?-- Physische Beschreibung "Bücher" -->
<controlfield tag="008">080617s2008 gw |||||r|||| 00||||ger </controlfield> <?-- Datenelement mit fester länge -->
<datafield tag="015" ind1=" " ind2=" "> <?-- Nummer der Nationabibliografie -->
<subfield code="a">08,A46,0093</subfield> <?-- -->
<subfield code="z">08,N27,0049</subfield> <?-- -->
<subfield code="2">dnb</subfield> <?-- -->
</datafield>
<datafield tag="016" ind1="7" ind2=" "> <?-- Kontrollnummer der Nationalen Bibliografischen Stelle -->
<subfield code="2">DE-101</subfield> <?-- erste Stelle -->
<subfield code="a">989219313</subfield> <?-- zweite Stelle -->
</datafield>
<datafield tag="020" ind1=" " ind2=" "> <?-- Internationale Standardbuchnummer -->
<subfield code="a">9783834805690</subfield> <?-- xx Internationale Standardbuchnumer -->
<subfield code="c">kart. : EUR 19.90</subfield> <?-- xx Bezugsbedingungen -->
<subfield code="9">978-3-8348-0569-0</subfield> <?-- xx ISBN mit Bindestrich -->
</datafield>
<datafield tag="024" ind1="3" ind2=" "> <?-- Anderer Standard-Identifier ind1=(UPC) Universal Product Code ind2=(ISMM)International Standard Music Number -->
<subfield code="a">9783834805690</subfield> <?-- Standardnummer oder code -->
</datafield>
.....
....
...
[/XML]
Das bedeutet, das mal mehr mal weniger Daten im Modell eingelesen werden.
Also muss ich halt nur schauen, welche Daten für mich relevant sind und nach diesen im Modell suchen und entsprechend ausgeben oder in Variablen weiterverarbeiten?
die ISBN benutze ich nur einmal und zwar um diese XML Datei zu finden und von der Datenbank zu holen. Die ganzen Metadaten, die ich dann lesen möchte hole ich dann anhand der Codes in das DOM Modell.
gibt dir eine liste von elementen die in dem element 0 enthalten sind. das ganze ist endlos verschachtelt, wo ist dein Problem?
du könntest auf jedes element dieser liste wieder jede beliebige operation für elemente ausführen, wie auch die liste alle kindelemente geben zu lassen.
wie wäre es wenn du erstmal versuchst ein leichtes xml einzulesen?
[XML]<Computer>
<Prozessor>
<Hersteller>AMD</Hersteller>
<Takt>2 GHz</Takt>
</Prozessor>
<Laufwerk Typ="CD" />
<Laufwerk Typ="HDD">
<Partition Groesse="4">C:</Partition>
<Partition Groesse="4">D:</Partition>
</Laufwerk>
<Laufwerk Typ="HDD">
<Partition Groesse="4">E:</Partition>
</Laufwerk>
<Motherboard Sockel="abc" Ramslots="3">
<Ram Groesse="4">Kingston</Ram>
<Ram Groesse="4">MSI</Ram>
<PCI>
<Grafikkarte />
<Soundkarte />
<Netzwerkkarte />
</PCI>
</Motherboard>
</Computer>[/XML]
Wenn du mit ner schleife über alle Kindelemente gehst, fragst du die attribute des elements ab und vergleichst die tag nummer.
passt sie, nehmen wir an du suchst nach dem preis, also tag=20, dann lässt du dir wieder alle childs für das element geben, vergleichst den code (und eventuell name) und lässt diese schleifen laufen bis du code = 9 findest. dann liest du die daten aus diesem diesem element aus.
So, soweit klappt alles. :toll:
Jetzt habe ich sogar schon die Suchabfrage mit in Java integriert und das Ergebnis wird mir in ein String-Objekt zurückgegeben.
Jetzt beginnt die eigentliche Arbeit mit dem durchlaufen der entsprechenden Tags.
Das heisst das DOM Modell wird je nach länge der XML aufgebaut, aber nur die Einträge, die mich interessieren bleiben immer gleich und die ziehe ich dann heraus.
Wenn du mit ner schleife über alle Kindelemente gehst, fragst du die attribute des elements ab und vergleichst die tag nummer.
passt sie, nehmen wir an du suchst nach dem preis, also tag=20, dann lässt du dir wieder alle childs für das element geben, vergleichst den code (und eventuell name) und lässt diese schleifen laufen bis du code = 9 findest. dann liest du die daten aus diesem diesem element aus.
Naja ich denke da hatte ich etwas falsch verstanden.
Das DOM ist ja ein Baum, und durch den kommt man nur durch das ablaufen der einzelnen Knotenpunkte.
// Wurzelelement erzeugen
Element wurzelElement = buchObjekt.getRootElement();
System.out.println("\nWurzelelement: " + wurzelElement.getName());
// Kindelemente von records, Kindelelement von der Wurzel
List recordsKinder = wurzelElement.getChildren("records");
System.out.println("Records Kinder" + recordsKinder);
// Kindelemente von record, Kindelement von records
List recordKinder = (List) recordsKinder.getchildren("record");
System.out.println("Record Kinder: " + recordKinder);
Einen Compilerfehler erhalte ich schon bei List record Kinder =... weil ich dort keine getChildren verwenden kann.
Bei der Ausgabe erhalte ich bei Records Kinder einfach nur []
Dann wollte ich mich von benannten Knoten zu benannten knoten hangeln.
Java:
// Wurzelelement erzeugen
Element wurzelElement = buchObjekt.getRootElement();
System.out.println("Wurzelelement: " + wurzelElement.getName());
// Nächster Vater records, Kindelelement von der Wurzel
Element recordsVater = wurzelElement.getChild("records");
System.out.println("Neuer Vater records: " + recordsVater.getName());
// Nächster Vater record, Kindelement von records
Element recordVater = recordsVater.getChild("record");
System.out.println("Neuer Vater record: " + recordVater.getName());
Compilerfehler gibt es nicht, nur Laufzeitfehler ?
Und zwar fängt das schon an ab hier
Java:
System.out.println("Neuer Vater records: " + recordVater.getName());
<?xml version="1.0" encoding="UTF-8"?>
<buch>
<titel>Algorithmen kompakt und verständlich</titel>
<untertitel>Lösungsstrategien am Computer</untertitel>
<inhalt>http://d-nb.info/989219313/04</inhalt>
<records>
<record />
</records>
<sachschlagwort>Algorithmus</sachschlagwort>
<masse>24 cm</masse>
<bezugsbedinnungen>kart. : EUR 19.90</bezugsbedinnungen>
</buch>
Wurzelelement: buch
Neuer Vater records: records
Neuer Vater record: record
Ich bin mit XML noch nicht so gut vertraut, aber mir ist dann aufgefallen, das die abgefragte XML Datei anders beginnt.
ich bin immer noch dran den XML Inhalt aus zu werten.
Hier mal einen Auszug
Java:
Document buchObjekt = null;
String isbn13 = "9783834805690";
String secretToken = "xxxXXXxxxXXXxxxXXXxxxXXXxxxXXXxxx";
// Sendet die Abfrage an die Datenbank und speichert das Ergebnis in sruAbfrage
String sruAbfrage = "https://services.dnb.de/sru/dnb?version=1.1&operation=searchRetrieve&query=NUM%3D" + isbn13 + "&recordSchema=MARC21-xml&accessToken=" + secretToken;
// Rückgabeobjekt
String buchRueckgabe = new String(sruAbfrage);
Das bedeutet ich sende eine Abfrage und erhalte eine XML Datei zurück, die direkt in den String sruAbfrage gespeichert wird.
Ich bin mir jetzt nicht mehr sicher, ob ich da ein XML mit einer DTD, Schema brauche um teile des Inhaltes in Java Objekte zu speichern.
Mit dem DOM Modell habe ich es versucht und konnte da nicht Navigieren.
Ist jetzt die Frage was mache ich mit dem Inhalt der String Variable, die ein XML Format enthält?
Da ich nicht alle Informationen daraus benötige, hatte ich gedacht mit einer DTD informationen zu excluden.
Die letzten 20 Tage habe ich mit XML Grundlagen und DTDs verbracht und konnte schon Ergebnisse erzielen, aber habe nicht so den richtigen durchblick was mir das bringen soll?
Zur Zeit habe ich keinen Plan, wie ich da weiter verfahren soll.
Poste mal das XML das raus kommt? Wo genau liegt dein Problem, wenn du so Probleme mit der Verarbeitung hast, warum machst du es nicht einfach mit String Operationen?
Du denkst zu kompliziert... gibt viele Arten wie du die Daten da aus dem String raus hohlen kannst...
Ich wollte die Knoten auslesen und erhalte folgende Meldungen
Code:
run:
Wurzelelement: searchRetrieveResponse
Exception in thread "main" java.lang.NullPointerException
at JDOMBuchAbfrage.main(JDOMBuchAbfrage.java:47)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)
Das Wurzelelement wird korrekt angezeigt.
Die Zeile java:47 ist die hier
Java:
System.out.println("Neuer Vater records: " + recordsVater.getName());
Das ist die Ausgabe des nächsten Knotens.
Ich habe auch mal die System.out Anweisungend der nächsten Vaterknoten auskommentiert.
Der Vaterknoten "records" machte dann keine Probleme bei der Ausführung des Codes.
Der Vaterknoten "record" machte dann aber doch Probleme.
Ich denke, ich werde mal SAX Beispiele suchen und damit mal herum experimentieren.
Es wäre vielleicht auch schneller und Ressourcen schonender, wenn man den Stream mit Ereignissen auswertet und nur die Informationen behält, die man dabei heraus filtert.
ich denke ich bin jetzt auf der richtigen Spur.
Ich habe alles gut lösen können, sobald in der XML keine Attribute vorkamen.
Jetzt habe ich mal einen Auszug einer XML Datei mit Attributen gemacht um mal zu sehen, ob ich in die richtige Richtung laufe.
Da sind jetzt noch keine Namespace drin, aber zumindest Attribute und Zeichenketten.
Auch habe ich mal die Variablen ausgegeben, um zu sehen, was da überhaupt so drin steht.
/* Entwurf einer SAX Anwendung */
package Bibliothek;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import java.io.*;
// Klasse als Erweiterung der Basisklasse DefaultHandler
public class SaxEntwurf extends DefaultHandler
{
// Variablendefinition
private String isbn13;
private String isbn15;
private String bezug;
/*
* Methoden des ContentHandlers
*/
// wird vom Parser ausgeführt, wenn er den Anfang des XML Dokumentes findet
public void startDocument() throws SAXException
{
System.out.println("Beginn der XML-Auswertung");
}
// wird vom Parser jedesmal aufgerufen, wenn ein Start-Tag gefunden wird
public void startElement(String namespaceURI, String localName, String qName,
Attributes attr) throws SAXException
{
// System.out.println("Es wurde ein Start-Tag gefunden");
System.out.println("Start-Tag namespaceURI: " + namespaceURI);
System.out.println("Start-Tag localName : " + localName);
System.out.println("Start-Tag qName : " + qName);
System.out.println("Start-Tag Attribut : " + attr);
}
// liefert Zeichendaten von Elementen, die keine Kindelemente enthalten
public void characters(char[] ch, int start, int length) throws SAXException
{
if (length > 0)
{
String zeichenkette = new String(ch, start, length);
System.out.println("Die Zeichenkette ist: " + zeichenkette);
}
}
// wird vom Parser jedesmal aufgerufen, wenn ein end-Tag gefunden wird
public void endElement(String namespaceURI, String localName,
String qName) throws SAXException
{
// System.out.println("Es wurde ein End-Tag gefunden");
System.out.println("End-Tag namespaceURI: " + namespaceURI);
System.out.println("End-Tag localName : " + localName);
System.out.println("End-Tag qName : " + qName);
}
// wird vom Parser aufgerufen, wenn das Ende des Dokumentes gemeldet wurde
public void endDocument() throws SAXException
{
System.out.println("Ende der XML-Auswertung");
}
// Zugriff und Umwandlung der Datenquelle wenn von einer Datei gelesen wird
private static String convertToFileURL(String filename)
{
// path = file.toURL().toString()
String path = new File(filename).getAbsolutePath();
if (File.separatorChar != '/')
{
path = path.replace(File.separatorChar, '/');
}
if (!path.startsWith("/"))
{
path = "/" + path;
}
return "file:" + path;
}
// Start der Verarbeitung des Dokumentes (Aufruf des Parsers)
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException
{
String filename = "src/Bibliothek/testbuch.xml";
// Start des Parsens Prozesses durch erzeugen einer Factory
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
// Konfiguration der Factory
saxFactory.setNamespaceAware(true);
// Durch die Factory eine neue Instnaz der Klasse JAXParser erzeugen
SAXParser saxParser = saxFactory.newSAXParser();
// XMLReader-Schittstelle durch Methode getXMLReader()
XMLReader xmlReader = saxParser.getXMLReader();
// Registriert die Schnittstelle ContentHandler beim XMLReader und gibt
// die aktuelle Anwendung SaxEntwurf als Klasse an, die über Parser-
// Ereignisse zu informieren ist. Es wird mit new eine Instnaz erzeugt
// und damit ein hadnlunfsfähiges Objekt erzeugt, damit die deklarierten
// Methoden zum Einsatz kommen kann.
xmlReader.setContentHandler(new SaxEntwurf());
// Registrierung der Fehlerbehandlungen
// xmlReader.setErrorHandler(new FehlerHandler(System.err));
// Der XMLReader erhält den Auftrag das XML-Dokument zu parsen
xmlReader.parse(convertToFileURL(filename));
}
}
Und die Ausgabe:
Beginn der XML-Auswertung
Start-Tag namespaceURI:
Start-Tag localName : searchRetrieveResponsesearchRetrieveResponse
Start-Tag qName : searchRetrieveResponsesearchRetrieveResponse
Start-Tag Attribut : com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@2a8f5fc2
Die Zeichenkette ist:
Start-Tag namespaceURI:
Start-Tag localName : records
Start-Tag qName : records
Start-Tag Attribut : com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@2a8f5fc2
Die Zeichenkette ist:
Start-Tag namespaceURI:
Start-Tag localName : record
Start-Tag qName : record
Start-Tag Attribut : com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@2a8f5fc2
Die Zeichenkette ist:
ich würd etwas objektorientierter denken. du willst ja irgendetwas aus dem ergenis auslesen und damit weiterarbeiten? Was ist das? Man könnte sich zb ein Ergebnis Objekt bauen...
mal als Beispiel:
Java:
public class SearchResult {
private String isbn13;
private String isbn13Code;
private String isbn15;
private String bezug;
public String getIsbn13() {
return isbn13;
}
public void setIsbn13(String isbn13) {
this.isbn13 = isbn13;
}
public String getIsbn13Code() {
return isbn13Code;
}
public void setIsbn13Code(String isbn13Code) {
this.isbn13Code = isbn13Code;
}
public String getIsbn15() {
return isbn15;
}
public void setIsbn15(String isbn15) {
this.isbn15 = isbn15;
}
public String getBezug() {
return bezug;
}
public void setBezug(String bezug) {
this.bezug = bezug;
}
@Override
public String toString() {
return "SearchResult [isbn13=" + isbn13 + ", isbn13Code=" + isbn13Code + ", isbn15=" + isbn15 + ", bezug=" + bezug + "]";
}
}
Dann kann man im Handler schön auf die Ereignisse reagieren und das Ergebnis Objekt füllen...
zb so... das geht natürlich noch sauberer... aber sax ist auch schon etwas älter und ich mach das sonst auch nie so...
Java:
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class SaxEntwurf extends DefaultHandler {
private SearchResult currentResult;
private List<SearchResult> results;
String currentValue;
public void startDocument() throws SAXException {
System.out.println("Beginn der XML-Auswertung");
results = new ArrayList<SearchResult>();
}
public List<SearchResult> getResults() {
return results;
}
public void startElement(String namespaceURI, String localName, String qName, Attributes attr) throws SAXException {
//bei record Data fangen wir ein neues ergebnis an...
if("recordData".equalsIgnoreCase(localName)){
currentResult = new SearchResult();
results.add(currentResult);
}
//wir setzen mal nur den code von isbn13... die andern kannst du selber machen
for (int i = 0; i < attr.getLength(); i++) { //hier iterieren wir einfach über die attriute
if("isbn13".equalsIgnoreCase(localName) && "code".equalsIgnoreCase(attr.getLocalName(i))){
currentResult.setIsbn13Code(attr.getValue(i));
}
}
}
//ist der tag zu ende kann man den aktuellen wert in die variable schreiben...
public void endElement(String uri, String localName, String qName) throws SAXException {
if("isbn13".equalsIgnoreCase(localName)){
currentResult.setIsbn13(currentValue);
}else if("isbn15".equalsIgnoreCase(localName)){
currentResult.setIsbn15(currentValue);
}else if("bezug".equalsIgnoreCase(localName)){
currentResult.setBezug(currentValue);
}
}
// hier bekommen wir den aktuellen wert...
public void characters(char[] ch, int start, int length) throws SAXException {
currentValue = new String(ch, start, length);
}
// Zugriff und Umwandlung der Datenquelle wenn von einer Datei gelesen wird
private static String convertToFileURL(String filename) {
// path = file.toURL().toString()
String path = new File(filename).getAbsolutePath();
if (File.separatorChar != '/') {
path = path.replace(File.separatorChar, '/');
}
if (!path.startsWith("/")) {
path = "/" + path;
}
return "file:" + path;
}
// Start der Verarbeitung des Dokumentes (Aufruf des Parsers)
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
String filename = "d:/testdata.xml";
// Start des Parsens Prozesses durch erzeugen einer Factory
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
// Konfiguration der Factory
saxFactory.setNamespaceAware(true);
// Durch die Factory eine neue Instnaz der Klasse JAXParser erzeugen
SAXParser saxParser = saxFactory.newSAXParser();
// XMLReader-Schittstelle durch Methode getXMLReader()
XMLReader xmlReader = saxParser.getXMLReader();
// Registriert die Schnittstelle ContentHandler beim XMLReader und gibt
// die aktuelle Anwendung SaxEntwurf als Klasse an, die über Parser-
// Ereignisse zu informieren ist. Es wird mit new eine Instnaz erzeugt
// und damit ein hadnlunfsfähiges Objekt erzeugt, damit die deklarierten
// Methoden zum Einsatz kommen kann.
SaxEntwurf handler = new SaxEntwurf();
xmlReader.setContentHandler(handler);
// Registrierung der Fehlerbehandlungen
// xmlReader.setErrorHandler(new FehlerHandler(System.err));
// Der XMLReader erhält den Auftrag das XML-Dokument zu parsen
xmlReader.parse(convertToFileURL(filename));
//wir sind fertig... ausgeben...
System.out.println(handler.getResults().size()+" Ergebnisse");
for(SearchResult result : handler.getResults()){
System.out.println(result);
}
}
}
mit der liste von SearchResult kann man dann super weiterarbeiten.. in db speichern, in gui anzeigen, rechnen usw...
ich würd solche kommentare lassen...
// Variablendefinition
Da ich in den letzten 20 Tagen nur XML Grundlagen gemacht habe, brauche ich ein wenig Zeit um mein gelerntes Java Wissen wieder zu reaktivieren.
Objektorientierter wollte ich eigentlich schon programmieren und hatte auch die Klasse Buch, die ich auch schon in den vorherigen Beispielen verwendet habe.
Auszug aus Klasse "Buch.java"
Java:
/* Datenhalter für Buchdaten */
package de.michael;
public class Buch
{
String bufferNummer;
String bufferCode;
String isbn13;
String isbn15;
String bezug;
public String getBufferNummer()
{
return bufferNummer;
}
public void setBufferNummer(String bufferNummer)
{
this.bufferNummer = bufferNummer;
}
public String getBufferCode()
{
return bufferCode;
}
public void setBufferCode(String bufferCode)
{
this.bufferCode = bufferCode;
}
public String getIsbn13()
{
return isbn13;
}
public void setIsbn13(String isbn13)
{
this.isbn13 = isbn13;
}
public String getIsbn15()
{
return isbn15;
}
public void setIsbn15(String isbn15)
{
this.isbn15 = isbn15;
}
public String getBezug()
{
return bezug;
}
public void setBezug(String bezug)
{
this.bezug = bezug;
}
}
Da ich Tags und Codes als Vorlage habe die zu einem Schlüssel passen, habe ich mir gedacht die Tags und Codes heraus zu lesen und dann zusammen zu setzen, um die gefundene Zeichenkette darin zu speichern.
Klasse "XMLextractorMarc21.java"
Java:
package de.michael;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* @author Michael
*
*/
public class XMLextractorMarc21 extends DefaultHandler
{
String bufferNummer; // Tagnummer (020, ...)
String bufferCode; // TagCode (a, b, ...)
String tag020codeA; // ISBN 13 Nummer
String tag020codeC; // Bezugsart
String tag020code9; // ISBN 15 Nummer
/*
* Default Handler Methoden
*/
// wird vom Parser ausgeführt, wenn er den Anfang des XML Dokumentes findet
public void startDocument() throws SAXException
{
System.out.println("Beginn der XML-Auswertung");
}
// wird vom Parser jedesmal aufgerufen, wenn ein Start-Tag gefunden wird
public void startElement(String namespaceURI, String localName,
String qName, Attributes attr) throws SAXException
{
// Der Attributinhalt ist der orange Dargestellte Wert (020, a, b, ...)
if (attr.getValue(0).length() > 1)
{
bufferNummer = attr.getValue(0);
System.out.println("Die bufferAttributnummer ist: " + bufferNummer);
} else
{
bufferCode = attr.getValue(0);
System.out.println("Der bufferAttributCode ist: " + bufferCode);
}
}
// liefert Zeichendaten von Elementen, die keine Kindelemente enthalten
public void characters(char[] ch, int start, int length)
throws SAXException
{
if (length > 0)
{
// Benötigte TagCodes
// 020 ab9, 245 abc, 250 a , 260 abc, 300 abc, 490 a, 856 mqu3
String zeichenkette = new String(ch, start, length);
System.out.println("Die Zeichenkette ist: " + zeichenkette);
String buchCode = bufferNummer + bufferCode;
if ("020a".equals(buchCode))
{
tag020codeA = zeichenkette;
System.out.println("Buchcode tag020codeA enthält: "
+ tag020codeA);
} else if ("020c".equals(buchCode))
{
tag020codeC = zeichenkette;
System.out.println("Buchcode tag020codeC enthält: "
+ tag020codeC);
} else if ("0209".equals(buchCode))
{
tag020code9 = zeichenkette;
System.out.println("Buchcode tag020code9 enthält: "
+ tag020code9);
}
}
}
// wird vom Parser aufgerufen, wenn das Ende des Dokumentes gemeldet wurde
public void endDocument() throws SAXException
{
System.out.println("Ende der XML-Auswertung");
System.out.println("Die ISBN13 Nummer ist: " + tag020codeA);
System.out.println("Die ISBN15 Nummer ist: " + tag020code9);
System.out.println("Die Bezugsart ist : " + tag020codeC);
}
// Zugriff und Umwandlung der Datenquelle wenn von einer Datei gelesen wird
private static String convertToFileURL(String filename)
{
// path = file.toURL().toString()
String path = new File(filename).getAbsolutePath();
if (File.separatorChar != '/')
{
path = path.replace(File.separatorChar, '/');
}
if (!path.startsWith("/"))
{
path = "/" + path;
}
return "file:" + path;
}
/**
* @param args
*/
// Start der Verarbeitung des Dokumentes (Aufruf des Parsers)
public static void main(String[] args) throws ParserConfigurationException,
SAXException, IOException
{
String filename = "src/xml/buchElementMarc21.xml";
// Start des Parsens Prozesses durch erzeugen einer Factory
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
// Konfiguration der Factory
saxFactory.setNamespaceAware(true);
// Durch die Factory eine neue Instnaz der Klasse JAXParser erzeugen
SAXParser saxParser = saxFactory.newSAXParser();
// XMLReader-Schittstelle durch Methode getXMLReader()
XMLReader xmlReader = saxParser.getXMLReader();
// Registriert die Schnittstelle ContentHandler beim XMLReader und gibt
// die aktuelle Anwendung SaxEntwurf als Klasse an, die über Parser-
// Ereignisse zu informieren ist. Es wird mit new eine Instnaz erzeugt
// und damit ein hadnlunfsfähiges Objekt erzeugt, damit die deklarierten
// Methoden zum Einsatz kommen kann.
// xmlReader.setContentHandler(new SaxEntwurf());
xmlReader.setContentHandler(new XMLextractorMarc21());
// Registrierung der Fehlerbehandlungen
// xmlReader.setErrorHandler(new FehlerHandler(System.err));
// Der XMLReader erhält den Auftrag das XML-Dokument zu parsen
xmlReader.parse(convertToFileURL(filename));
}
}
Um dann die komplexe XML-Datei mit Namespace usw. zu verwenden, habe ich ein Element heraus gezogen.
Warum ich die Klasse Buch nicht verwendet habe, ist der Grund, weil , wenn ich ein Objekt in der Main Methode sagen wir (Buch buchObjekt = new Buch()) erstelle, dann in den Methoden des Parsers nicht darauf zugreifen kann.
Wenn der Parser einmal gestartet ist, dann springt dieser ja automatisch zu den Parser-Methoden.
Der Parser ruft dann immer wie folgt auf:
startDocument() Wenn er den Anfang der XML findet
startElement(.......) Wenn er ein Start-Tag findet
characters(.....) Wenn er eineZeichendaten findet, die keine Kindelemente sind
endElement() Wenn er ein End-Tag findet
.....
...
..
endDokument() Wenn das Ende der XML-Datei gefunden wurde.
Ich würde gerne die Instanzvariablen in der Buchklasse drauf zugreifen, da der Parser bis zum ende nur auf die Parser-Methoden zugreift, kann ich auf das buchObjekt nicht drauf zugreifen.
Wenn ich aber ein Buchobjekt in der Methode startElement(...) erstelle und eines in Characters(...) dan sind das zwei unterschiedliche Objekte, also das ist auch keine Lösung.
So ich habe es mittlerweile umgebaut und verwende die Klasse Buch.
XMLExtractorMarc21.java
Java:
package de.michael;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import de.michael.Buch;
/**
* @author Michael
*
*/
public class XMLextractorMarc21 extends DefaultHandler
{
// Buchobjekt erzeugen
Buch buchObjekt = new Buch();
/*
* Default Handler Methoden
*/
// wird vom Parser ausgeführt, wenn er den Anfang des XML Dokumentes findet
public void startDocument() throws SAXException
{
System.out.println("Beginn der XML-Auswertung");
}
// wird vom Parser jedesmal aufgerufen, wenn ein Start-Tag gefunden wird
public void startElement(String namespaceURI, String localName,
String qName, Attributes attr) throws SAXException
{
// Der Attributinhalt ist der orange Dargestellte Wert (020, a, b, ...)
if (attr.getValue(0).length() > 1)
{
buchObjekt.setBufferNummer(attr.getValue(0));
System.out.println("Die bufferAttributnummer ist: " + buchObjekt.getBufferNummer());
} else
{
buchObjekt.setBufferCode(attr.getValue(0));
System.out.println("Der bufferAttributCode ist: " + buchObjekt.getBufferCode());
}
}
// liefert Zeichendaten von Elementen, die keine Kindelemente enthalten
public void characters(char[] ch, int start, int length)
throws SAXException
{
if (length > 0)
{
// Benötigte TagCodes
// 020 ab9, 245 abc, 250 a , 260 abc, 300 abc, 490 a, 856 mqu3
String zeichenkette = new String(ch, start, length);
System.out.println("Die Zeichenkette ist: " + zeichenkette);
String buchCode = buchObjekt.getBufferNummer() + buchObjekt.getBufferCode();
if ("020a".equals(buchCode))
{
buchObjekt.setIsbn13(zeichenkette);
System.out.println("Buchcode tag020codeA enthält: "
+ buchObjekt.getIsbn13());
} else if ("020c".equals(buchCode))
{
buchObjekt.setBezug(zeichenkette);
System.out.println("Buchcode tag020codeC enthält: "
+ buchObjekt.getBezug());
} else if ("0209".equals(buchCode))
{
buchObjekt.setIsbn15(zeichenkette);
System.out.println("Buchcode tag020code9 enthält: "
+ buchObjekt.getIsbn15());
}
}
}
// wird vom Parser aufgerufen, wenn das Ende des Dokumentes gemeldet wurde
public void endDocument() throws SAXException
{
System.out.println("Ende der XML-Auswertung");
System.out.println("Die ISBN13 Nummer ist: " + buchObjekt.getIsbn13());
System.out.println("Die ISBN15 Nummer ist: " + buchObjekt.getIsbn15());
System.out.println("Die Bezugsart ist : " + buchObjekt.getBezug());
}
// Zugriff und Umwandlung der Datenquelle wenn von einer Datei gelesen wird
private static String convertToFileURL(String filename)
{
// path = file.toURL().toString()
String path = new File(filename).getAbsolutePath();
if (File.separatorChar != '/')
{
path = path.replace(File.separatorChar, '/');
}
if (!path.startsWith("/"))
{
path = "/" + path;
}
return "file:" + path;
}
/**
* @param args
*/
// Start der Verarbeitung des Dokumentes (Aufruf des Parsers)
public static void main(String[] args) throws ParserConfigurationException,
SAXException, IOException
{
String filename = "src/xml/buchElementMarc21.xml";
// Start des Parsens Prozesses durch erzeugen einer Factory
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
// Konfiguration der Factory
saxFactory.setNamespaceAware(true);
// Durch die Factory eine neue Instnaz der Klasse JAXParser erzeugen
SAXParser saxParser = saxFactory.newSAXParser();
// XMLReader-Schittstelle durch Methode getXMLReader()
XMLReader xmlReader = saxParser.getXMLReader();
// Registriert die Schnittstelle ContentHandler beim XMLReader und gibt
// die aktuelle Anwendung SaxEntwurf als Klasse an, die über Parser-
// Ereignisse zu informieren ist. Es wird mit new eine Instnaz erzeugt
// und damit ein hadnlunfsfähiges Objekt erzeugt, damit die deklarierten
// Methoden zum Einsatz kommen kann.
// xmlReader.setContentHandler(new SaxEntwurf());
xmlReader.setContentHandler(new XMLextractorMarc21());
// Registrierung der Fehlerbehandlungen
// xmlReader.setErrorHandler(new FehlerHandler(System.err));
// Der XMLReader erhält den Auftrag das XML-Dokument zu parsen
xmlReader.parse(convertToFileURL(filename));
}
}
Die Ausgabe ist wie folgt:
Beginn der XML-Auswertung
Die bufferAttributnummer ist: Bibliographic
Die Zeichenkette ist:
Die bufferAttributnummer ist: 020
Die Zeichenkette ist:
Der bufferAttributCode ist: a
Die Zeichenkette ist: 9783834805690
Buchcode tag020codeA enthält: 9783834805690
Die Zeichenkette ist:
Buchcode tag020codeA enthält:
Der bufferAttributCode ist: c
Die Zeichenkette ist: kart. : EUR 19.90
Buchcode tag020codeC enthält: kart. : EUR 19.90
Die Zeichenkette ist:
Buchcode tag020codeC enthält:
Der bufferAttributCode ist: 9
Die Zeichenkette ist: 978-3-8348-0569-0
Buchcode tag020code9 enthält: 978-3-8348-0569-0
Die Zeichenkette ist:
Auch leider werden hier die Ausgabe auf die Konsole nicht mit den Variablen ausgegeben.
Da ich aber in die Instanzvariablen schreibe und auch direkt von dort aus als Kontrolle ausgeben lasse, sollten die Werte schon richtig gespeichert worden sein?
Warum werden die Werte zum Schluss nicht ausgegeben ??
Buchcode tag020code9 enthält: 978-3-8348-0569-0
ok da passts noch
paar zeilen darunter
Buchcode tag020code9 enthält:
als tipp: ich würde in der characters Methode nix ins objekt schreiben sondern nur den aktuellen string in eine zwischenvariable halten und dann beim endTag in die entsprechende variable...
ja Du hast recht, die Variable buchCode wird immer wieder überschrieben, aber je nach Inhalt, die der buchCode trägt wie "020a" wird der Inhalt der Zeichenkette in die entsprechende Instanzvariable geschrieben.
Wenn der buchCode "020a" enthält wird er durch die if Anweisungen in setIsbn13 geschrieben.
Wenn der buchCode "020c" enthält dann setBezug und bei "0209" in setIsbn15.
Da der buchCode immer andere Werte hat, überschreibt er doch dann die Inhalte des "buchObjekt" doch nicht?
Um auch noch den buchCode zu prüfen habe ich den Code so geändert, das noch der aktuelle buchCode mit ausgegeben wird.
Also wenn der Parser anfängt und den start der XML findet, dann führt er folgende Methoden aus:
Ich habe jetzt mal die XML ergänzt um mal mehr zu sehen.
marc21... nicht gerade das was man als schönes xml bezeichnet.. hab mir das einwenig angesehen, aber gut das ist halt eine alte standard schnittstelle die ins xml transferiert wurde
deine überprüfung im startElement ist zu ungenau!!!! wenn der wert länger als 1 ist dann muss es tag von datefield sein und sonst ist es code vom subfield? ist nicht dein ernst oder?
ich würd mich auch nicht drauf verlassen, das tag immer als erstes kommt, die reihenfolge von attributen ist nicht festgelegt (oder? du hast die letzen 20 tage xml bücher gelesen)
Java:
public void startElement(String namespaceURI, String localName,
String qName, Attributes attr) throws SAXException
{
// Der Attributinhalt ist der orange Dargestellte Wert (020, a, b, ...)
if (localName.equals("datafield"))
{
buchObjekt.setBufferNummer(getValueFromAttribute(attr, "tag"));
System.out.println("Die bufferAttributnummer ist: " + buchObjekt.getBufferNummer());
} else if (localName.equals("subfield"))
{
buchObjekt.setBufferCode(getValueFromAttribute(attr, "code"));
System.out.println("Der bufferAttributCode ist: " + buchObjekt.getBufferCode());
}
}
private String getValueFromAttribute(Attributes attr, String attributeName){
for(int i = 0; i < attr.getLength(); i++){
if(attr.getLocalName(i).equals(attributeName)){
return attr.getValue(i);
}
}
return null;
}
und du ich denke du solltest wenn das subfield tag geschlossen wurden, den code zurück setzen, dann kann es dir nicht passieren, dass irgendetwas anderes das zwischen </slim:subfield> und
</slim:datafield> steht in deine variablen geschrieben wird
Die bufferAttributnummer ist: 020
Die Zeichenkette ist:
Der bufferAttributCode ist: a
Die Zeichenkette ist: 9783834805690
Buchcode tag020codeA enthält: 9783834805690
Der bufferAttributCode ist: null
Die Zeichenkette ist:
Der bufferAttributCode ist: c
Die Zeichenkette ist: kart. : EUR 19.90
Buchcode tag020codeC enthält: kart. : EUR 19.90
Der bufferAttributCode ist: null
Die Zeichenkette ist:
Der bufferAttributCode ist: 9
Die Zeichenkette ist: 978-3-8348-0569-0
Buchcode tag020code9 enthält: 978-3-8348-0569-0
Der bufferAttributCode ist: null
Die Zeichenkette ist:
Die bufferAttributnummer ist: null
Die Zeichenkette ist:
Ende der XML-Auswertung
Die ISBN13 Nummer ist: 9783834805690
Die ISBN15 Nummer ist: 978-3-8348-0569-0
Die Bezugsart ist : kart. : EUR 19.90
ich Habe die Quelle mal verändert um mal zu sehen, was sich bei der Ausgabe sonst noch so tut.
Ist halt mal was probieren und sehen gewesen und war für mich sehr aufschlussreich.
Wie das nicht schöne XML aussieht liegt leider nicht bei mir, das ist halt ein Auszug aus einem Datensatz der Deutschen National Bibliothek, so wie er zurückgegeben wird.
Die Prüfungen im start Element sind für einen langjährigen Programmierer zu ungenau. Ok, klar, das war halt das erste was mir eingefallen war, denn die Codes tragen immer nur eine Ziffer und die Tags immer 3 Ziffern. Demnach ergab sich das so. Da ich noch nicht lange Java Programmiere, wollte ich erstmal etwas funktionsfähiges sehen. Ausbaufähig und Verbesserungen sind immer möglich.
Die letzten 20 Tage habe ich XML Grundlagen gemacht und versucht zu verstehen, wie DTDs, Schema usw funktionieren. Habe aber dann festgestellt, das dies eine ziemlich komplexe Angelegenheit ist.
Da ich mit DOM schon erfolgreich war, habe ich mich dann entschlossen mit SAX mal zu probieren. Deshalb ist der code auch so entstanden, das er gerade mal so läuft.
Ich habe in den letzten Wochen ziemlich viel probieren müssen, bis ich verstanden habe, was ich überhaupt benötige um mein Problem zu lösen.
Ich möchte mich noch mal bei allen recht herzlich bedanken.
Das Problem zu lösen habe ich jetzt verstanden und mein XML-Testelement erfolgreich in Java Variablen geschrieben.
@ARadauer
Du hattest Recht, das nicht nur die Start-Tags zu prüfen seien, sondern auch die End-Tags und dort dann die Variablen NULL zu setzen. Ausserdem war die Abfrage zwischen Nummer und Code mit "> 1" zwar lauffähig, aber nicht gerade guter Programmierstil. Durch Dein Codebeispiel habe ich verstanden wie Wichtig es ist durch andere Parameter zu prüfen.