-->

Example to validate a xml-File against an XSD v1.1

2019-07-27 22:37发布

问题:

  • My current validation does not work for XSD v1.1 Schemas .. I tried many things to change that, but until now without success
  • It does not matter for me if the solution is done with Saxon or Xerces (Edit: I dont want to spend money to solve the problem and it looks like Saxon XSD1.1 validation is not for free, so I quess I have to stick with Xerces)
  • Yes, I already searched SO for that, but so far none of the code-snippets helped me to get a working validation.
  • The code is goin to be used in an eclipse-plugin, if that should matter
  • I added the following jar-file to the project/classpath, however it looks like it is not used in my code:
<dependency>
  <groupId>xerces</groupId>
  <artifactId>xercesImpl</artifactId>
  <version>2.11.0</version>
</dependency>

Here the code I used so far for validation ( No problem with dumping it, if it cannot be used for xsd1.1 ):

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;

import org.apache.xerces.parsers.DOMParser;
import org.apache.xerces.xni.parser.XMLInputSource;

....

public List<MyError> validate(File xmlFile) {
    List<MyError> errors = null;
    try {
        DOMParser parser = new DOMParser();
        parser.setFeature(XmlUtils.VALIDATION, true);
        parser.setFeature(XmlUtils.VALIDATION_SCHEMA, true);
        parser.setFeature(XmlUtils.ALL_SCHEMA_LOCATIONS, true);
        parser.setFeature(XmlUtils.DEFER_NODE_EXPANSION, false);

        Handler handler = new Handler(xmlFile, parser);
        parser.setErrorHandler(handler);

        // there probably are smarter ways to do this
        String uri = xmlFile.toURI().toString().replace("%20", " ");
        InputStream inputStream = new FileInputStream(xmlFile);
        XMLInputSource inputSource = new XMLInputSource("", uri, uri, inputStream, "UTF-8");
        parser.parse(inputSource);

        errors = handler.getErrors();

    }
    catch (Exception e)
    {
        ConsoleHandler.printError("Document " + xmlFile.getName() + " has not been parsed correctly: " + e.getMessage(), true);
        ConsoleHandler.printStackTrace(e);
    }
    // printing the errors happens in some other method
    return errors;
}

回答1:

You have tagged this "Saxon" so I assume you are looking for a Saxon solution. (But you have also tagged it "Xerces"). You have explicitly instantiated the Xerces DOMParser, so there's nothing here that could possibly invoke Saxon as the schema validator. If you want a Xerces solution, then I'm no expert and can't help you. If you want a Saxon solution, you'll find plenty of examples in the saxon-resources download file (available both on SourceForge and saxonica.com). Here's are a couple of extracts that do roughly what you want:

s9api example:

            Processor proc = new Processor(true);
            SchemaManager sm = proc.getSchemaManager();
            sm.load(new StreamSource(new File("data/books.xsd")));

            try {
                SchemaValidator sv = sm.newSchemaValidator();
                sv.validate(new StreamSource(new File("data/books.xml")));
                System.out.println("First schema validation succeeded (as planned)");
            } catch (SaxonApiException err) {
                System.out.println("First schema validation failed");
            }

JAXP example:

            System.setProperty("javax.xml.transform.TransformerFactory",
                               "com.saxonica.config.EnterpriseTransformerFactory");
            TransformerFactory factory = TransformerFactory.newInstance();
            System.err.println("TransformerFactory class: " + factory.getClass().getName());
            factory.setAttribute(FeatureKeys.SCHEMA_VALIDATION, new Integer(Validation.STRICT));
            factory.setAttribute(FeatureKeys.VALIDATION_WARNINGS, Boolean.TRUE);
            if (args.length > 1) {
                StreamSource schema = new StreamSource(new File(args[1]).toURI().toString());
                ((EnterpriseTransformerFactory)factory).addSchema(schema);
            }
            Transformer trans = factory.newTransformer();
            StreamSource source = new StreamSource(new File(args[0]).toURI().toString());
            SAXResult sink = new SAXResult(new DefaultHandler());
            trans.transform(source, sink);


回答2:

Ok, I finally got my XML to validate against a XSD1.1 Schema with Xerces. Here the dependency I used:

<dependency>
    <groupId>org.opengis.cite.xerces</groupId>
    <artifactId>xercesImpl-xsd11</artifactId>
    <version>2.12-beta-r1667115</version>
</dependency>

( It seems like there is no official xerces release yet which supports xsd1.1. What first confused me: Xercex v2.11.0 seems not to support XSD1.1, where 2.11.0.beta does )

And here the source code I used:

import java.io.File;
import java.io.IOException;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.xml.sax.SAXException;

public class MyClass {

    public static void main(String[] args) {

        try {
            validateFile(new File("Test.xml") , new  File("Test.xsd"));
        } catch (Exception e) {

            e.printStackTrace();
        }
    }

    private static void validateFile(File xmlFile, File xsdFile) throws SAXException, IOException
    {
        SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/XML/XMLSchema/v1.1");
        File schemaLocation = xsdFile;
        Schema schema = factory.newSchema(schemaLocation);
        Validator validator = schema.newValidator();
        Source source = new StreamSource(xmlFile);
        try
        {
            validator.validate(source);
            System.out.println(xmlFile.getName() + " is valid.");
        }
        catch (SAXException ex)
        {
            System.out.println(xmlFile.getName() + " is not valid because ");
            System.out.println(ex.getMessage());
        }
    }
}

Edit: However my code does not yet run as eclipse-plugin. When validation is triggered in the plug-in, I get the following error:

!ENTRY org.eclipse.core.jobs 4 2 2016-03-15 15:14:37.852
!MESSAGE An internal error occurred during: "validation job".
!STACK 0
javax.xml.validation.SchemaFactoryConfigurationError: Provider for class javax.xml.validation.SchemaFactory cannot be created
    at javax.xml.validation.SchemaFactoryFinder.findServiceProvider(SchemaFactoryFinder.java:414)
    at javax.xml.validation.SchemaFactoryFinder._newFactory(SchemaFactoryFinder.java:218)
    at javax.xml.validation.SchemaFactoryFinder.newFactory(SchemaFactoryFinder.java:145)
    at javax.xml.validation.SchemaFactory.newInstance(SchemaFactory.java:213)
    at plugin.control.validation.MyValidator.validateFile(MyValidator.java:39)
    at
...

The line of my code where the exception is thrown:

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/XML/XMLSchema/v1.1");