RESTeasy/JAXB; How do I avoid a namespace being added to an Element in an <any> tag? (List<Element> in JAXB)

若如初见. 提交于 2019-12-12 10:44:28

问题


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.]

回答1:


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




回答2:


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.




回答3:


Have you tried setting your elementFormDefault to "UNqualified" ?




回答4:


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).



来源:https://stackoverflow.com/questions/7929633/resteasy-jaxb-how-do-i-avoid-a-namespace-being-added-to-an-element-in-an-any

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!