Quelle est la meilleure façon de valider un fichier XML sur un fichier XSD?

Je génère des fichiers XML qui doivent se conformer à un fichier xsd qui m’a été donné. Quelle est la meilleure façon de vérifier leur conformité?

La bibliothèque d’exécution Java prend en charge la validation. La dernière fois que j’ai vérifié, c’était l’parsingur Apache Xerces sous les couvertures. Vous devriez probablement utiliser un javax.xml.validation.Validator .

import javax.xml.XMLConstants; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.*; import java.net.URL; import org.xml.sax.SAXException; //import java.io.File; // if you use File import java.io.IOException; ... URL schemaFile = new URL("http://host:port/filename.xsd"); // webapp example xsd: // URL schemaFile = new URL("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"); // local file example: // File schemaFile = new File("/location/to/localfile.xsd"); // etc. Source xmlFile = new StreamSource(new File("web.xml")); SchemaFactory schemaFactory = SchemaFactory .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); try { Schema schema = schemaFactory.newSchema(schemaFile); Validator validator = schema.newValidator(); validator.validate(xmlFile); System.out.println(xmlFile.getSystemId() + " is valid"); } catch (SAXException e) { System.out.println(xmlFile.getSystemId() + " is NOT valid reason:" + e); } catch (IOException e) {} 

La constante de fabrique de schémas est la chaîne http://www.w3.org/2001/XMLSchema qui définit les XSD. Le code ci-dessus valide un descripteur de déploiement WAR par rapport à l’URL http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd mais vous pouvez tout aussi bien valider par rapport à un fichier local.

Vous ne devez pas utiliser DOMParser pour valider un document (à moins que votre objective ne soit de créer un modèle d’object de document). Cela va commencer à créer des objects DOM pendant qu’il parsing le document – ce qui est inutile si vous ne l’utilisez pas.

Voici comment procéder en utilisant Xerces2 . Un tutoriel pour cela, ici (inscription obligatoire).

Atsortingbution originale: copiée de manière flagrante d’ ici :

 import org.apache.xerces.parsers.DOMParser; import java.io.File; import org.w3c.dom.Document; public class SchemaTest { public static void main (Ssortingng args[]) { File docFile = new File("memory.xml"); try { DOMParser parser = new DOMParser(); parser.setFeature("http://xml.org/sax/features/validation", true); parser.setProperty( "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", "memory.xsd"); ErrorChecker errors = new ErrorChecker(); parser.setErrorHandler(errors); parser.parse("memory.xml"); } catch (Exception e) { System.out.print("Problem parsing the file."); } } } 

Nous construisons notre projet en utilisant ant, donc nous pouvons utiliser la tâche schemavalidate pour vérifier nos fichiers de configuration:

    

Les fichiers de configuration vilains vont maintenant échouer à notre build!

http://ant.apache.org/manual/Tasks/schemavalidate.html

J’ai trouvé ce site aussi utile.

http://www.ibm.com/developerworks/xml/library/x-javaxmlvalidapi.html

C’est celui qui a fonctionné pour moi avec un minimum de tracas.

Comme il s’agit d’une question populaire, je voudrais également souligner que java peut valider contre un xsd “référencé”, par exemple si le fichier .xml lui-même spécifie un XSD, utilisant xsi:SchemaLocation ou xsi:noNamespaceSchemaLocation (ou xsi pour espaces de noms particuliers) comme indiqué ici :

  ... 

ou SchemaLocation (toujours une liste d’espaces de noms vers les mappages xsd)

  ... 

“Si vous créez un schéma sans spécifier une URL, un fichier ou une source, le langage Java en crée un qui recherche dans le document en cours de validation le schéma à utiliser. Par exemple:”

 SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); Schema schema = factory.newSchema(); 

et cela fonctionne pour plusieurs espaces de noms, etc. Le problème avec cette approche est que le xmlsns:xsi est probablement un emplacement réseau, donc il va sortir et bash le réseau avec chaque validation, pas toujours optimale.

Voici un exemple qui valide un fichier XML par rapport à un XSD auquel il fait référence (même s’il doit les extraire du réseau):

  public static void verifyValidatesInternalXsd(Ssortingng filename) throws Exception { InputStream xmlStream = new new FileInputStream(filename); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); factory.setNamespaceAware(true); factory.setAtsortingbute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler(new RaiseOnErrorHandler()); builder.parse(new InputSource(xmlStream)); xmlStream.close(); } public static class RaiseOnErrorHandler implements ErrorHandler { public void warning(SAXParseException e) throws SAXException { throw new RuntimeException(e); } public void error(SAXParseException e) throws SAXException { throw new RuntimeException(e); } public void fatalError(SAXParseException e) throws SAXException { throw new RuntimeException(e); } } 

Vous pouvez éviter de tirer des XSD référencés du réseau, même si les fichiers XML font référence aux URL, en spécifiant le fichier xsd manuellement (voir d’autres réponses ici) ou en utilisant un résolveur de style “catalogue XML”. Spring, apparemment, peut également intercepter les demandes d’URL pour servir des fichiers locaux pour des validations. Ou vous pouvez définir votre propre via setResourceResolver , ex:

 Source xmlFile = new StreamSource(xmlFileLocation); SchemaFactory schemaFactory = SchemaFactory .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = schemaFactory.newSchema(); Validator validator = schema.newValidator(); validator.setResourceResolver(new LSResourceResolver() { @Override public LSInput resolveResource(Ssortingng type, Ssortingng namespaceURI, Ssortingng publicId, Ssortingng systemId, Ssortingng baseURI) { InputSource is = new InputSource( getClass().getResourceAsStream( "some_local_file_in_the_jar.xsd")); // or lookup by URI, etc... return new Input(is); // for class Input see // https://stackoverflow.com/a/2342859/32453 } }); validator.validate(xmlFile); 

Voir aussi ici pour un autre tutoriel.

En utilisant Java 7, vous pouvez suivre la documentation fournie dans la description du package .

 // parse an XML document into a DOM tree DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = parser.parse(new File("instance.xml")); // create a SchemaFactory capable of understanding WXS schemas SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // load a WXS schema, represented by a Schema instance Source schemaFile = new StreamSource(new File("mySchema.xsd")); Schema schema = factory.newSchema(schemaFile); // create a Validator instance, which can be used to validate an instance document Validator validator = schema.newValidator(); // validate the DOM tree try { validator.validate(new DOMSource(document)); } catch (SAXException e) { // instance document is invalid! } 

Si vous avez une machine Linux, vous pouvez utiliser l’outil de ligne de commande gratuit SAXCount. J’ai trouvé cela très utile.

 SAXCount -f -s -n my.xml 

Il valide contre dtd et xsd. 5 s pour un fichier de 50 Mo.

Dans debian squeeze, il se trouve dans le paquet “libxerces-c-samples”.

La définition de dtd et xsd doit être dans le xml! Vous ne pouvez pas les configurer séparément.

Une réponse de plus: comme vous avez dit que vous devez valider les fichiers que vous générez (écriture), vous pouvez valider le contenu pendant que vous écrivez, au lieu de commencer par écrire, puis de relire pour validation. Vous pouvez probablement le faire avec l’API JDK pour la validation Xml, si vous utilisez un écrivain basé sur SAX: si c’est le cas, insérez simplement le validateur en appelant «Validator.validate (source, result)», où source provient de votre écrivain. où la production doit aller.

Si vous utilisez Stax pour écrire du contenu (ou une bibliothèque qui utilise ou peut utiliser Stax), Woodstox peut également prendre en charge directement la validation lors de l’utilisation de XMLStreamWriter. Voici une entrée de blog montrant comment cela se fait:

Si vous générez des fichiers XML par programmation, vous souhaiterez peut-être consulter la bibliothèque XMLBeans . À l’aide d’un outil de ligne de commande, XMLBeans génère et empaquette automatiquement un ensemble d’objects Java basés sur un XSD. Vous pouvez ensuite utiliser ces objects pour créer un document XML basé sur ce schéma.

Il prend en charge la validation de schéma et peut convertir des objects Java en un document XML et inversement.

Castor et JAXB sont d’autres bibliothèques Java qui ont un objective similaire à XMLBeans.

Vous recherchez un outil ou une bibliothèque?

En ce qui concerne les bibliothèques, la norme de facto est Xerces2, qui possède à la fois des versions C ++ et Java .

Attention cependant, c’est une solution lourde. Mais encore une fois, la validation de XML contre des fichiers XSD est un problème de poids plutôt lourd.

Quant à un outil pour le faire, XMLFox semble être une solution décente de freeware, mais ne pas l’avoir utilisée personnellement, je ne peux pas le dire avec certitude.

Avec JAXB, vous pouvez utiliser le code ci-dessous:

  @Test public void testCheckXmlIsValidAgainstSchema() { logger.info("Validating an XML file against the latest schema..."); MyValidationEventCollector vec = new MyValidationEventCollector(); validateXmlAgainstSchema(vec, inputXmlFileName, inputXmlSchemaName, inputXmlRootClass); assertThat(vec.getValidationErrors().isEmpty(), is(expectedValidationResult)); } private void validateXmlAgainstSchema(final MyValidationEventCollector vec, final Ssortingng xmlFileName, final Ssortingng xsdSchemaName, final Class rootClass) { try (InputStream xmlFileIs = Thread.currentThread().getContextClassLoader().getResourceAsStream(xmlFileName);) { final JAXBContext jContext = JAXBContext.newInstance(rootClass); // Unmarshal the data from InputStream final Unmarshaller unmarshaller = jContext.createUnmarshaller(); final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); final InputStream schemaAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(xsdSchemaName); unmarshaller.setSchema(sf.newSchema(new StreamSource(schemaAsStream))); unmarshaller.setEventHandler(vec); unmarshaller.unmarshal(new StreamSource(xmlFileIs), rootClass).getValue(); // The Document class is the root object in the XML file you want to validate for (Ssortingng validationError : vec.getValidationErrors()) { logger.trace(validationError); } } catch (final Exception e) { logger.error("The validation of the XML file " + xmlFileName + " failed: ", e); } } class MyValidationEventCollector implements ValidationEventHandler { private final List validationErrors; public MyValidationEventCollector() { validationErrors = new ArrayList<>(); } public List getValidationErrors() { return Collections.unmodifiableList(validationErrors); } @Override public boolean handleEvent(final ValidationEvent event) { Ssortingng pattern = "line {0}, column {1}, error message {2}"; Ssortingng errorMessage = MessageFormat.format(pattern, event.getLocator().getLineNumber(), event.getLocator().getColumnNumber(), event.getMessage()); if (event.getSeverity() == ValidationEvent.FATAL_ERROR) { validationErrors.add(errorMessage); } return true; // you collect the validation errors in a List and handle them later } } 

J’ai dû valider un XML contre XSD juste une fois, j’ai donc essayé XMLFox. J’ai trouvé ça très déroutant et bizarre. Les instructions d’aide ne semblaient pas correspondre à l’interface.

J’ai fini par utiliser LiquidXML Studio 2008 (v6), beaucoup plus facile à utiliser et plus familier (l’interface utilisateur est très similaire à Visual Basic 2008 Express, que j’utilise fréquemment). L’inconvénient: la capacité de validation n’est pas dans la version gratuite, j’ai donc dû utiliser l’essai de 30 jours.