BATMAN_2008
BATMAN_2008

Reputation: 3530

Java XML validation against XSD fails at first error does not validate complete XML even with custom error handler

Is there a way I can validate my XML against my XSD COMPLETELY, meaning that I want the file to continue validating even after it has found an error so I can get the complete error messages rather than just 1 or the first error message?

Currently, the execution stops when it finds the first error, prints it, and does not continue any further. I want to know if it's possible to achieve this. I tried the method mentioned here and did the same but still it's not working as expected and execution stops.

Following is the code I have: XsdErrorHandler.class:

import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException;

public class XsdErrorHandler implements ErrorHandler {
   @lombok.Getter
    private java.util.List<SAXParseException> exceptions;

    public XsdErrorHandler() {
        this.exceptions = new java.util.ArrayList<>();
    }

    @Override
    public void warning(final SAXParseException exception) throws org.xml.sax.SAXException {
       handleError(exception);
    }

    @Override
    public void error(final SAXParseException exception) throws org.xml.sax.SAXException {
        handleError(exception);
    }

    @Override
    public void fatalError(final SAXParseException exception) throws org.xml.sax.SAXException  {
        handleError(exception);
    }

    public void handleError(SAXParseException e) throws org.xml.sax.SAXException  {
        // Do nothing. This will allow the validation to continue even if there are errors.
        this.exceptions.add(e);
    }
}

Following is my schema validator: Main.class

import javax.xml.XMLConstants;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestMain {
    public static void main(String[] args) throws SAXException, IOException {
        final String xsdPath = "/xsd/myXSD.xsd";
        final String xmlPath = "/myXml.xml";
        listParsingExceptions(xsdPath, xmlPath);
    }

    private static Validator initValidator(final String xsdPath) throws SAXException {
        final SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        final Source schemaFile = new StreamSource(TestMain.class.getResourceAsStream(xsdPath));
        final Schema schema = factory.newSchema(schemaFile);
        return schema.newValidator();
    }

    public static List<SAXParseException> listParsingExceptions(final String xsdPath, final String xmlPath) throws IOException, SAXException {
        final InputStream inputStream = TestMain.class.getResourceAsStream(xmlPath);
        final XsdErrorHandler xsdErrorHandler = new XsdErrorHandler();
        final Validator validator = initValidator(xsdPath);
        validator.setErrorHandler(xsdErrorHandler);

        try {
            validator.validate(new StreamSource(inputStream));
        } catch (SAXParseException e)
        {
            // ...
        }

        System.out.println("ERRORS : ");
        xsdErrorHandler.getExceptions().forEach(e -> System.out.println(e.getMessage()));
        return xsdErrorHandler.getExceptions();
    }
}

Issues:

  1. I am a bit confused about what else I need to do to make this continue working. Can someone please provide some suggestions?

  2. Also, my XSD contains many imports and references to other XSD. When I give a relative path, then it won't work, but when I give an absolute path, then it works. Is there a way I can make it work with a relative path?

Following fails:

<xsd:import namespace="urn:global:xsd:1" schemaLocation="./global.xsd"/>

Following works:


<xsd:import namespace="urn:global:xsd:1" schemaLocation="/Users/username/project/validation/src/main/resources/xsd/global.xsd"/>

I tried to provide the path for XSD file using maven-jaxb2-plugin something like this but this also did not work for me

    <build>
        <plugins>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.14.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <schemaDirectory>${basedir}/src/main/resources/xsd</schemaDirectory>
                </configuration>
            </plugin>
        </plugins>
    </build>

I tried to write my own ClasspathResourceResolver by referencing here and added to my schemaFactory using schemaFactory.setResourceResolver(new ClasspathResourceResolver()); but that also did not work for me.

All my files are present in the XSD folder and I would like to reference using the relative path something like this ./xsdName.xsd

Upvotes: 1

Views: 436

Answers (0)

Related Questions