Source files
Source files include the catalog manager properties file, Java source code, catalog file, XML data, XSL files, and XSD files. All files are in the current working directory ( ./ ).
Directory Manager Properties File
This property file is read by the CatalogResolver class; save as ./CatalogManager.properties :
catalogs=catalog.xml relative-catalogs=yes verbosity=99 prefer=system static-catalog=yes allow-oasis-xml-catalog-pi=yes
TestXSD.java
This is the main application; save it as ./src/TestXSD.java :
package src; import java.io.*; import java.net.URI; import java.util.*; import java.util.regex.Pattern; import java.util.regex.Matcher; import javax.xml.parsers.*; import javax.xml.xpath.*; import javax.xml.XMLConstants; import org.w3c.dom.*; import org.xml.sax.*; import org.apache.xml.resolver.tools.CatalogResolver; import org.apache.xerces.util.XMLCatalogResolver; import static org.apache.xerces.jaxp.JAXPConstants.JAXP_SCHEMA_LANGUAGE; import static org.apache.xerces.jaxp.JAXPConstants.W3C_XML_SCHEMA; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Schema; import javax.xml.validation.Validator; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; public class TestXSD { private final static String ENTITY_RESOLVER = "http://apache.org/xml/properties/internal/entity-resolver"; public static void main( String args[] ) throws Exception {
Error handler
This is code for user-friendly error messages; save as ./src/DocumentErrorHandler.java :
package src; import java.io.PrintStream; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXParseException; import org.xml.sax.SAXException; public class DocumentErrorHandler implements ErrorHandler { private final static PrintStream OUTSTREAM = System.err; private void log( String type, SAXParseException e ) { OUTSTREAM.println( "SAX PARSE EXCEPTION " + type ); OUTSTREAM.println( " Public ID: " + e.getPublicId() ); OUTSTREAM.println( " System ID: " + e.getSystemId() ); OUTSTREAM.println( " Line : " + e.getLineNumber() ); OUTSTREAM.println( " Column : " + e.getColumnNumber() ); OUTSTREAM.println( " Message : " + e.getMessage() ); } @Override public void error( SAXParseException e ) throws SAXException { log( "ERROR", e ); } @Override public void fatalError( SAXParseException e ) throws SAXException { log( "FATAL ERROR", e ); } @Override public void warning( SAXParseException e ) throws SAXException { log( "WARNING", e ); } }
Catalog file
Save as ./catalog.xml :
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE catalog PUBLIC "-//OASIS//DTD XML Catalogs V1.1//EN" "http://www.oasis-open.org/committees/entity/release/1.1/catalog.dtd"> <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"> <rewriteSystem systemIdStartString="http://stackoverflow.com/schema" rewritePrefix="./ArbitraryFolder/schemas" /> <rewriteURI uriStartString="http://stackoverflow.com/2014/09/xsd" rewritePrefix="./ArbitraryFolder/schemas" /> <nextCatalog catalog="./ArbitraryFolder/catalog.xml" /> </catalog>
XML data
Various test cases include the XSD indicated in the processing instructions or root nodes.
Scheme: processing instruction
A schema can be provided using the xml-model (PI) processing instruction. Save as ./Tests/good-notes2.xml :
<?xml version="1.0" encoding="UTF-8"?> <?xml-model type="application/xml" href="http://stackoverflow.com/2014/09/xsd/notes/notes.xsd"?> <note> <title>Shopping List</title> <date>2014-08-30</date> <body>headlight fluid, flamgrabblit, exhaust coil</body> </note>
Schematic: Node Root
The schema can be provided in the root attributes of the document node. Save as ./Tests/good-notes3.xml :
<?xml version="1.0" encoding="UTF-8"?> <note xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://stackoverflow.com http://stackoverflow.com/2014/09/xsd/notes/notes.xsd"> <title>Shopping List</title> <date>2014-08-30</date> <body>Eggs, Milk, Carrots</body> </note>
Failure Check
The following should fail (hyphens need dates); save as ./Tests/bad-note1.xml :
<?xml version="1.0" encoding="UTF-8"?> <?xml-model type="application/xml" href="http://stackoverflow.com/2014/09/xsd/notes/notes.xsd"?> <note> <title>Shopping List</title> <date>20140830</date> <body>headlight fluid, flamgrabblit, exhaust coil</body> </note>
Conversion
Save this as ./Tests/note-to-html.xsl :
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0"> <xsl:import href="http://stackoverflow.com/2014/09/xsl/notes/notes.xsl"/> </xsl:stylesheet>
Custom folder
Any folder is a path to files on a computer that can be located anywhere in the file system. The location of these files may differ, for example, between production, development, and storage.
Catalog
Save this file as ./ArbitraryFolder/catalog.xml :
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE catalog PUBLIC "-//OASIS//DTD XML Catalogs V1.1//EN" "http://www.oasis-open.org/committees/entity/release/1.1/catalog.dtd"> <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"> <rewriteURI uriStartString="http://stackoverflow.com/2014/09/xsl/" rewritePrefix="./XSL/"/> </catalog>
Notes
In this example, there are two files for converting notes: notes.xsl and note-body.xsl. The first includes the second.
Note Style Sheet
Save this as ./ArbitraryFolder/XSL/notes/notes.xsl :
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0"> <xsl:import href="note-body.xsl"/> <xsl:template match="/"> <html> <head> <title>A Note</title> </head> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:template match="note"> <div> <xsl:apply-templates select="title, date, body"/> </div> </xsl:template> <xsl:template match="title"> <h1><xsl:value-of select="."/></h1> </xsl:template> <xsl:template match="date"> <p class="date"><xsl:value-of select="."/></p> </xsl:template> </xsl:stylesheet>
Note. Body style sheet
Save this as ./ArbitraryFolder/XSL/notes/note-body.xsl :
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0"> <xsl:template match="body"> <p class="notebody"><xsl:value-of select="."/></p> </xsl:template> </xsl:stylesheet>
Scheme
The last required file is a schema; save this as ./schemas/notes/notes.xsd :
<?xml version="1.0" encoding="UTF-8"?> <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="note"> <xs:complexType> <xs:sequence> <xs:element name="title" type="xs:token"/> <xs:element name="date" type="xs:date"/> <xs:element name="body" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
Building
This section describes how to create a test application.
Libraries
You will need Saxon 9 (for XSLT2.0 documents), Xerces, Xalan, and the API Resolver:
jaxen-1.1.6.jar resolver.jar saxon9he.jar serializer.jar xalan.jar xercesImpl.jar xml-apis.jar xsltc.jar
Scenarios
Save as ./build.sh :
Save as ./run.sh :
#!/bin/bash java -cp .:bin:lib/* src.TestXSD Tests/note-to-html.xsl $1
Compile
Use ./build.sh to compile the code.
Execute output
Run using:
./run.sh filename.xml
Good test
Verify that a good note is being tested:
./run.sh Tests/good-note2.xml
No mistakes.
Bad test
Verify that the date of the bad note is not validating:
./run.sh Tests/bad-note1.xml
As expected, this causes the desired error:
Exception in thread "main" org.xml.sax.SAXParseException; cvc-datatype-valid.1.2.1: '20140830' is not a valid value for 'date'. at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source) at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) at org.apache.xerces.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source) at org.apache.xerces.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source) at org.apache.xerces.impl.xs.XMLSchemaValidator.elementLocallyValidType(Unknown Source) at org.apache.xerces.impl.xs.XMLSchemaValidator.processElementContent(Unknown Source) at org.apache.xerces.impl.xs.XMLSchemaValidator.handleEndElement(Unknown Source) at org.apache.xerces.impl.xs.XMLSchemaValidator.endElement(Unknown Source) at org.apache.xerces.jaxp.validation.DOMValidatorHelper.finishNode(Unknown Source) at org.apache.xerces.jaxp.validation.DOMValidatorHelper.validate(Unknown Source) at org.apache.xerces.jaxp.validation.DOMValidatorHelper.validate(Unknown Source) at org.apache.xerces.jaxp.validation.ValidatorImpl.validate(Unknown Source) at javax.xml.validation.Validator.validate(Validator.java:124) at src.TestXSD.main(TestXSD.java:103)