How to Validate an Xml File Using Java with an Xsd Having an Include

How to validate an XML file using Java with an XSD having an include?

you need to use an LSResourceResolver for this to work. please take a look at the sample code below.

a validate method:

// note that if your XML already declares the XSD to which it has to conform, then there's no need to declare the schemaName here
void validate(String xml, String schemaName) throws Exception {

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);

DocumentBuilder parser = builderFactory
.newDocumentBuilder();

// parse the XML into a document object
Document document = parser.parse(new StringInputStream(xml));

SchemaFactory factory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

// associate the schema factory with the resource resolver, which is responsible for resolving the imported XSD's
factory.setResourceResolver(new ResourceResolver());

// note that if your XML already declares the XSD to which it has to conform, then there's no need to create a validator from a Schema object
Source schemaFile = new StreamSource(getClass().getClassLoader()
.getResourceAsStream(schemaName));
Schema schema = factory.newSchema(schemaFile);

Validator validator = schema.newValidator();
validator.validate(new DOMSource(document));
}

the resource resolver implementation:

public class ResourceResolver  implements LSResourceResolver {

public LSInput resolveResource(String type, String namespaceURI,
String publicId, String systemId, String baseURI) {

// note: in this sample, the XSD's are expected to be in the root of the classpath
InputStream resourceAsStream = this.getClass().getClassLoader()
.getResourceAsStream(systemId);
return new Input(publicId, systemId, resourceAsStream);
}

}

The Input implemetation returned by the resource resolver:

public class Input implements LSInput {

private String publicId;

private String systemId;

public String getPublicId() {
return publicId;
}

public void setPublicId(String publicId) {
this.publicId = publicId;
}

public String getBaseURI() {
return null;
}

public InputStream getByteStream() {
return null;
}

public boolean getCertifiedText() {
return false;
}

public Reader getCharacterStream() {
return null;
}

public String getEncoding() {
return null;
}

public String getStringData() {
synchronized (inputStream) {
try {
byte[] input = new byte[inputStream.available()];
inputStream.read(input);
String contents = new String(input);
return contents;
} catch (IOException e) {
e.printStackTrace();
System.out.println("Exception " + e);
return null;
}
}
}

public void setBaseURI(String baseURI) {
}

public void setByteStream(InputStream byteStream) {
}

public void setCertifiedText(boolean certifiedText) {
}

public void setCharacterStream(Reader characterStream) {
}

public void setEncoding(String encoding) {
}

public void setStringData(String stringData) {
}

public String getSystemId() {
return systemId;
}

public void setSystemId(String systemId) {
this.systemId = systemId;
}

public BufferedInputStream getInputStream() {
return inputStream;
}

public void setInputStream(BufferedInputStream inputStream) {
this.inputStream = inputStream;
}

private BufferedInputStream inputStream;

public Input(String publicId, String sysId, InputStream input) {
this.publicId = publicId;
this.systemId = sysId;
this.inputStream = new BufferedInputStream(input);
}
}

Java: string xml validation against xsd that include another xsd

Finally i found a solution. Thestandard method does not resolve included or imported files from the start. To resolve the included files i used the LSResourceResolver.

This works for me:

@Service
public class ResourceResolverImpl implements LSResourceResolver {
private ILoadFromSRService iLoadFromSRService;

@Autowired
public ResourceResolverImpl(ILoadFromSRService iLoadFromSRService){
this.iLoadFromSRService = iLoadFromSRService;
}

public LSInput resolveResource(String type,
String namespaceURI,
String publicId,
String systemId,
String baseURI) {
String string =iLoadFromSRService.getServiceBaseTypeSchema();
string = string.replace("\n", "").replace("\t", "");
InputStream resourceAsStream = new ByteArrayInputStream( string.getBytes());
return new LSInputImpl(publicId, systemId, resourceAsStream);
}
}

How to validate an XML file against an XSD file?

The Java runtime library supports validation. Last time I checked this was the Apache Xerces parser under the covers. You should probably use a 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) {}

The schema factory constant is the string http://www.w3.org/2001/XMLSchema which defines XSDs. The above code validates a WAR deployment descriptor against the URL http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd but you could just as easily validate against a local file.

You should not use the DOMParser to validate a document (unless your goal is to create a document object model anyway). This will start creating DOM objects as it parses the document - wasteful if you aren't going to use them.

Validating xml against an xsd which has an include

You are experiencing a case problem. 'true' is a valid value for xsd:boolean, but 'True' (which is apparently what is in the XML document) is not.

The responses here (xsd:boolean element type accept "true" but not "True". How can I make it accept it?) provide some additional information and a possible alternate solution based on enumerated values (if you cannot change the True to true).

XML validation against XSD with javax.xml.validation.Validator: cannot resolve types come from 2nd XSD

I suspect that when the schema document is loaded using getResourceAsStream("schema/my.xsd"); it doesn't have a known base URI and therefore the relative URI xmldsig-core-schema.xsd doesn't resolve properly. Try setting a base URI (systemId property) on your StreamSource object.

How do I validate an XML with a schema file that imports another schema file?

Have a look at the accepted answer for this post. Based on the little I can see in your post, and from what I can remember, the problem with the way you're loading the XSD has to do with the fact that doing it your way, the factory doesn't get a base uri, hence it can't apply its smarts to resolve references to the other two XSDs. I have to assume that your other two XSDs are also packed as resources in the same jar, in the same directory.

I have to admit that I am intrigued by the error message, which seems to imply the schema it loaded is valid, so it might be an XML issue; if the above doesn't help you, then you should consider posting the offending XML as well...

UPDATE: As per my comments, it is working as described. See code snippet below:

SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema compiledSchema = schemaFactory.newSchema(new SOTests().getClass()
.getClassLoader().getResource("generalInvoiceRequest_430.xsd"));
Validator validator = compiledSchema.newValidator();
try {
validator.validate(new StreamSource("D:\\...\\dentist_ersred_TG_430.xml"));
System.out.println("Valid.");
}
catch (SAXException ex) {
System.out.print("Not valid because..." + ex.getMessage());
}

You don't need to load more than the first XSD, and you shouldn't, since all the imports provide hints to the schema location.

Sample Image

The XSD files are all in the same directory in the generated jar, and they must be, since the relative URIs used for imports indicate same parent.

Sample Image

The program output with one of the files downloaded from here:

Valid.

And after introducing invalid content:

Not valid because...cvc-complex-type.2.4.a: Invalid content was found starting with element 'wrong'. One of '{"http://www.forum-datenaustausch.ch/invoice":processing}' is expected.

My recommendations to who reads this:

  • use getResource() to get an URL; as I've said above, a StreamResource doesn't have a base URI, hence relative references as per your xsd:import schemaLocation attribute cannot be de-referenced.
  • Let the schema/factory do the loading for you, when they're explicitly provided.
  • make sure that when provided, relative references match the folder structure in your jar file.

Java XSD validation depends on order XSDs are provided

Javadoc of newSchema(Source[] schemas):

parsers may choose to ignore all but the first <import> for a given namespace

Read the full description in the javadoc for more context information.

So only the first file listed is used.

Since a.xsd has an <xs:include> for b.xsd, they both get loaded when a.xsd is first.

If b.xsd is first, then only b.xsd is loaded, which means that <xs:element name="TestMessage"> is missing, and hence the error.

XML String Validation with two XSD Strings (with include) / how does LSResourceResolver work?

Finally i found a solution.

This works for me:

@Service
public class ResourceResolverImpl implements LSResourceResolver {
private ILoadFromSRService iLoadFromSRService;

@Autowired
public ResourceResolverImpl(ILoadFromSRService iLoadFromSRService){
this.iLoadFromSRService = iLoadFromSRService;
}

public LSInput resolveResource(String type,
String namespaceURI,
String publicId,
String systemId,
String baseURI) {
String string =iLoadFromSRService.getServiceBaseTypeSchema();
string = string.replace("\n", "").replace("\t", "");
InputStream resourceAsStream = new ByteArrayInputStream( string.getBytes());
return new LSInputImpl(publicId, systemId, resourceAsStream);
}
}


Related Topics



Leave a reply



Submit