# Problem mit XML-Schema Validierung mit Java



## Guest (17. Okt 2007)

Hallo zusammen,

ich hab hier folgenden Java-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:



```
<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:

```
<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:

```
<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.
> 
> ...



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]


----------



## Masipulami (17. Okt 2007)

So, jetzt bin ich auch mal eingeloggt.
Der obere Eintrag ist von mir.


----------



## Masipulami (17. Okt 2007)

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!


----------



## Wildcard (17. Okt 2007)

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:


```
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:


----------



## Masipulami (17. Okt 2007)

Ö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...


----------



## Masipulami (17. Okt 2007)

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.


----------



## Wildcard (17. Okt 2007)

Och, das ist ja langweilig   
einfache Validierung gegen ein Schema: http://java.sun.com/developer/EJTechTips/2005/tt1025.html#1


----------



## Masipulami (17. Okt 2007)

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!


----------



## Wildcard (17. Okt 2007)

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...


----------



## Masipulami (17. Okt 2007)

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?


----------



## Wildcard (17. Okt 2007)

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...


----------



## Masipulami (18. Okt 2007)

So, habs jetzt hinbekommen.
War oben eigentlich schon sehr nah dran.

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


```
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:


----------



## NegiMagi (21. Nov 2007)

Könnte mir mal jemand den Kompletten Quellcode ohne fehler schicken?! 

Danke im voraus 

MFG NegiMagi


----------

