Comment valider un fichier schema (le XSD lui-même)
Bonjour,
je voudrais valider un fichier XSD pour vérifier qu'il a bien été formé.
Dans ce fichier XSD, je n'ai, pour l'exemple et le test, utilisé que des balises par défaut et sans namespace.
voici le fichier XSD que je veux valider.
Code:
1 2 3 4 5 6 7
|
<?xml version='1.0' encoding='utf-8' ?>
<schema xmlns='http://www.w3.org/2001/XMLSchema' elementFormDefault='qualified' version='1.0'>
<annotation>
<documentation>...</documentation>
</annotation>
</schema> |
En cela, j'ai téléchargé les XSD et DTD se trouvant ici http://www.w3.org/2001/XMLSchema et j'utilise donc le fichier XMLSchema .xsd pour ma validation.
Mais lorsque je lance la validation, j'ai l'erreur suivante:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'xml:lang' to a(n) 'attribute declaration' component.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDHandler.reportSchemaError(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDHandler.getGlobalDecl(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDAttributeTraverser.traverseLocal(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDAbstractTraverser.traverseAttrsAndAttrGrps(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDComplexTypeTraverser.processComplexContent(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDComplexTypeTraverser.traverseComplexContent(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDComplexTypeTraverser.traverseComplexTypeDecl(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDComplexTypeTraverser.traverseLocal(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDElementTraverser.traverseNamedElement(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDElementTraverser.traverseGlobal(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDHandler.traverseSchemas(Unknown Source)
at org.apache.xerces.impl.xs.traversers.XSDHandler.parseSchema(Unknown Source)
at org.apache.xerces.impl.xs.XMLSchemaLoader.loadSchema(Unknown Source)
at org.apache.xerces.impl.xs.XMLSchemaLoader.loadGrammar(Unknown Source)
at org.apache.xerces.impl.xs.XMLSchemaLoader.loadGrammar(Unknown Source)
at org.apache.xerces.jaxp.validation.XMLSchemaFactory.newSchema(Unknown Source)
at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:594)
at xx.yyy.zzzzzz.util.XMLUtils.validate(XMLUtils.java:226)
at xx.yyy.zzzzzz.config.ConfigurationValidator.validateOneFragmentFile(ConfigurationValidator.java:303)
at xx.yyy.zzzzzz.config.ConfigurationValidator.generateProcessXSD(ConfigurationValidator.java:123)
at xx.yyy.zzzzzz.runner.SoftwareRunner.generateProcessXSDIfSpecifiedAndExit(SoftwareRunner.java:238)
at xx.yyy.zzzzzz.runner.SoftwareRunner.main(SoftwareRunner.java:142) |
Voici le code Java que j'utilise
Code:
1 2 3 4 5 6 7 8 9 10 11
|
final Source xsdSource = new SAXSource(new InputSource(xsdStream));
final Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(xsdSource);
final Validator validator = schema.newValidator();
final Source source = new StreamSource(xmlFile);
try {
validator.validate(source);
return true;
} catch (SAXException e) {
return false;
} |
L'exception est lancée au niveau du validator.validate(source);Je suis sous oracle JDK 6
J'arrive très bien à valider des fichiers XML contre des XSD.
J'obtiens cette exception uniquement lorsque j'essaie de valider un fichier XSD (qui n'est rien d'autre qu'un fichier XML aussi ...)
J'ai un peu cherché déjà, mais je sèche.
J'ai aussi téléchargé et mis dans mon CLASSPATH les lib xercesImpl et ses dépendances pour solutionner tout ceci, mais rien n'y fait.
Est ce que quelqu'un d'autre aurait une solution ?
Merci d'avance.
Cordialement,
Solution et code "final".
Rebonjour,
Bon, j'ai finalement trouvé la solution en suivant les indications que tu m'as données.
Je "résume".
J'ai fait une implémentation de LSResourceResolver
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
private static class CustomLSResourceResolver implements LSResourceResolver {
CustomLSResourceResolver() {
}
@Override
public LSInput resolveResource(
String type, String namespaceURI, String publicId, String systemId, String baseURI) {
InputStream input = null;
if (systemId.equals("http://www.w3.org/2001/xml.xsd")) {
input = Thread.currentThread().getClass().getResourceAsStream("/xsd/xml.xsd");
}
return new CustomLSInput(systemId, publicId, baseURI, input);
}
} |
Où CustomLSInput est une implémentation de LSInput
Voici mon implémentation de LSInput
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
private static class CustomLSInput implements LSInput {
private String systemId;
private String publicId;
private String baseURI;
private InputStream input;
CustomLSInput(String systemId, String publicId, String baseURI, InputStream input) {
this.systemId = systemId;
this.publicId = publicId;
this.baseURI = baseURI;
this.input = input;
}
@Override
public Reader getCharacterStream() {
return null;
}
@Override
public void setCharacterStream(Reader characterStream) {
}
@Override
public InputStream getByteStream() {
return null;
}
@Override
public void setByteStream(InputStream byteStream) {
}
@Override
public String getStringData() {
if (this.input == null) return null;
try {
byte[] data = new byte[this.input.available()];
this.input.read(data);
final String contents = new String(data);
return contents;
} catch (IOException e) {
e.printStackTrace(System.err);
return null;
}
}
@Override
public void setStringData(String stringData) {
}
@Override
public String getSystemId() {
return this.systemId;
}
@Override
public void setSystemId(String systemId) {
}
@Override
public String getPublicId() {
return this.publicId;
}
@Override
public void setPublicId(String publicId) {
}
@Override
public String getBaseURI() {
return this.baseURI;
}
@Override
public void setBaseURI(String baseURI) {
}
@Override
public String getEncoding() {
return null;
}
@Override
public void setEncoding(String encoding) {
}
@Override
public boolean getCertifiedText() {
return false;
}
@Override
public void setCertifiedText(boolean certifiedText) {
}
} |
Mais cela ne suffit pas, il faut ensuite faire une implémentation de EntityResolver afin de pouvoir trouver la localisation des ressources "Schema.dtd" , "datatypes.dtd" etc ... (c'est obligatoire, sinon, si on veut se passer d'un EntityResolver, il faudrait poser ces fichier au même endroit où l'application a été lancé, c'est à dire à System.getProperty("user.dir");
Voici mon implémentation d'EntityResolver.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
private static class CustomXSDEntityResolver implements EntityResolver {
CustomXSDEntityResolver() {
}
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
InputStream xsd = null;
if (systemId.equals(XMLConstants.XML_NS_URI)) {
xsd = CommonUtils.getResourceAsStream("/xsd/xml.xsd", false);
} else if (systemId.endsWith("XMLSchema.dtd")) {
xsd = CommonUtils.getResourceAsStream("/xsd/XMLSchema.dtd", false);
} else if (systemId.endsWith("datatypes.dtd")) {
xsd = CommonUtils.getResourceAsStream("/xsd/datatypes.dtd", false);
} else {
// On laisse le comportement par défaut.
return null;
}
return new InputSource(xsd);
}
} |
Ensuite, je suis passé à la validation de mes fichiers XSD en passant, bien évidemment comme XSD -> Schema.xsd
Je reposte le code simplifié de validation:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
final InputStream xsdStream = Thread.currentThread().getClass().getResourceAsStream("/xsd/Schema.xsd");
// Il faut quand même vérifier que xsdStream n'est pas null ...
final XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setEntityResolver(new CustomXSDEntityResolver());
final Source xsdSource = new SAXSource(xmlReader, new InputSource(xsd));
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setResourceResolver(new CustomLSResourceResolver());
final Schema schema = schemaFactory.newSchema(xsdSource);
final Validator validator = schema.newValidator();
final Source source = new StreamSource(xml);
try {
validator.validate(source);
return true;
} catch (SAXException e) {
return false;
} |
NOTE: Dans mon exemple de code, les fichiers "Schema.xsd", Schema.dtd, datatypes.dtd et xml.xsd se trouvent dans le répertoire src/main/resources/xsd (donc, dans le CLASSPATH pour plus de facilités)
Merci pour tout.