views:

199

answers:

2

We have an XSD which validates an XML document with a namespace declared, but we would like to use it on a document without one.

In Java 5, it looks like it's possible to call setAttribute() on the xmlns attribute of the root element, but this fails in Java 6 with an exception:

Exception in thread "main" org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'Test'.

Is this a bug in Java 5 or 6 or neither?

Code to reproduce:

import java.io.*;
import javax.xml.XMLConstants;
import javax.xml.parsers.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import javax.xml.validation.*;
import org.w3c.dom.Document;

public class NamespaceTest
{
    public static void main(String[] args) throws Exception
    {
        String namespace = "myNamespace";
        String xmlDoc = "<Test/>\n";
        String xsd = String.format(
                "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"%n" +
                "            targetNamespace=\"%1$s\" xmlns=\"%1$s\" elementFormDefault=\"qualified\">%n" +
                "     <xs:element name=\"Test\"/>%n" +
                "</xs:schema>%n", namespace);

        System.out.println("Original doc:\n" + xmlDoc);
        System.out.println("Original schema:\n" + xsd);

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document testXml = builder.parse(new ByteArrayInputStream(xmlDoc.getBytes("UTF-8")));
        testXml.getDocumentElement().setAttribute("xmlns", namespace);
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = schemaFactory.newSchema(new StreamSource(new StringReader(xsd)));
        Validator validator = schema.newValidator();
        validator.validate(new DOMSource(testXml));

    }   
}
+2  A: 

This does not look like a bug to me, and I am surprised that you could do this earlier. Setting the xmlns attribute on the root element after the DOM tree has already been built is too late.

At that point, every element in the DOM tree already has had its prefix resolved, and a local name and URI assigned.

If you really want to do this by manipulating the xmlns attribute (which is not really a proper attribute), you have to manipulate the input stream before calling the DOM parser.

Alternatively, could try to walk the tree and set the namespace URI of each node in it.

Edit: to clarify, if there was a bug in there somewhere, it was in Java 5 - if somebody checked for an xmlns attribute. The correct way is to get the URI of the root element.

xcut
+2  A: 

IIRC, xmlns is not an attribute, it is a namespace declaration. It may look like an attribute in the xml text, but it isn't one. It should not be settable with a call to setAttribute. IMO, the Java 5 behavior is a BUG.

KitsuneYMG