Réponses:
La bibliothèque d'exécution Java prend en charge la validation. La dernière fois que j'ai vérifié, c'était l'analyseur 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éma 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 facilement valider par rapport à un fichier local.
Vous ne devez pas utiliser DOMParser pour valider un document (à moins que votre objectif ne soit de toute façon de créer un modèle d'objet de document). Cela commencera à créer des objets DOM lors de l'analyse du document, ce qui est inutile si vous ne les utilisez pas.
Voici comment le faire en utilisant Xerces2 . Un tutoriel pour cela, ici (inscription requise).
Attribution originale: copiée de façon flagrante à partir d' ici :
import org.apache.xerces.parsers.DOMParser;
import java.io.File;
import org.w3c.dom.Document;
public class SchemaTest {
public static void main (String 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, afin que nous puissions utiliser la tâche schemavalidate pour vérifier nos fichiers de configuration:
<schemavalidate>
<fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>
Maintenant, les fichiers de configuration coquins échoueront dans notre build!
Puisque c'est une question populaire, je soulignerai que java peut également valider par rapport aux xsd "référencés", par exemple si le fichier .xml lui-même spécifie les XSD dans l'en-tête, en utilisant xsi:SchemaLocation
ou xsi:noNamespaceSchemaLocation
(ou xsi pour des espaces de noms particuliers) ex :
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
...
ou SchemaLocation (toujours une liste d'espaces de noms aux mappages xsd)
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:SchemaLocation="http://www.example.com/my_namespace http://www.example.com/document.xsd">
...
Les autres réponses fonctionnent également ici, car les fichiers .xsd sont "mappés" aux espaces de noms déclarés dans le fichier .xml, car ils déclarent un espace de noms, et si cela correspond à l'espace de noms dans le fichier .xml, vous êtes bon. Mais parfois c'est pratique d'avoir un résolveur personnalisé ...
À partir des javadocs: "Si vous créez un schéma sans spécifier d'URL, de fichier ou de source, le langage Java en crée un qui examine le document en cours de validation pour trouver le schéma qu'il doit 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 xmlsns:xsi
c'est probablement un emplacement réseau, donc il va par défaut s'éteindre et frapper le réseau avec chaque validation, pas toujours optimale.
Voici un exemple qui valide un fichier XML par rapport aux références informatiques de n'importe quel XSD (même s'il doit les extraire du réseau):
public static void verifyValidatesInternalXsd(String filename) throws Exception {
InputStream xmlStream = new new FileInputStream(filename);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(true);
factory.setAttribute("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 les XSD référencés du réseau, même si les fichiers xml font référence aux URL, en spécifiant le xsd manuellement (voir d'autres réponses ici) ou en utilisant un résolveur de style "catalogue XML" . Spring peut également intercepter les demandes d'URL pour servir des fichiers locaux pour les validations. Ou vous pouvez définir le vôtre via setResourceResolver , par exemple:
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(String type, String namespaceURI,
String publicId, String systemId, String 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.
Je crois que la valeur par défaut est d'utiliser l'analyse DOM, vous pouvez faire quelque chose de similaire avec l'analyseur SAX qui valide également saxReader.setEntityResolver(your_resolver_here);
setResourceResolver
mais au-delà, ouvrez peut-être une nouvelle question ...
En utilisant Java 7, vous pouvez suivre la documentation fournie dans la description du package .
// 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 StreamSource(new File("instance.xml")); } catch (SAXException e) { // instance document is invalid! }
parser.parse(new File("instance.xml"))
. L' validator
accepte un Source
, vous pouvez: validator.validate(new StreamSource(new File("instance.xml")))
.
ErrorHandler
si vous avez besoin de faire une validation.
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. 5s pour un fichier de 50 Mo.
Dans Debian Squeeze, il se trouve dans le paquet "libxerces-c-samples".
La définition du dtd et du xsd doit être dans le xml! Vous ne pouvez pas les configurer séparément.
xmllint --schema phone.xsd phone.xml
(d'après une réponse de 13ren)
Une autre réponse: puisque vous avez dit que vous devez valider les fichiers que vous générez (écriture), vous voudrez peut-être valider le contenu pendant que vous écrivez, au lieu de d'abord écrire, puis 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, liez simplement le validateur en appelant 'Validator.validate (source, result)', où la source provient de votre écrivain, et le résultat est où la sortie doit aller.
Alternativement, 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 programme, vous souhaiterez peut-être consulter la bibliothèque XMLBeans . À l'aide d'un outil en ligne de commande, XMLBeans générera et conditionnera automatiquement un ensemble d'objets Java basé sur un XSD. Vous pouvez ensuite utiliser ces objets pour créer un document XML basé sur ce schéma.
Il prend en charge la validation de schéma et peut convertir des objets Java en document XML et vice-versa.
Castor et JAXB sont d'autres bibliothèques Java qui ont un objectif similaire à XMLBeans.
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 String xmlFileName, final String 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 (String 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<String> validationErrors;
public MyValidationEventCollector() {
validationErrors = new ArrayList<>();
}
public List<String> getValidationErrors() {
return Collections.unmodifiableList(validationErrors);
}
@Override
public boolean handleEvent(final ValidationEvent event) {
String pattern = "line {0}, column {1}, error message {2}";
String 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
}
}
Vous recherchez un outil ou une bibliothèque?
En ce qui concerne les bibliothèques, la norme de facto est à peu près Xerces2, qui a à la fois des versions C ++ et Java .
Soyez averti cependant, c'est une solution lourde. Mais là encore, la validation de XML par rapport aux fichiers XSD est un problème assez lourd.
Quant à un outil pour le faire pour vous, XMLFox semble être une solution freeware décente, mais ne l'ayant pas utilisé personnellement, je ne peux pas le dire avec certitude.
Valider par rapport aux schémas en ligne
Source xmlFile = new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream("your.xml"));
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(Thread.currentThread().getContextClassLoader().getResource("your.xsd"));
Validator validator = schema.newValidator();
validator.validate(xmlFile);
Valider par rapport aux schémas locaux
À l'aide de Woodstox , configurez l'analyseur StAX pour valider par rapport à votre schéma et analyser le XML.
Si des exceptions sont interceptées, le XML n'est pas valide, sinon il est valide:
// create the XSD schema from your schema file
XMLValidationSchemaFactory schemaFactory = XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA);
XMLValidationSchema validationSchema = schemaFactory.createSchema(schemaInputStream);
// create the XML reader for your XML file
WstxInputFactory inputFactory = new WstxInputFactory();
XMLStreamReader2 xmlReader = (XMLStreamReader2) inputFactory.createXMLStreamReader(xmlInputStream);
try {
// configure the reader to validate against the schema
xmlReader.validateAgainst(validationSchema);
// parse the XML
while (xmlReader.hasNext()) {
xmlReader.next();
}
// no exceptions, the XML is valid
} catch (XMLStreamException e) {
// exceptions, the XML is not valid
} finally {
xmlReader.close();
}
Remarque : Si vous devez valider plusieurs fichiers, vous devez essayer de réutiliser votre XMLInputFactory
et XMLValidationSchema
afin de maximiser les performances.
J'ai dû valider un XML contre XSD une seule fois, j'ai donc essayé XMLFox. Je l'ai trouvé 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) qui était beaucoup plus facile à utiliser et plus immédiatement 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 la version d'essai de 30 jours.