The Source for Java Technology Collaboration
User: Password:



Kohsuke Kawaguchi

Kohsuke Kawaguchi's Blog

Validate XML using RELAX NG and JAXP 1.3.

Posted by kohsuke on February 10, 2006 at 07:23 PM | Comments (10)

RELAX NG is a schema language for XML. It allows you to describe a structure of XML in a way much easier to read/write than W3C XML Schema, and it can be useful both for humans (to understand what XML is OK) and for programs (to mechanically determine if an XML is OK or not.)

Historically many good RELAX NG validators, like MSV or Jing, has been available through another validation API called JARV, which predates JAXP 1.3.

But since now JAXP 1.3 is available widely (in particular it's in J2SE 5.0), it would be really nice if one can use them through JAXP 1.3 validation API. So I wrote a little adapter layer so that I can use validators written for JARV through JAXP 1.3.

To use this, you don't have to know anything about JARV. Just put isorelax-jaxp-bridge.jar and a JARV implementation in your classpath, and write a program like this:

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI);

The complete example is also available. For more about JAXP 1.3 validation API, see this.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Kohsuke, the link to "the complete example" is broken.

    Posted by: kirillcool on February 10, 2006 at 10:58 PM

  • Thanks. Fixed.

    Posted by: kohsuke on February 11, 2006 at 09:34 AM

  • It is not working for JDK1.6.0 RC.

    Posted by: subwiz on December 05, 2006 at 08:16 AM

  • More info appreciated, subwiz.

    Posted by: kohsuke on December 06, 2006 at 02:28 PM

  • Even though I have all necessary jar files in my classpath, I am getting this error: Exception in thread "main" javax.xml.validation.SchemaFactoryFinder$ConfigurationError: Provider http\://relaxng.org/ns/structure/1.0=org.iso_relax.verifier.jaxp.validation.RELAXNGSchemaFactoryImpl not found at javax.xml.validation.SchemaFactoryFinder.newInstance(Unknown Source) at javax.xml.validation.SchemaFactoryFinder.findJarServiceProvider(Unknown Source) at javax.xml.validation.SchemaFactoryFinder.find(Unknown Source) at javax.xml.validation.SchemaFactory.newInstance(Unknown Source)

    Posted by: rolivieri on March 04, 2007 at 09:45 PM

  • I highly recommend you to directly use code like that: SchemaFactory factory = null; try { Class clazz = Class.forName("org.iso_relax.verifier.jaxp.validation.RELAXNGSchemaFactoryImpl"); factory = (SchemaFactory) clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } because the way SchemaFactoryFinder looks for libraries is definitely a mess.

    Posted by: nicodeb on March 29, 2007 at 04:53 AM

  • the produced SAXParseException doesn't give back the line number and the column numbers. They always have "0" value. I am trying to display them like that in a ErrorHandler implemented class: private void print(String gravity, SAXParseException exception) throws SAXException { out.println(gravity + " : line " + exception.getLineNumber() + " column " + exception.getColumnNumber() + " " + exception.getMessage() + "
    "); throw exception; }

    Posted by: nicodeb on May 07, 2007 at 03:00 AM

  • I wonder - has anyone ever managed to figure out the magic jars required on the classpath to make RelaxNG available inside JAXP validation? I've tried various permutations of jars from the instructions here and I always seem to get an exeption like this...
    java.lang.IllegalArgumentException: http://relaxng.org/ns/structure/1.0
            at javax.xml.validation.SchemaFactory.newInstance(SchemaFactory.java:186)
    

    Posted by: jstrachan on August 06, 2007 at 06:08 AM

  • Did the sample bundle not work for you?

    Posted by: kohsuke on August 06, 2007 at 03:15 PM

  • No, it doesn't work with Java 6 because of two different reasons.

    The first reason is, SchemaFactoryFinder from Java 6 works differently from the Java 5 version. (According to the file's author credits, it was at least originally written by you so you probably know about that.)

    Java 5 interprets the Service Provider file as a list of key/value pairs, which is a violation to the Java 5 & 6 JAR file specification but happens to match your example.

    Java 6 parses the Service Provider file as specified, ie. as a list of fully qualified class names, but thus fails to instantiate your adapter's SchemaFactory as the Service Provider file's contents are invalid.

    To be compatible with both Java 5 and Java 6 without having to change the JAXP-JARV-adapter JAR file, one can simply add another JAR file containing a correct javax.xml.validation.SchemaFactory Service Provider file.

    In this case, Java 5 will be able to use the invalid one contained in the example JAR file while Java 6 will fail to use this but succeed with the one from the "patch" JAR file.

    However, instantiating a RELAX NG capable SchemaFactory with Java 6 will still fail, as Java 6 uses reflection to call the SchemaFactories' isSchemaLanguageSupported() method. This fails with an IllegalAccessException as in the JARV-bridge's case this method is implemented within org.iso_relax.verifier.jaxp.validation.SchemaFactoryImpl which is only package visible.

    Making this abstract class public finally solves the incompatibilities and the JAXP/JARV bridge will also work with Java 6. :-)

    To avoid modifying the JAXP/JARV bridge's distribution tarball, one can just fix the SchemaFactoryImpl source file, add it to the patch JAR which is needed anyway to hold the fixed Service Provider file and include the patch JAR file in the classpath before the isorelax-jaxp-bridge-1.0.jar.

    I hope this information helps to solve the confusing I read from the previous comments in this blog.

    Posted by: gohrner on August 09, 2007 at 04:13 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds