XML Schema Validation with JAXP 1.4 and JDK 6.0
A few people have found problems validating DOM instances with JAXP1.4/JDK 6.0. I saw this quesion raised in the Java Technology and XML forum, and at least 3 bugs were filed for this in the last few weeks. I'll use this blog entry to explain what the problem is and how to easily fix your code.
Let's start by showing a snippet of the problematic code, which basically parses an XML file into a DOM and tries to validate it against an XML schema.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = dbf.newDocumentBuilder(); Document document = parser.parse(getClass().getResourceAsStream("test.xml")); // create a SchemaFactory capable of understanding XML schemas SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // load an XML schema Source schemaFile = new StreamSource(getClass().getResourceAsStream("test.xsd")); Schema schema = factory.newSchema(schemaFile); // create a Validator instance and validate document Validator validator = schema.newValidator(); validator.validate(new DOMSource(document));
Can you spot any problems in this code? Well, there's nothing obviously wrong with it, except that if you try this with JAXP 1.4 RI or JDK 6.0, you're going to get an error like,
org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'foo'. at ...
So what is the problem then? Namespace processing. By default, and for historical reasons, namespace awareness isn't enabled in a DocumentBuilderFactory, which means the document that is passed to the validator object isn't properly constructed. You can fix this problem by adding just one line,
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); // Must enable namespace processing!! DocumentBuilder parser = dbf.newDocumentBuilder(); ...
By now you may be asking yourself why is this even reported as a problem. Naturally, XML Schema validation requires namespace processing. It turns out that in JDK 5.0 this magically worked in many cases. Notice the use of the term "magically". By that I mean, "we don't know how it worked before but we are certainly looking into it".
So for now I'm just reporting the problem and proposing a fix for it. But I still owe you a better explanation as to why this worked before --or maybe you know why and you can tell me?