6

I'm going to simplify my classes and output as best I can here, but basically what I'm after is I want to add an org.w3c.dom.Element (representing an atom link in this case) to a JAXB object I'm returning. The JAXB Class looks something like:

import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
import org.w3c.dom.Element;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "People", namespace = "main", propOrder = {
    "any",
    "persons"
})
public class People {
    @XmlAnyElement
    protected List<Element> any;
    @XmlElement(name = "person", namespace = "main")
    protected List<Person> persons;
    [...]
}

I'm creating the Element using a template I create like this:

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

public class ElementGen {
    public Element getTemplate() throws DOMException, SAXException, ParserConfigurationException {
        final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        final Schema schema = sf.newSchema(new StreamSource(
                Thread.currentThread().getContextClassLoader().getResourceAsStream(ATOM_XSD)));
        final DocumentBuilderFactory docBuilder = DocumentBuilderFactory.newInstance();
        docBuilder.setSchema(schema);
        final Document doc = docBuilder.newDocumentBuilder().newDocument();
        linkTemplate = doc.createElementNS(ATOM_NAMESPACE, ATOM_LINK);
        return linkTemplate;
    }
}

(That's not actually what the class looks like, I'm just trying to make it as easy as possible to compile something to test it without all the external mess).

I then clone that template using linkTemplate.cloneNode(false);

Now this all works in that it returns xml, but the odd thing is that the xml I get back has additional namespaces attached:

<atom:link xmlns:ns3="main" xmlns="" href="href" rel="rel"/>

If I add linkTemplate.setAttribute("xmlns", null); the "xmlns:ns3" namespace disappears and I get:

<atom:link xmlns="" href="href" rel="rel"/>

But there seems to be no way of removing that xmlns="". Am I creating the Element in the wrong way? Or perhaps something else is going wrong? I'm rather at a loss as to why it's adding these at all so any help/explanation would be appreciated.

Edit: I believe it must be related to the namespace of the document I use for generating the Element, but I'm not sure how to fix it. Is there any way of setting the (XML) targetNamespace on the document?

Edit 2: I'm not sure if it adds anything useful for anyone, but with more experimenting I found that linkTemplate.setAttribute("xmlns:" + anything, null); has the effect of creating a link with xmlns:[anything]="" and removing any others that would have otherwise been generated.

Edit 3: The relevant bits of the xsd used to generate the JAXB objects is:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0"
    xmlns="main"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:atom="http://www.w3.org/2005/Atom"
    targetNamespace="main"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified">

<xs:complexType name="People">
    <xs:sequence>
        <xs:any namespace="##other" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
        <xs:element name="person" type="Person" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    [attributes]
</xs:complexType>
[other types etc.]
Vala
  • 5,628
  • 1
  • 29
  • 55

4 Answers4

0

is the value of ATOM_LINK = "link"? if so, it should be "atom:link", and remove the setPrefix() call.

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
  • Yes, it is. And I realised that after writing the question, but the result is unfortunately the same. :\ – Vala Oct 28 '11 at 14:44
  • Eh. It's just literally that. ATOM_LINK is now "atom:link" and setPrefix is gone. I also tried creating a root element and making this element be a child of that, but it didn't do anything so I removed it again. – Vala Oct 28 '11 at 22:02
  • how are you adding the attributes? – jtahlborn Oct 28 '11 at 22:44
  • `linkTemplate.setAttribute("xmlns", null);` etc. That's just after I've cloned the template. – Vala Oct 28 '11 at 22:46
  • Again exactly the same, just replace "xmlns" with "href"/"rel" and null with the Strings from the xml in the question. – Vala Oct 29 '11 at 02:07
0

I believe the problem is that the DocumentBuilderFactory you aere creating should be name space aware.

public class ElementGen {
   public Element getTemplate() throws DOMException, SAXException, ParserConfigurationException {
    final DocumentBuilderFactory docBuilder = DocumentBuilderFactory.newInstance();
    docBuilder.setNamespaceware(true);
    final Document doc = docBuilder.newDocumentBuilder().newDocument();
    linkTemplate = doc.createElementNS(ATOM_NAMESPACE, ATOM_LINK);
    return linkTemplate;
  }
}

If you find yourself manipulating xmlns attribute directly, somethibng is wrong.

forty-two
  • 12,204
  • 2
  • 26
  • 36
0

Have you tried setting your elementFormDefault to "UNqualified" ?

Pat B
  • 1,915
  • 23
  • 40
0

Since none of the suggestions here have worked for me I've decided to go a different route. In the end I ended up overwriting the Listener RESTEasy adds to the Marshaller with a Listener of my own. This Listener then calls the RESTEasy listener (if it was present), before adding the links manually on the RESTServiceDiscovery field (you have to get this field using reflection, and turn off access checking with field.setAccessible(true) before getting the object).

Vala
  • 5,628
  • 1
  • 29
  • 55