Problem mit XML-Schema Validierung mit Java

  • Themenstarter Themenstarter Guest
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hallo zusammen,

ich hab hier folgenden Java-Code:

Code:
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.dom4j.util.XMLErrorHandler;
import org.xml.sax.SAXException;

public class TestClass {
	private static String directory;
	private static File dir;

	public TestClass() {
	}
	public static void main(String[] args) {

		if (args.length < 1) {
			System.out.println("directory parameters have to be entered!");
		} else {
			directory = args[0];

			System.out.println("Input Directory: " + directory);

			dir = new File(directory);
			File[] files = dir.listFiles();

			Vector prev_files = new Vector();

			if (files != null) {
				for (int i = 0; i < files.length; i++) {
					if (files[i].toString().endsWith(".xml")) {
						prev_files.add(files[i]);
					}
				}
			}
			Iterator prev_iterator = prev_files.iterator();

			for (;prev_iterator.hasNext();) {
				try {
					createPrevisions(prev_iterator);
				} catch (SAXException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (DocumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	private static void createPrevisions(Iterator prev_iterator)
			throws SAXException, DocumentException, IOException {
			File prev_file = (File) prev_iterator.next();

			// each previsions.xml file found in the directory has to be checked against previsions.xsd
			SAXReader reader = new SAXReader();
			reader.setValidation(true);

			// specification of schema to use
			reader.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", "previsions.xsd");

			// add error handler which turns any errors into XML
			XMLErrorHandler errorHandler = new XMLErrorHandler();
			reader.setErrorHandler(errorHandler);

			// parse the document
			reader.read(prev_file);

			// output the errors XML
			XMLWriter writer = new XMLWriter(OutputFormat.createPrettyPrint());

			if (errorHandler.getErrors() != null) {
				writer.write(errorHandler.getErrors());
				// System.exit(0);
			}
	}
}


Hier mal der Inhalt der XML-Datei:


Code:
<PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="purchaseOrder.xsd">
   <Reference>ADAMS-2001112712104128PST</Reference>
   <Actions>
      <Action>
         <User>SCOTT</User>
   
      </Action>
   </Actions>
   <Reject/>
   <Requestor>Julie P. Adams</Requestor>
   <User>ADAMS</User>
   <CostCenter>R20</CostCenter>
   <ShippingInstructions>
      <name>Julie P. Adams</name>
      <address>300 Oracle Parkway
Redwood Shores
CA
94065
USA</address>
      <telephone>650 506 7300</telephone>
   </ShippingInstructions>
   <SpecialInstructions>Hand Carry</SpecialInstructions>
   <LineItems>
      <LineItem ItemNumber="1">
         <Description>The Life of Brian</Description>
         <Part Id="715515010320" UnitPrice="39.95" Quantity="2"/>
      </LineItem>
      <LineItem ItemNumber="2">
         <Description>Hamlet</Description>
         <Part Id="037429128428" UnitPrice="29.95" Quantity="2"/>
      </LineItem>
      <LineItem ItemNumber="3">
         <Description>Salesman</Description>
         <Part Id="037429158920" UnitPrice="39.95" Quantity="4"/>
      </LineItem>
      <LineItem ItemNumber="4">
         <Description>Nights of Cabiria</Description>
         <Part Id="037429138427" UnitPrice="39.95" Quantity="1"/>
      </LineItem>
      <LineItem ItemNumber="5">
         <Description>Unbearable Lightness Of Being</Description>
         <Part Id="037429140222" UnitPrice="29.95" Quantity="2"/>
      </LineItem>
   </LineItems>
</PurchaseOrder>

Und hier noch der Inhalt der XSD:
Code:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xdb="http://xmlns.oracle.com/xdb" xmlns:a="test1" xmlns:b="test2" version="1.0" xdb:storeVarrayAsTable="true">
	<xs:element name="PurchaseOrder" type="PurchaseOrderType" xdb:defaultTable="PURCHASEORDER"/>
	<xs:complexType name="PurchaseOrderType">
		<xs:sequence>
			<xs:element ref="Reference"/>
			<xs:element name="Actions" type="ActionsType"/>
			<xs:element name="Reject" type="RejectType" minOccurs="0"/>
			<xs:element ref="Requestor"/>
			<xs:element ref="User"/>
			<xs:element ref="CostCenter"/>
			<xs:element name="ShippingInstructions" type="ShippingInstructionsType"/>
			<xs:element ref="SpecialInstructions"/>
			<xs:element name="LineItems" type="LineItemsType"/>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="LineItemsType">
		<xs:sequence>
			<xs:element name="LineItem" type="LineItemType" maxOccurs="unbounded"/>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="LineItemType">
		<xs:sequence>
			<xs:element ref="Description"/>
			<xs:element ref="Part"/>
		</xs:sequence>
		<xs:attribute name="ItemNumber" type="xs:integer"/>
	</xs:complexType>
	<xs:element name="Reference" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="18"/>
				<xs:maxLength value="30"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="Part" xdb:defaultTable="">
		<xs:complexType>
			<xs:attribute name="Id">
				<xs:simpleType>
					<xs:restriction base="xs:string">
						<xs:minLength value="10"/>
						<xs:maxLength value="14"/>
					</xs:restriction>
				</xs:simpleType>
			</xs:attribute>
			<xs:attribute name="Quantity" type="money"/>
			<xs:attribute name="UnitPrice" type="quantity"/>
		</xs:complexType>
	</xs:element>
	<xs:complexType name="ActionsType">
		<xs:sequence>
			<xs:element name="Action" maxOccurs="4">
				<xs:complexType>
					<xs:sequence>
						<xs:element ref="User"/>
						<xs:element ref="Date" minOccurs="0"/>
					</xs:sequence>
				</xs:complexType>
			</xs:element>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="RejectType">
		<xs:all>
			<xs:element ref="User" minOccurs="0"/>
			<xs:element ref="Date" minOccurs="0"/>
			<xs:element ref="Comments" minOccurs="0"/>
		</xs:all>
	</xs:complexType>
	<xs:complexType name="ShippingInstructionsType">
		<xs:sequence>
			<xs:element ref="name"/>
			<xs:element ref="address"/>
			<xs:element ref="telephone"/>
		</xs:sequence>
	</xs:complexType>
	<xs:simpleType name="money">
		<xs:restriction base="xs:decimal">
			<xs:fractionDigits value="2"/>
			<xs:totalDigits value="12"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="quantity">
		<xs:restriction base="xs:decimal">
			<xs:fractionDigits value="4"/>
			<xs:totalDigits value="8"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="User" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="1"/>
				<xs:maxLength value="10"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="Requestor" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="0"/>
				<xs:maxLength value="128"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="CostCenter" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="1"/>
				<xs:maxLength value="4"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="Vendor" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="0"/>
				<xs:maxLength value="20"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="PONumber" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:integer"/>
		</xs:simpleType>
	</xs:element>
	<xs:element name="SpecialInstructions" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="0"/>
				<xs:maxLength value="2048"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="name" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="1"/>
				<xs:maxLength value="20"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="address" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="1"/>
				<xs:maxLength value="256"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="telephone" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="1"/>
				<xs:maxLength value="24"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="Date" type="xs:date" xdb:defaultTable=""/>
	<xs:element name="Comments" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="1"/>
				<xs:maxLength value="2048"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="Description" xdb:defaultTable="">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:minLength value="1"/>
				<xs:maxLength value="256"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
</xs:schema>

Wenn ich das ganze dann allerdings ablaufen lasse, bekomm ich folgenden Output auf der Konsole:
Code:
<errors>
  <error column="12" line="2" systemID="file:///C:/Users/Username/Desktop/test/prevision_test_delete_false.xml">Document is invalid: no grammar found.</error>
  <error column="12" line="2" systemID="file:///C:/Users/Username/Desktop/test/prevision_test_delete_false.xml">Document root element "previsions", must match DOCTYPE root "null".</error>
</errors>

Wenn ich die gleiche XML-Datei allerdings mit XML-Spy gegen die XSD validiere, bekomm ich keinen Fehler.
Da scheint also was mit meinem Java-Code nicht zu stimmen.

Ich nutze halt DOM4J fürs parsen etc.! Da DOM4J allerdings keine Schema-Validierung kann, habe ich es versucht auf dem von DOM4J selbst
vorgeschlagenen Weg zu machen:

Validation

Currently dom4j does not come with a validation engine. You are forced to use a external validator. In the past we recommended Xerces, but now you are able to use Sun Multi-Schema XML Validator. Xerces is able to validate against DTDs and XML Schema, but not against TREX or Relax. The Suns Multi Schema Validator supports all mentioned kinds of validation.

Validation consumes valuable resources. Use it wisely.
Using Apaches Xerces 1.4.x and dom4j for validation

It is easy to use Xerces 1.4.x for validation. Download Xerces from Apaches XML web sites. Experience shows that the newest version is not always the best. View Xerces mailing lists in order to find out issues with specific versions. Xerces provides Schema support strarting from 1.4.0.

*

Turn on validation mode - which is false for default - using a SAXReader instance
*

Set the following Xerces property http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation using the schema URI.
*

Create a SAX XMLErrorHandler and install it to your SAXReader instance.
*

Parse and validate the Document.
*

Output Validation/Parsing errors.

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.i😵utputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.dom4j.util.XMLErrorHandler;


import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException

public class SimpleValidationDemo {

public static void main(String[] args) {
SAXReader reader = new SAXReader();

reader.setValidation(true);

// specify the schema to use
reader.setProperty(
"http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
"prices.xsd"
);

// add error handler which turns any errors into XML
XMLErrorHandler errorHandler = new XMLErrorHandler();
reader.setErrorHandler( errorHandler );

// parse the document
Document document = reader.read(args[0]);

// output the errors XML
XMLWriter writer = new XMLWriter( OutputFormat.createPrettyPrint() );
writer.write( errorHandler.getErrors() );
}


Both, Xerecs and Crimson, are JaXPable parsers. Be careful while using Crimson and Xerces in same class path. Xerces will work correctly only when it is specified in class path before Crimson. At this time I recommend that you should either Xereces or Crimson.

Was ich nicht ganz verstehe ist das "Download Xerces from Apaches XML web sites. Experience shows that the newest version is not always the best. View Xerces mailing lists in order to find out issues with specific versions. Xerces provides Schema support strarting from 1.4.0.".

Was muss ich jetzt downloaden, wo in Eclipse hinpacken und muss ich dann nicht auch was importieren (fehlt da nicht ein Import in dem DOM4J Beispiel?

Ich hoffe ihr könnt mir weiterhelfen.

Viele Grüße,
Masipulami[/code]
 
Hab gerade noch nen Fehler im Java-Code entdeckt.
In Zeile 66 muss natürlich "purchaseOrder.xsd" anstatt "previsions.xsd" stehen.

Läuft aber auch so nicht! 🙁
 
Schonmal EMF versucht? Ich hab gerade innerhalb von 5 Minuten ein komplettes Datenmodell inklusive XML Binding aus dem Schema erzeugt und daraus eine Jar erstellt.
Im Code kann man dann ganz einfach auf die XML zugreifen:

Code:
public class Main {
	public static void main(String[] args) {
		Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("xml", new SchemaResourceFactoryImpl());
		ResourceSet set = new ResourceSetImpl();
		Resource resource =  set.getResource(URI.createFileURI("demo.xml"),true);
		DocumentRoot root = (DocumentRoot)resource.getContents().get(0);
		PurchaseOrderType order = root.getPurchaseOrder();
		System.out.println(order.getReference());
	}
}

Ergebnis:
ADAMS-2001112712104128PST

Das Datenmodell kannst du dann einfach auf Objekt Ebene manipulieren und mit einer einzigen Zeile wieder in ein Schema konformes Format speichern :wink:
 
Öhm, erst mal danke dir für die schnelle Antwort, aber ich denke du hast mich falsch verstanden.

Ich will einfach nur die XML mittels Java gegen die XSD, die im gleichen Verzeichnis liegt, validieren und die Fehler (falls vorhanden) ausgeben.

Ich brauch ja kein Datenmodell oder sonstiges. Einfach nur ne "simple" Schema-Validierung.

Laut dem Text, den ich oben aus der DOM4J Doku kopiert habe, sollte das ja auch sehr einfach gehen, aber irgendwas stimmt bei mir im Code noch nicht und ich geh einfach mal davon aus, dass es sich nur um ne Kleinigkeit handelt.

Falls du also sonst noch ne Idee hast... 😉
 
Es wäre halt auch prima, wenn ich weiter DOM4J für das ganze Parsing etc. nutzen kann.

Weil das (sieht man jetzt zwar oben im Code nicht) klappt alles prima.
 
Auch jetzt noch mal danke, aber genau das hab ich schon gelesen und auch schon rumprobiert und ich habs einfach nicht hinbekommen?

Wie müsste denn deiner Meinung nach mein Code oben geändert werden?
Ich bekomm hier echt noch die Krise! Sitz da jetzt schon den halben Tag vor. Das bremst mich gerade voll aus! 🙁

Wäre toll, wenn du mir auf die Sprünge helfen könntest und ich nachher wieder beruhigt schlafen kann! 🙂
 
Hmm, mach mal einen XML Header rein, vielleicht stört er sich daran.
DOM4J hab ich noch nicht verwendet, ich bin mehr für Komplettpakete wie EMF oder JaxB zu haben...
 
XML-Header? Wie? Was? Wo? Wohin?

Naja, DOM4J würde ich dann ja nur fürs "Drumherum" nutzen.

Könnte ich nicht JAXP mit den folgenden Zeilen irgendwie für meinen Code nutzen?
Nur wenn ja, wie genau?
 
sowas:
<?xml version="1.0" encoding="UTF-8">

Naja, DOM4J würde ich dann ja nur fürs "Drumherum" nutzen.
In den meisten Anwendungen sind Binding Frameworks ein echter Mehrwert gegenüber herkömlichen XML Frameworks.
Für's nächste Projekt würde ich einen Blick riskieren...
 
So, habs jetzt hinbekommen.
War oben eigentlich schon sehr nah dran.

Hätte eigentlich nur anstatt reader.setProperty(...), folgendes schreiben müssen:

Code:
reader.setFeature("http://apache.org/xml/features/validation/schema", true);

Trotzdem noch mal danke für die Hilfe! 🙂

Werd hier mit Sicherheit noch öfter posten.

Tolles Forum! :toll:
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben