Reputation: 21124
I have to validate an xml file against an xsd grammer. What follows is a simple simulation of my original requirement.
There's a root element named <foo>
It has four child elements, let's denote them as child1, child2, child3 and child4 for the sake of simplicity.
<foo />
a valid xml.After going through some existing answers, I figured out that the more verbose answer given in [1]
is not a practical solution to my problem since there are more than 10 child elements
would yield to a combinatorial explosion. Then, in the latter part of the answer states that xsd 1.1
relaxes some of the constraints, so that the use of <xs:all>
along with maxOccurs="unbounded"
is allowed.
Then I used xerces library, and tried using xsd 1.1 features with java. What follows is my sample code. However, when multiple elements are presented in the xml, I am getting the following error. cvc-complex-type.2.4.a: Invalid content was found starting with element 'child1'. One of '{child2, child3, child4}' is expected.
xsd schema with xsd 1.1 extensions.
<?xml version="1.1" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
elementFormDefault="qualified" vc:minVersion="1.1">
<xs:element name="foo">
<xs:complexType>
<xs:all>
<xs:element name="child1" vc:minOccurs="0"
vc:maxOccurs="unbounded" />
<xs:element name="child2" vc:minOccurs="0"
vc:maxOccurs="unbounded" />
<xs:element name="child3" type="xs:string" />
<xs:element name="child4" type="xs:string" />
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
xml payload
<foo>
<child1> a </child1>
<child1> b </child1>
<child3> c </child3>
<child2> d </child2>
<child4> e </child4>
<child2> g </child2>
<child1> f </child1>
</foo>
maven dependency
<dependency>
<groupId>org.opengis.cite.xerces</groupId>
<artifactId>xercesImpl-xsd11</artifactId>
<version>2.12-beta-r1667115</version>
<exclusions>
<exclusion>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.exist-db.thirdparty.org.eclipse.wst.xml</groupId>
<artifactId>xpath2</artifactId>
<version>1.2.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>edu.princeton.cup</groupId>
<artifactId>java-cup</artifactId>
<version>10k</version>
<scope>runtime</scope>
</dependency>
or
<dependency>
<groupId>org.ibissource</groupId>
<artifactId>ibis-xerces</artifactId>
<version>2.12.2-xml-schema-1.1</version>
</dependency>
sample java code:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.StringJoiner;
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.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
public class CrtDataValidatorImpl {
public void validate(String xsdFilePath, String data) {
final XmlErrorHandler errorHandler = new XmlErrorHandler();
try {
final File schemaFile = new File(xsdFilePath);
final SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/XML/XMLSchema/v1.1");
final Schema schema = schemaFactory.newSchema(schemaFile);
final Validator validator = schema.newValidator();
validator.setErrorHandler(errorHandler);
final Source xmlSource = new StreamSource(new StringReader(data));
validator.validate(xmlSource);
} catch (SAXException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
}
System.out.println(String.format("Number of errors: %s", errorHandler.getExceptions().size()));
for (Exception ex : errorHandler.getExceptions())
System.out.println(ex.getMessage());
}
public static void main(String[] args) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader("./src/main/resources/simple-payload.xml"))) {
final StringJoiner sj = new StringJoiner("\n");
String line = br.readLine();
while (line != null) {
sj.add(line);
line = br.readLine();
}
System.out.println(sj.toString());
new CrtDataValidatorImpl().validate("./src/main/resources/sample.xsd", sj.toString());
}
}
static class XmlErrorHandler implements ErrorHandler {
private Collection<SAXParseException> exceptions;
public XmlErrorHandler() {
this.exceptions = new ArrayList<>();
}
public Collection<SAXParseException> getExceptions() {
return exceptions;
}
@Override
public void warning(SAXParseException exception) {
exceptions.add(exception);
}
@Override
public void error(SAXParseException exception) {
exceptions.add(exception);
}
@Override
public void fatalError(SAXParseException exception) {
exceptions.add(exception);
}
}
}
I tried debugging the issue, unfortunately it didn't shed any light in figuring out the cause. What is missing here? Any help would be appreciated. Thanks.
[1] XSD - how to allow elements in any order any number of times?
Upvotes: 1
Views: 118
Reputation: 163458
The minOccurs
and maxOccurs
attribute should not be in the vc
namespace.
By placing minOccurs
and maxOccurs
in the "http://www.w3.org/2007/XMLSchema-versioning"
namespace, the real minOccurs
and maxOccurs
are absent. Thus, the default values of 1
come into play, explaining the observed validation error message.
Upvotes: 2