xml validierung gegen xsd mit jdom: Fehlermeldung Cannot find the declaration of element ...

ceugster

Mitglied
Hallo,

vielleicht kann mir jemand helfen: Ich habe folgendes Problem:

Ich habe eine ZIP-Datei, welche zwei Dateien enthält: eine metadata.xml und eine metadata.xsd.

Aufgabe: Ich muss metadata.xml gegen metadata.xsd validieren. Ich verwende dafür JDOM (Version 2.0.0).

Wenn ich versuche, metadata.xml "direkt in der ZIP-Datei" zu validieren, erhalte ich eine Fehlermeldung, die lautet: cvc-elt.1: Cannot find the declaration of element <element-name>.

Entpacke ich die ZIP-Datei und validiere ich so, dann läuft die Validierung korrekt ab, d.h. der SAXBuilder erkennt die metadata.xml Date als valid. Nachfolgend der Code:

Inline-Validierung:
Java:
	public static void main(String[] args)
	{
		try
		{
			String zip = "U:/Incubator Projekte/Test/test.zip";

			File file = new File(zip);
			ZipFile zipFile = new ZipFile(file);
			ZipEntry xmlEntry = zipFile.getEntry("header/metadata.xml");
			InputStream in = zipFile.getInputStream(xmlEntry);
			File xml = File.createTempFile("tmp_", ".xml");
			OutputStream out = new FileOutputStream(xml);
			while (in.available() > 0)
			{
				byte[] b = new byte[in.available()];
				int n = in.read(b);
				out.write(b, 0, n);
			}
			out.close();
			in.close();

			ZipEntry xsdEntry = zipFile.getEntry("header/metadata.xsd");
			in = zipFile.getInputStream(xsdEntry);
			File xsdFile = File.createTempFile("tmp_", ".xsd");
			out = new FileOutputStream(xsdFile);
			while (in.available() > 0)
			{
				byte[] b = new byte[in.available()];
				int n = in.read(b);
				out.write(b, 0, n);
			}
			out.close();
			in.close();

			XMLReaderXSDFactory xsdFactory = new XMLReaderXSDFactory(xsdFile);
			SAXBuilder builder = new SAXBuilder(xsdFactory);
			builder.setFeature("http://apache.org/xml/features/validation/schema", true);
			Document document = builder.build(xml);
			System.out.println(document);
		} 
		catch (JDOMException e)
		{
			e.printStackTrace();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}

Der Stacktrace lautet:

Java:
org.jdom2.input.JDOMParseException: Error on line 2 of document file:///C:/Dokumente%20und%20Einstellungen/ceugster/Lokale%20Einstellungen/Temp/tmp_3203038574951862036.xml: cvc-elt.1: Cannot find the declaration of element 'siardArchive'.
	at org.jdom2.input.sax.SAXBuilderEngine.build(SAXBuilderEngine.java:228)
	at org.jdom2.input.sax.SAXBuilderEngine.build(SAXBuilderEngine.java:329)
	at org.jdom2.input.SAXBuilder.build(SAXBuilder.java:1256)
	at test.jdom.Main.main(Main.java:55)
Caused by: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'siardArchive'.
	at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
	at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
	at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
	at org.jdom2.input.sax.SAXBuilderEngine.build(SAXBuilderEngine.java:217)
	... 3 more

Dieselben metadata.xml und metadata.xsd entpackt:
Java:
	public static void main(String[] args)
	{
		try
		{
			String xml = "U:/Incubator Projekte/SIARD.val/Test Data/gebaeudeversicherung/header/metadata.xml";
			String xsd = "U:/Incubator Projekte/SIARD.val/Test Data/gebaeudeversicherung/header/metadata.xsd";

			XMLReaderXSDFactory xsdFactory = new XMLReaderXSDFactory(xsd);
			SAXBuilder builder = new SAXBuilder(xsdFactory);
			builder.setFeature("http://apache.org/xml/features/validation/schema", true);
			Document document = builder.build(xml);
			System.out.println(document);
		} 
		catch (JDOMException e)
		{
			e.printStackTrace();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}

funktioniert.

Kann mir jemand einen Hinweis geben? Vielen Dank!
 
deine zwei Varianten sind besser als nur eine mit Fehler und gar keine Ideen,
aber das könntest du doch noch leicht fortführen und viel mehr Information erlangen?

1. entpacke nicht nach
> C:/Dokumente%20und%20Einstellungen/ceugster/Lokale%20Einstellungen/Temp/
oder ähnlich komisches,
sondern nach c:/Temp oder etwas in Richtung von
> U:/Incubator Projekte/SIARD.val/Test Data
wenn das bei dir schon funktioniert,

nur die Änderung des Festplatten-Ortes bringt aber noch nichts, oder?

2. jetzt wird es richtig interessant:
die entpackten Dateien löscht ja niemand oder?
funktioniert im nächsten Durchlauf das zweite kürzere Programm dann mit diesen beiden vor paar Minuten entpackten Dateien?
wenn ja, dann ist das eine spannende Richtung, zu der ich aber erstmal nichts sage (wer weiß ob mir je dazu was einfällt)

meine Annahme ist, dass auch das dann nicht funktioniert, korrekt?
damit wäre das Zip vorerst aus dem Spiel, du hast nur noch ein Programm, welches mit den einen Dateien geht, mit den anderen nicht

3. nun die Dateien vergleichen, wer hätte das gedacht,
grob anschauen zeigt vielleicht sofort Fehler, fehlende oder komische Zeilenumbrüche, Leerzeichen usw.,
evtl. mit einem Java-Programm exakt Länge und bytes vergleichen, Checksumme (alle bytes addieren) geht recht schnell

weitere Vergleiche: geht alte xml-Datei zusammen mit (vor einige Minuten) entpackter xsd-Datei?
oder andersum kombiniert?

wenn beide Dateien von
> U:/Incubator Projekte/SIARD.val/Test Data
in das Verzeichnis des Entpackens kopiert werden, die dortigen Dateien überschreiben, geht es dann dort?
reicht es nur die eine oder andere dorthin zu kopieren?
 
Hallo SlaterB,

vielen Dank für Deine Antwort. Bevor ich darauf zurückkomme, habe ich noch eine Verständnisfrage, die ich nicht lösen konnte: Bezieht sich die Fehlermeldung auf metadata.xml oder metadata.xsd?

Nun zu Deinen Anregungen:

Ich habe nun jeweils von den zwei metadata.xml und metadata.xsd die checksum gezogen. Die Dateien sind nicht identisch, haben aber die identische Checksum. Folgendes zeigt sich:

U:\Incubator Projekte\SIARD.val\Test Data\tmp_7714983833481510786.xml: b1ad8d3b84930207f03fc3717d0ef4c0
U:\Incubator Projekte\SIARD.val\Test Data\tmp_8704367740297626862.xsd: 9fb7da6cabdc0ebfddaaac7f22d5483c
U:/Incubator Projekte/SIARD.val/Test Data\gebaeudeversicherung/header\metadata.xml: b1ad8d3b84930207f03fc3717d0ef4c0
U:/Incubator Projekte/SIARD.val/Test Data\gebaeudeversicherung/header\metadata.xsd: 9fb7da6cabdc0ebfddaaac7f22d5483c

Und trotzdem, das Problem bleibt. Die Exception wird in SAXBuilderEngine.build(InputSource) geworfen. Könnte das Problem "irgendwie" am InputStream liegen, der in der langen Methode eingelesen wird? Scheint mir auch unwahrscheinlich, aber ich weiss sonst nichts.
 
> Bezieht sich die Fehlermeldung auf metadata.xml oder metadata.xsd?

Validieren von XML zu XSD ist mir im Grunde immer ein Rätsel wenn ich das irgendwo sehe,
sollte da irgendwo irgendwas nicht funktionieren ist das in meinen Augen immer der richtige Normalzustand 😉 ,

hättest du nicht ein funktionierendes Beispiel würde ich überhaupt nicht daran denken dass das irgendwie zu lösen ist,
also ich kann dazu nichts sagen, antworte nur auf die interessante strukturelle Anomalie funktionierendes vs. nicht funktionierendes Programm

hast du denn schon das kürzere Programm wie gesagt mit den anderen Dateien laufen lassen?

an deiner Ausgabe der 4 Checksummen fallen mir die verschiedenen Slashes auf: / und \,
wie kommt es dazu?
kann es sein dass
> File xml = File.createTempFile("tmp_", ".xml");
\-Files erzeugt statt sonst / ?
sowas könnte in meinen Augen eine denkbare Ursache sein

-----

ich sehe gerade dass du in deinem funktionierenden Beispiel Strings übergibst, File-Objekte überhaupt nicht beteiligt sind,
das sollte besser kein entscheidender Punkt sein, aber ist doch auch wieder etwas was man testen kann,

im Zip-Programm aus [c]File xml[/c] und dem anderen File die kompletten Pfade extrahieren, ausgeben,
evtl. umformen zu / statt \ und was immer komisch aussehen mag und dann das übergeben,
wenn es dann klappt kann man ja zurückgehen und testen, welcher Schritt weggelassen werden kann

dass du nicht das komische User-Temp-Verzeichnis nehmen musst und auch nicht komplett neugenerierte Dateinamen,
sondern auch zumindest testweise "c:/temp/test.xml" vorgeben kannst habe ich ja mehr oder weniger schon gesagt
 
> Validieren von XML zu XSD ist mir im Grunde immer ein Rätsel wenn ich das irgendwo sehe,
> sollte da irgendwo irgendwas nicht funktionieren ist das in meinen Augen immer der richtige > Normalzustand

Ich hoffe, Du hast nicht recht ???:L

Ja, ich habe beide Programme mit beiden Dateien versucht, immer das gleiche Ergebnis. Der Unterschied scheint ja nicht in den Dateien zu liegen, sondern möglicherweise daran, dass ich einmal einen InputStream verwende, den ich aus einem ZipFile "extrahiere", im anderen Fall ein File übergebe. Obwohl ich denke, dass das ja eigentlich kein Unterschied sein sollte.

Die Slashes/Backslashes haben nur mit der System.out.println() zu tun; ich printe jeweils den String oder File.getAbsolutePath(), damit ich im Ausdruck erkennen kann, was was ist.

Mir scheint der wesentliche Unterschied wie gesagt in der Übergabe eines InputStreams im einen, eines File im anderen Fall zu sein. Warum das aber unterschiedlich gehandelt wird, ist mir schleierhaft.
 
> Der Unterschied scheint ja nicht in den Dateien zu liegen, sondern möglicherweise daran, dass ich einmal einen InputStream verwende, den ich aus einem ZipFile "extrahiere", im anderen Fall ein File übergebe.

du speicherst die Zip-Dateien doch auf der Festplatte, für den SAXBuilder sind es in beiden Fällen Dateien?
ich kann mich nur billig wiederholen, aber die einzigen Unterschiede sind in meinen Augen bisher
- die Dateien an sich
- die Orte
- im Programm String vs File, evtl. interne Bezeichnungen im File, / statt \ usw.
 
du speicherst die Zip-Dateien doch auf der Festplatte, für den SAXBuilder sind es in beiden Fällen Dateien?
ich kann mich nur billig wiederholen, aber die einzigen Unterschiede sind in meinen Augen bisher
- die Dateien an sich
- die Orte
- im Programm String vs File, evtl. interne Bezeichnungen im File, / statt \ usw.

Das stimmt nicht ganz: Im einen Fall habe ich eine Zip-Datei (ja, auf der Festplatte gespeichert), aus der ich ich metadata.xml als InputStream extrahiere und dem SAXBuilder übergebe.

Im anderen Fall übergebe ich ein File, das auf eine bereits vorher (manuell) extrahierte metadata.xml verweist.
 
Zuletzt bearbeitet von einem Moderator:
ähm, wenn du "5" sagst und ich "nein, nicht 5 sondern 4" antworte,
dann kannst du doch nicht "das stimmt nicht ganz, nicht 4 sondern 5" antworten?!

genau diesen Punkt, dass du KEINEN Inputstream an den SAXBuilder übergibst, habe ich doch angesprochen,
da kannst du doch nicht ohne Begründungen direkt erneut wiedersprechen, wie bringt das die Diskussion voran?

zum Glück gibts ja meine Seite, die eine Endlosschleife derselben Antworten durchbricht 😉 und nochmal Code-Details nachzieht:
an SAXBuilder übergibst du, jedenfalls im geposteten Code, die File-Objekte xml und xsdFile, das sind Links auf die Festplatte,
enthalten nur intern einen String, erstaunlich simple leere Klassen, enthalten keine byte-Daten oder so,

die Daten beider Dateien schreibst du vorher mit FileOutputStream auf die Festplatte, inklusive close(),
zu dem Zeitpunkt sind es fertige Dateien so gut es nur eben geht,
ob dann 5 Zeilen oder 5 Min. später wieder eingelesen wird sollte keinen Unterschied machen

falls du nicht den technischen Aspekt 'Übergabe eines Streams an SaxBuilder' meinst sondern den Umstand, dass die Dateien
ms zuvor aus einem Zip auf die Festplatte entpackt wurden,
so ist das zum einen wie gerade erst gesagt egal ob vor ganz ganz ganz kurzem oder gestern,
zum anderen ist die Quelle an sich völlig egal, ob Zip, Eingabe vom Benutzer in ein Textfeld oder vom Zufallsgenerator automatisch erstellt,

deshalb vermute ich wie gesagt die von mir aufgelisteten Punkte,
anderes ist natürlich nie auszuschließen, aber soweit meine Meinung dazu


edit:
> Mir scheint der wesentliche Unterschied wie gesagt in der Übergabe eines InputStreams im einen, eines File im anderen Fall zu sein.

ok, das klingt auch wiederum so, als würdest du mit 'InputStream' eher das nicht-Zip-Programm meinen,
denn eindeutig nur im Zip-Programm ist ja von Files die Rede,
also in jedem Fall kein Stream direkt an SaxBuilder

dass der Parameter File vs. String ein Unterschied ist, habe ich ja schon gesagt,
ruhig untersuchen falls möglich, mit Tests vielleicht eher zu sagen,

kannst du das Zip hier an ein Posting anhängen? vielleicht kann ich es testen
 
Zuletzt bearbeitet von einem Moderator:
Hallo SlaterB,

tut mir leid, dann habe ich Dich falsch verstanden, nichts für ungut. Ich habe jetzt einen anderen Ansatz gewählt, da im Netz wirklich überhaupt nichts zu finden ist (bin wohl der einzige, der damit kämpft...)

Ein Artikel (The Java XML Validation API) macht den Vorschlag, direkt mit den in JAVA (ab 1.5) enthaltenen xml-Packages zu arbeiten. Ich habe es versucht und genau das, was ich wollte, klappt.

Dir also vielen Dank für Deine Unterstützung und einen schönen Abend dann!
 

Zurück
Oben