"Package with uri 'null' not found" while loading XML file using EMF - java

I am trying to load an XML file using EMF and I am using the following code to do that in XMLArtefactAdapter.java:
constructor():
ResourceSet set = new ResourceSetImpl();
//registering factory
set.getResourceFactoryRegistry()
.getExtensionToFactoryMap()
.put
(Resource.Factory.Registry.DEFAULT_EXTENSION,new XMLResourceFactoryImpl());
parse() method:
//parsing XML
try {
String absolutePath = file.getAbsolutePath();
URI uri = URI.createFileURI(absolutePath);
Resource resource = resourceSet.createResource(uri);
resource.load(Collections.EMPTY_MAP);
System.out.println("LOADED");
} catch (IOException e) {
System.out.println(e.toString());
}
I am executing this code fragment from my Main class:
Path path = Paths.get("C:\\Users\\Srijani\\Desktop\\book.xml");
XMLArtefactAdapter xmlAdapter = new XMLArtefactAdapter(path);
xmlAdapter.parse();
But, I get error while running this code.
org.eclipse.emf.ecore.resource.Resource$IOWrappedException: Package with uri 'null' not found. (file:/C:/Users/Srijani/Desktop/plugin.xml, 3, 9)
Please note the following:
My Plugin.xml
<plugin>
<extension point="org.eclipse.emf.ecore.generated_package">
<!-- #generated simpletree -->
<package
uri="platform:/plugin/com.kaleidoscope.core.aux.simpletree/model/SimpleTree.ecore"
class="SimpleTree.SimpletreePackage"
genModel="model/simpletree.genmodel"/>
</extension>
</plugin>
Any idea why this is happening?
Thanks in Advance!

An EPackage uri is a kind of public identifier for your EPackage. It should not be an eclipse uri.
Usually, the namespace URI is an http url providing some basic informations about the EPackage provider, ePackage name and version.
eg :
<extension point="org.eclipse.emf.ecore.generated_package">
<package
uri="http://www.eclipse.org/emf/2002/Ecore"
class="org.eclipse.emf.ecore.EcorePackage"
genModel="model/Ecore.genmodel"/>
</extension>
You should :
change your EPackage nsUri with an identifier for your EPackage,
regenerate the EMF code,
and merge your plugin.xml and plugin.xml_gen files to synchronize your nsURI value.

Related

Adding a catalog to XSLT Saxon s9api in Java

I have the following code which takes XML as input and produces a bunch of other files as output.
public void transformXml(InputStream inputFileStream, Path outputDir) {
try {
Resource resource = resourceLoader
.getResource("classpath:demo.xslt");
LOGGER.info("Creating output XMLs and Assessment Report in {}", outputDir);
final File outputFile = new File(outputDir.toString());
final Processor processor = getSaxonProcessor();
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable stylesheet = compiler.compile(new StreamSource(resource.getFile()));
Xslt30Transformer transformer = stylesheet.load30();
Serializer out = processor.newSerializer(outputFile);
out.setOutputProperty(Serializer.Property.METHOD, "xml");
transformer.transform(new StreamSource(inputFileStream), out);
LOGGER.debug("Generated DTD XMLs and Assessment Report successfully in {}", outputDir);
} catch (SaxonApiException e) {
throw new XmlTransformationException("Error occured during transformation", e);
} catch (IOException e) {
throw new XmlTransformationException("Error occured during loading XSLT file", e);
}
}
private Processor getSaxonProcessor() {
final Configuration configuration = Configuration.newConfiguration();
configuration.disableLicensing();
Processor processor = new Processor(configuration);
return processor;
}
The XML input contains a DOCTYPE tag which resolves to a DTD that is not available to me. Hence why I am wanting to use a catalog to point it to a dummy DTD which is on my classpath.
I am struggling to find a way to this. Most examples that I find out there, are not using the s9api implementation. Any ideas?
Instead of
new StreamSource(inputFileStream)
you should instantiate a SAXSource, containing an XMLReader initialized to use the catalog resolver as its EntityResolver.
If you need to do the same thing for other source documents, such as those read using doc() or document(), you should supply a URIResolver which itself returns a SAXSource initialized in the same way.
There are other ways of doing it using Saxon configuration properties, but I think the above is the simplest.

Java load local xsd file in <import namespace> [duplicate]

This question already has answers here:
XML validation failing in java with schemaLocation a local file
(2 answers)
Closed 2 years ago.
I try to load my local xsd file (import...schemaLocation="gml.xsd" but it seems nothing working because I got always same error :
org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 122; src-resolve: Cannot resolve the name 'gml:AbstractFeature' to a(n) 'element declaration' component.
config.xsd :
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:pcrs="http://cnig.gouv.fr/pcrs" xmlns:pcrs-i="http://cnig.gouv.fr/pcrs-information" targetNamespace="http://cnig.gouv.fr/pcrs" elementFormDefault="qualified" version="2.0beta2">
<import namespace="http://cnig.gouv.fr/pcrs-information" schemaLocation="CNIG_PCRS-INFO_v2.0.xsd"/>
<import namespace="http://www.opengis.net/gml/3.2" schemaLocation="gml.xsd"/>
<!--XML Schema document created by ShapeChange - http://shapechange.net/-->
<element name="AffleurantEnveloppePCRS" type="pcrs:AffleurantEnveloppePCRSType" substitutionGroup="gml:AbstractFeature">
java :
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream xsd = classloader.getResourceAsStream("gml/config.xsd");
InputStream gml = classloader.getResourceAsStream("gml/test.gml");
public boolean validateXSD() {
try {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new StreamSource(xsd));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(gml));
return true;
} catch (Exception error) {
System.out.println(error);
return false;
}
}
Since you're supplying a byte stream, the XML library has no idea where the file is located, so it cannot resolved relative paths.
As a fall-back, it likely resolved the relative paths relative to the current directory, but since the files are not there, they are not found.
Specify the XSD as a URI.
public boolean validateXSD() {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
URL xsd = classloader.getResource("gml/config.xsd");
URL gml = classloader.getResource("gml/test.gml");
try {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(xsd); // Pass URL to XML library
Validator validator = schema.newValidator();
validator.validate(new StreamSource(gml.toString())); // Pass URL as a string
return true;
} catch (Exception error) {
System.out.println(error);
return false;
}
}
Advantage: You don't have to remember to close the streams, which you seemed to have forgot.

Implementation of JAXB-API has not been found on module path or classpath

I am using JAXB to convert between classes and XML and save and read to an XML document. I am working in Eclipse Oxygen.1a Release (4.7.1a) and I have included the jaxb-api-2.3.0.jar file to the project from here: https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api/2.3.0 It looks like my implementation of the JAXB-API in Eclipse has not been done correctly. I am not sure how to do that. I just included the jar file hoping it will work.
Now my code throws an expectation Implementation of JAXB-API has not been found on module path or classpath.
/**
* Saves the current person data to the specified file.
*
* #param file
*/
public void savePersonDataToFile(File file) {
try {
JAXBContext context = JAXBContext
.newInstance(PersonListWrapper.class);
Marshaller m = (Marshaller) context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
// Wrapping our person data.
PersonListWrapper wrapper = new PersonListWrapper();
wrapper.setPersons(personData);
// Marshalling and saving XML to the file.
((Marshaller) m).marshal(wrapper, file);
// Save the file path to the registry.
setPersonFilePath(file);
} catch (Exception e) { // catches ANY exception
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText("Could not save data");
//alert.setContentText("Could not save data to file:\n" + file.getPath());
alert.setContentText(e.getMessage());
alert.showAndWait();
}
}
I must be missing configurations.

Liquibase execution order of changeset files when using includeAll with classpath*:

I am using liquibase (3.1.1) in a spring environment (3.2.x) and load the changesets via the inlcudeAll tag in a master file. There I use the "classpath*:/package/to/changesets" as path.
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<includeAll path="classpath*:/package/to/changesets"/>...
I use a naming strategy like "nnn_changesetname.xml" to keep ordering. But when I look into the changeset table this ordering via the filenames are not kept. Is this only working, if the changeset files are contained in a directory and not on the classpath?
Update
Hi, I found out that the below suggested solution is not enough. I think it lies in the implementation how liquibase resolves the includAll attribute. In my case it first resolves all "folders" and then looks into each folder for changeset xmls. This will break the ordering of the xml files in all classpath*:/changes locations, because there are now several "changes" folders in different locations. What I would suspect in such a case is a merge of all contents of this "virtual" classpath folders and loading of all resources in one enumeration. Or we could allow some resouce pattern in the inlcudeAll tag like resources="classpath*:/changes/*.xml" to directly select all needed files (tried it out with the path attribute, but did not work, because it checks for a folder)?
Update
I made a hack to check if the ordering in the returned enumeration is preserved with the anwser from below. To achive this I checked for the given package name and if it matches my pattern I added an additional "*.xml" to it. With this extension I get all changeset as needed.
#Override
public Enumeration<URL> getResources(String packageName)
throws IOException {
if(packageName.equals("classpath*:/plugin/liquibase/changes/")) {
packageName = packageName + "*.xml";
}
List<URL> resources = Collections.list(super.getResources(packageName));
Collections.sort(resources, new Comparator<URL>() {
#Override
public int compare(URL url1, URL url2) {
String path1 = FilenameUtils.getName(url1.getPath());
String path2 = FilenameUtils.getName(url2.getPath());
return String.CASE_INSENSITIVE_ORDER.compare(path1, path2);
}
});
logger.info("Found resources: {}", resources);
return Collections.enumeration(resources);
}};
In the log I can see now that the resources have the correct order. But when I look into the table DATABASECHANGELOCK it does not reflect the order I had in the enumeration. So it seems that this values get reodered somewhere else.
Update
Analyzed the code furhter and found out that the class liquibase.parser.core.xml.XMLChangeLogSAXHandler makes a reordering of the returned enumeration. So my changes will have no effect. I do not think that I can hack into this class as well.
You are right, Liquibase is relying on the underlying "list files" logic which orders files alphabetically through the file system but apparently does not through classpaths.
I created https://liquibase.jira.com/browse/CORE-1843 to track the fix.
For now, if you configure spring with a subclass of liquibase.integration.spring.SpringLiquibase that overrides getResources(String packageName) with a method that sorts the returned Enumeration that should resolve the problem for you.
So after some thinking and one night of sleep I came up with the following hack to guarantee order of the loaded changelog files via classpath pattern classpath*:/my/path/to/changelog/*.xml . The idea is to create the main changelog file on the fly via dom manipulation, when liquibase requests it.
It only works for the main changelog file. Following prerequisite:
The pattern can only be used for the main changelog file
I use an empty master changelog file as template
All other changelog files have to use the normal allowed loading mechanism
Works only in an Spring environment
First I had to extend/overwrite the liquibase.integration.spring.SpringLiquibase with my implementation.
public class MySpringLiquibase extends SpringLiquibase {
private static final Logger logger = LoggerFactory.getLogger(MySpringLiquibase.class);
private ApplicationContext context;
private String changeLogLocationPattern;
private List<String> changeLogLocations;
#Autowired
public void setContext(ApplicationContext context) {
this.context = context;
}
/**
* Location pattern to search for changelog files.
*
* #param changeLogLocationPattern
*/
public void setChangeLogLocationPattern(String changeLogLocationPattern) {
this.changeLogLocationPattern = changeLogLocationPattern;
}
#Override
public void afterPropertiesSet() throws LiquibaseException {
try {
changeLogLocations = new ArrayList<String>();
// retrieve all changelog resources for the pattern
List<Resource> changeLogResources = Arrays.asList(context.getResources(changeLogLocationPattern));
for (Resource changeLogResource : changeLogResources) {
// get only the classpath path of the resource
String changeLogLocation = changeLogResource.getURL().getPath();
changeLogLocation = "classpath:" + StringUtils.substringAfterLast(changeLogLocation, "!");
changeLogLocations.add(changeLogLocation);
}
// sort all found resources by string
Collections.sort(changeLogLocations, String.CASE_INSENSITIVE_ORDER);
} catch (IOException e) {
throw new LiquibaseException("Could not resolve changeLogLocationPattern", e);
}
super.afterPropertiesSet();
}
#Override
protected SpringResourceOpener createResourceOpener() {
final String mainChangeLog = getChangeLog();
return new SpringResourceOpener(getChangeLog()) {
#Override
public InputStream getResourceAsStream(String file)
throws IOException {
// check if main changelog file
if(mainChangeLog.equals(file)) {
// load master template and convert to dom object
Resource masterResource = getResourceLoader().getResource(file);
Document masterDocument = DomUtils.parse(masterResource, true);
// add all changelog locations as include elements
for (String changeLogLocation : changeLogLocations) {
Element inlcudeElement = masterDocument.createElement("include");
inlcudeElement.setAttribute("file", changeLogLocation);
masterDocument.getDocumentElement().appendChild(inlcudeElement);
}
if(logger.isDebugEnabled()) {
logger.debug("Master changeset: {}", DomUtils.toString(masterDocument));
}
// convert dom back to string and give it back as input resource
return new ByteArrayInputStream(DomUtils.toBytes(masterDocument));
} else {
return super.getResourceAsStream(file);
}
}
};
}
}
This class now needs to be used in the spring xml configuration.
<bean id="liquibase" class="liquibase.integration.spring.MySpringLiquibase"
p:changeLog="classpath:/plugin/liquibase/master.xml"
p:dataSource-ref="dataSource"
p:contexts="${liquibase.contexts:prod}"
p:ignoreClasspathPrefix="true"
p:changeLogLocationPattern="classpath*:/plugin/liquibase/changes/*.xml"/>
With this changes I have achieved that my main changelog files are ordered by their name.
Hope that helps others too.

How to validate an XML file against an XSD file?

I'm generating some xml files that needs to conform to an xsd file that was given to me. How should I verify they conform?
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.
Here's how to do it using Xerces2. A tutorial for this, here (req. signup).
Original attribution: blatantly copied from here:
import org.apache.xerces.parsers.DOMParser;
import java.io.File;
import org.w3c.dom.Document;
public class SchemaTest {
public static void main (String args[]) {
File docFile = new File("memory.xml");
try {
DOMParser parser = new DOMParser();
parser.setFeature("http://xml.org/sax/features/validation", true);
parser.setProperty(
"http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
"memory.xsd");
ErrorChecker errors = new ErrorChecker();
parser.setErrorHandler(errors);
parser.parse("memory.xml");
} catch (Exception e) {
System.out.print("Problem parsing the file.");
}
}
}
We build our project using ant, so we can use the schemavalidate task to check our config files:
<schemavalidate>
<fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>
Now naughty config files will fail our build!
http://ant.apache.org/manual/Tasks/schemavalidate.html
Since this is a popular question, I will point out that java can also validate against "referred to" xsd's, for instance if the .xml file itself specifies XSD's in the header, using xsi:schemaLocation or xsi:noNamespaceSchemaLocation (or xsi for particular namespaces) ex:
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
...
or schemaLocation (always a list of namespace to xsd mappings)
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.com/my_namespace http://www.example.com/document.xsd">
...
The other answers work here as well, because the .xsd files "map" to the namespaces declared in the .xml file, because they declare a namespace, and if matches up with the namespace in the .xml file, you're good. But sometimes it's convenient to be able to have a custom resolver...
From the javadocs: "If you create a schema without specifying a URL, file, or source, then the Java language creates one that looks in the document being validated to find the schema it should use. For example:"
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
and this works for multiple namespaces, etc.
The problem with this approach is that the xmlsns:xsi is probably a network location, so it'll by default go out and hit the network with each and every validation, not always optimal.
Here's an example that validates an XML file against any XSD's it references (even if it has to pull them from the network):
public static void verifyValidatesInternalXsd(String filename) throws Exception {
InputStream xmlStream = new new FileInputStream(filename);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(true);
factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new RaiseOnErrorHandler());
builder.parse(new InputSource(xmlStream));
xmlStream.close();
}
public static class RaiseOnErrorHandler implements ErrorHandler {
public void warning(SAXParseException e) throws SAXException {
throw new RuntimeException(e);
}
public void error(SAXParseException e) throws SAXException {
throw new RuntimeException(e);
}
public void fatalError(SAXParseException e) throws SAXException {
throw new RuntimeException(e);
}
}
You can avoid pulling referenced XSD's from the network, even though the xml files reference url's, by specifying the xsd manually (see some other answers here) or by using an "XML catalog" style resolver. Spring apparently also can intercept the URL requests to serve local files for validations. Or you can set your own via setResourceResolver, ex:
Source xmlFile = new StreamSource(xmlFileLocation);
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema();
Validator validator = schema.newValidator();
validator.setResourceResolver(new LSResourceResolver() {
#Override
public LSInput resolveResource(String type, String namespaceURI,
String publicId, String systemId, String baseURI) {
InputSource is = new InputSource(
getClass().getResourceAsStream(
"some_local_file_in_the_jar.xsd"));
// or lookup by URI, etc...
return new Input(is); // for class Input see
// https://stackoverflow.com/a/2342859/32453
}
});
validator.validate(xmlFile);
See also here for another tutorial.
I believe the default is to use DOM parsing, you can do something similar with SAX parser that is validating as well saxReader.setEntityResolver(your_resolver_here);
Using Java 7 you can follow the documentation provided in package description.
// create a SchemaFactory capable of understanding WXS schemas
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// load a WXS schema, represented by a Schema instance
Source schemaFile = new StreamSource(new File("mySchema.xsd"));
Schema schema = factory.newSchema(schemaFile);
// create a Validator instance, which can be used to validate an instance document
Validator validator = schema.newValidator();
// validate the DOM tree
try {
validator.validate(new StreamSource(new File("instance.xml"));
} catch (SAXException e) {
// instance document is invalid!
}
If you have a Linux-Machine you could use the free command-line tool SAXCount. I found this very usefull.
SAXCount -f -s -n my.xml
It validates against dtd and xsd.
5s for a 50MB file.
In debian squeeze it is located in the package "libxerces-c-samples".
The definition of the dtd and xsd has to be in the xml! You can't config them separately.
With JAXB, you could use the code below:
#Test
public void testCheckXmlIsValidAgainstSchema() {
logger.info("Validating an XML file against the latest schema...");
MyValidationEventCollector vec = new MyValidationEventCollector();
validateXmlAgainstSchema(vec, inputXmlFileName, inputXmlSchemaName, inputXmlRootClass);
assertThat(vec.getValidationErrors().isEmpty(), is(expectedValidationResult));
}
private void validateXmlAgainstSchema(final MyValidationEventCollector vec, final String xmlFileName, final String xsdSchemaName, final Class<?> rootClass) {
try (InputStream xmlFileIs = Thread.currentThread().getContextClassLoader().getResourceAsStream(xmlFileName);) {
final JAXBContext jContext = JAXBContext.newInstance(rootClass);
// Unmarshal the data from InputStream
final Unmarshaller unmarshaller = jContext.createUnmarshaller();
final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
final InputStream schemaAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(xsdSchemaName);
unmarshaller.setSchema(sf.newSchema(new StreamSource(schemaAsStream)));
unmarshaller.setEventHandler(vec);
unmarshaller.unmarshal(new StreamSource(xmlFileIs), rootClass).getValue(); // The Document class is the root object in the XML file you want to validate
for (String validationError : vec.getValidationErrors()) {
logger.trace(validationError);
}
} catch (final Exception e) {
logger.error("The validation of the XML file " + xmlFileName + " failed: ", e);
}
}
class MyValidationEventCollector implements ValidationEventHandler {
private final List<String> validationErrors;
public MyValidationEventCollector() {
validationErrors = new ArrayList<>();
}
public List<String> getValidationErrors() {
return Collections.unmodifiableList(validationErrors);
}
#Override
public boolean handleEvent(final ValidationEvent event) {
String pattern = "line {0}, column {1}, error message {2}";
String errorMessage = MessageFormat.format(pattern, event.getLocator().getLineNumber(), event.getLocator().getColumnNumber(),
event.getMessage());
if (event.getSeverity() == ValidationEvent.FATAL_ERROR) {
validationErrors.add(errorMessage);
}
return true; // you collect the validation errors in a List and handle them later
}
}
One more answer: since you said you need to validate files you are generating (writing), you might want to validate content while you are writing, instead of first writing, then reading back for validation. You can probably do that with JDK API for Xml validation, if you use SAX-based writer: if so, just link in validator by calling 'Validator.validate(source, result)', where source comes from your writer, and result is where output needs to go.
Alternatively if you use Stax for writing content (or a library that uses or can use stax), Woodstox can also directly support validation when using XMLStreamWriter. Here's a blog entry showing how that is done:
If you are generating XML files programatically, you may want to look at the XMLBeans library. Using a command line tool, XMLBeans will automatically generate and package up a set of Java objects based on an XSD. You can then use these objects to build an XML document based on this schema.
It has built-in support for schema validation, and can convert Java objects to an XML document and vice-versa.
Castor and JAXB are other Java libraries that serve a similar purpose to XMLBeans.
Using Woodstox, configure the StAX parser to validate against your schema and parse the XML.
If exceptions are caught the XML is not valid, otherwise it is valid:
// create the XSD schema from your schema file
XMLValidationSchemaFactory schemaFactory = XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA);
XMLValidationSchema validationSchema = schemaFactory.createSchema(schemaInputStream);
// create the XML reader for your XML file
WstxInputFactory inputFactory = new WstxInputFactory();
XMLStreamReader2 xmlReader = (XMLStreamReader2) inputFactory.createXMLStreamReader(xmlInputStream);
try {
// configure the reader to validate against the schema
xmlReader.validateAgainst(validationSchema);
// parse the XML
while (xmlReader.hasNext()) {
xmlReader.next();
}
// no exceptions, the XML is valid
} catch (XMLStreamException e) {
// exceptions, the XML is not valid
} finally {
xmlReader.close();
}
Note: If you need to validate multiple files, you should try to reuse your XMLInputFactory and XMLValidationSchema in order to maximize the performance.
Are you looking for a tool or a library?
As far as libraries goes, pretty much the de-facto standard is Xerces2 which has both C++ and Java versions.
Be fore warned though, it is a heavy weight solution. But then again, validating XML against XSD files is a rather heavy weight problem.
As for a tool to do this for you, XMLFox seems to be a decent freeware solution, but not having used it personally I can't say for sure.
Validate against online schemas
Source xmlFile = new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream("your.xml"));
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(Thread.currentThread().getContextClassLoader().getResource("your.xsd"));
Validator validator = schema.newValidator();
validator.validate(xmlFile);
Validate against local schemas
Offline XML Validation with Java
I had to validate an XML against XSD just one time, so I tried XMLFox. I found it to be very confusing and weird. The help instructions didn't seem to match the interface.
I ended up using LiquidXML Studio 2008 (v6) which was much easier to use and more immediately familiar (the UI is very similar to Visual Basic 2008 Express, which I use frequently). The drawback: the validation capability is not in the free version, so I had to use the 30 day trial.

Categories

Resources