XML-Datei mit Java einlesen und gegen ein Schema validieren

Eine XML-Datei mit Java einzulesen und gegen ein XML-Schema zu validieren ist recht einfach, wenn man weiß wie es geht 😉

Gut, dass es zu diesem Thema einige sehr gute Quellen im Internet gibt (z.B. XML Validation and XPath Evaluation in J2SE 5.0 oder Validation with Java and XML Schema, Part 3). Zuerst habe ich es mit der hier beschriebenen Vorgehensweise probiert: Validating with XML Schema. Kurz gesagt: man holt sich eine DocumentBuilderFactory und konfiguriert sie mittels setValidating(true), um die XML-Datei zu validieren. Dafür muss jedoch in der entsprechenden XML-Datei dann auf das XML-Schema verwiesen werden (mittels schemaLocation), was in meinem Fall zu Problemen beim Auflösen von Pfaden führte (die man aber sicher irgendwie umgehen kann). Darüber hinaus hat die Validierung von Constraints (in meinem Fall unique) nicht korrekt funktioniert, sodass ich den Weg über einen Validator gegangen bin.

Doch zunächst einmal mein Beispiel: Es handelt sich um eine XML-Datei, die (sehr einfach) den Aufbau einer Fertigungsanlage beschreibt (siehe Bild hier: Wegfindung mit dem A*-Algorithmus in Java). Eine ProductionPlant enthält Modules (die Teile der Anlage wie z.B. Förderbänder und Drehteller) und Connections zwischen diesen, die jedoch für mein Beispiel nicht wichtig sind. Jedes Module hat eine (eindeutige → unique) ID.

Der eigentliche Code, der nun die XML-Datei einliest und validiert, ist der folgende:

// create a factory that understands namespaces and validates the XML input DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); // read the XML file DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new File("SamplePlant.xml")); // create a SchemaFactory and a Schema SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Source schemaFile = new StreamSource(new File("ProductionPlant.xsd")); Schema schema = schemaFactory.newSchema(schemaFile); // create a Validator object and validate the XML file Validator validator = schema.newValidator(); validator.validate(new DOMSource(doc)); System.out.println("XML file successfully validated.");

Download

In eine Klasse gepackt und um die import-Anweisungen und einen (einfachen) ErrorHandler ergänzt, gibt es das Ganze hier zum Download: PlantBuilder.

Wie folgt kann das kleine Programm gestartet werden:

Kompilierung und Ausführung von PlantBuilder

Über Stefan

Polyglot Clean Code Developer

3 Kommentare

  1. Hallo,
    ich habe diesen Code benutzt um eine XML-Datei gegen ein selbstgeschriebenes Schema zu validieren. Nachdem ich zuerst Fehlermeldungen bekam, da das Schema wohl noch nicht so 100%ig korrekt war, hat er mir immer ausgegeben, dass das XML file successfully validated sein soll. Nur, es wird anscheinend jede XML-datei succssfully validated… Also ich konnte auch Fehler einbauen und habe danach auch noch andere XML-files ausprobiert und es kommt immer die Erfolgsmeldung.
    Woran kann das liegen?
    Danke für eine Antwort. Ich bin da so n bisschen an meinen Grenzen.
    Gruß,
    Daniel

  2. @Daniel: Sorry, kann ich dir so nicht sagen! Schickst du mir mal dein Programm und die XML-/XSD-Datei per Mail?

  3. Danke für den Code.
    Leider funktioniert das mit JRE6 nicht wie gewünscht. Der DocumentBuilder validiert, wenn er ein Schema finden kann, die Datei schon selbst. Falls dann eine Schema-Inkonformität gefunden wird, schmeisst schon der DocumentBuilder eine (ungenaue) Fehlermeldung. Da nützt auch nichts, wenn man bei der DocumentBuilderFactory.setValiditing(false) setzt, denn das bezieht sich auf DTDs, nicht auf XSD Schemas…

    Mit folgendem Code geht es:

    public static void validateXML(File xmlFile, File schemaFile, boolean nameSpaceAware, 
    			ErrorHandler errHandler) throws Exception
    	{
    		try
    		{
    			// create a SchemaFactory and a Schema
    			SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    			Source schemaSource = new StreamSource(schemaFile);
    			Schema schema = schemaFactory.newSchema(schemaSource);
    			
    			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    			dbf.setNamespaceAware(true); //so we can correctly validate the file.
    			dbf.setSchema(schema);
    			DocumentBuilder db = dbf.newDocumentBuilder();
    			db.setErrorHandler(errHandler);
    			Document doc = db.parse(xmlFile);
    		}
    		catch (SAXParseException spe)
    		{
    			// error generated by the parser
    			String message = "** Parser error! **\n  URI: " + spe.getSystemId() + "\n  Line: " + spe.getLineNumber() + "\n  Message: " + spe.getMessage();
    			Exception x = spe;
    			if (spe.getException() != null)
    				x = spe.getException();
    			throw new Exception(message, x);
    		}
    		catch (SAXException sxe)
    		{
    			Exception x = sxe;
    			if (sxe.getException() != null)
    				x = sxe.getException();
    			throw new Exception("Error during parsing.", x);
    
    		}
    		catch (ParserConfigurationException pce)
    		{
    			throw new Exception("Parser with specified options can't be built.", pce);
    		}
    		catch (IOException ioe)
    		{
    			// I/O error
    			throw new Exception("Error reading file.", ioe);
    		}
    	}
    

    Den Error Handler kann man so belassen wie von dir angegeben.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax