Using Jing with Google App Engine. Can't load SchemaFactory given Relax NG schema
Okay, so here's the short of what I'm trying to achieve. I am developing a small Google App Engine application that generates XML given a particular object.
Now, I run into issues because I need to use a Relax NG schema and validate it against my Document object. This works fine on my local machine (Eclipse Helios Java EE, Mac OS X Snow Leopard, Google Web Toolkit 2.2.0, App Engine 1.4.2), but as soon as I deploy to App Engine, my code fails and throws an IllegalArgumentException.
The specific exception is this:
java.lang.IllegalArgumentException: No SchemaFactory that implements the schema language specified by: http://relaxng.org/ns/structure/1.0 could be loaded
The specific line(s) of code that it is complaining about are the following:
System.setProperty(SchemaFactory.class.getName() + ":" 开发者_C百科+ XMLConstants.RELAXNG_NS_URI, "com.thaiopensource.relaxng.jaxp.CompactSyntaxSchemaFactory");
SchemaFactory schemaFac = SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI);
The last line is the line that throws the Exception.
I have tried looking online, and posted in several Google Groups, but no one came forth with an idea.
Note: I took the use of some of the above code from this example: How to validate an XML document using a RELAX NG schema and JAXP?
My suspicion is that App Engine is not loading Jing.jar for some reason. I don't know how I can check that it is/isn't.
Any help would be appreciated! Thanks!
This post just to clarify.
The usual way I would validate an XML document with Jing and Relax NG is:
System.setProperty(SchemaFactory.class.getName() + ":" + XMLConstants.RELAXNG_NS_URI, "com.thaiopensource.relaxng.jaxp.XMLSyntaxSchemaFactory");
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI);
Schema schema = factory.newSchema(new File("path/to/schema.rng"));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new StringReader(xmlString)));
Now, in App Engine, the first two lines don't work, and cause an IllegalArgumentException to be thrown, like you said. So exchanging them with
SchemaFactory factory = new XMLSyntaxSchemaFactory();
does the trick. Summary (including imports):
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import com.thaiopensource.relaxng.jaxp.XMLSyntaxSchemaFactory;
SchemaFactory factory = new XMLSyntaxSchemaFactory();
Schema schema = factory.newSchema(new File("path/to/schema.rng"));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new StringReader(xmlString)));
Note that this is for schemas in XML syntax. For compact syntax, exchange XMLSyntaxSchemaFactory with CompactSyntaxSchemaFactory.
I'd guess that System.setProperty()
is failing, or rather not being used correctly. According to the docs:
All system properties and environment variables are private to your application. Setting a system property only affects your application's view of that property, and not the JVM's view.
If SchemaFactory is part of the JDK (which I think it is), you may not be able to reset it. However, you may have more luck setting the system property in your appconfig file, as this might get changed earlier in the startup sequence.
Well, I actually found a workaround of sorts that completely takes out the (practically hackish) use of System.setProperty.
It turns out that Jing has a little class called "CompactSyntaxSchemaFactory".
Here is how I used it:
DocumentBuilderFactory docFactory = null;
CompactSyntaxSchemaFactory scReader = new CompactSyntaxSchemaFactory();
URL relaxSchemaURL = new URL("http://example.com/myschema.rng");
Schema2 relaxSchema = scReader.newSchema(relaxSchemaURL);
docFactory = DocumentBuilderFactory.newInstance();
docFactory.setSchema(relaxSchema);
Worked like a charm.
精彩评论