David North
David North

Reputation: 1139

Is it possible to get the DOM Attr for an attribute using JAXB?

We're using JAXB to unmarshall a fragment of XML which looks a bit like this:

<someRandomElement xmlns:foo="http://example.com/foo" xpath="//foo:bar" />

Our object model is:

@XmlRootElement(name="someRandomElement")
class SomeRandomClass {

    @XmlAttribute(name="xpath")
    private XPathFragment _expression;
}

class XPathFragment {
    String _expr;

    // we need this to look up namespace prefixes used in _expr
    Node _parentNode;
}

So my question is, how can I unmarshall the XPathFragment from the XML using JAXB?

I have tried using a custom XmlAdapter for XPathFragment, but this doesn't seem to have an opportunity to access the DOM Nodes corresponding to the someRandomElement and its attributes.

Upvotes: 1

Views: 629

Answers (2)

bdoughan
bdoughan

Reputation: 149017

You could leverage the ability to pass an initialized XmlAdapter to an unmarshaller.

XPathFragmentAdapter

import javax.xml.bind.annotation.adapters.XmlAdapter;

import org.w3c.dom.Document;

public class XPathFragmentAdapter extends XmlAdapter<String, XPathFragment>{

    private Document document;

    public XPathFragmentAdapter() {
    }

    public XPathFragmentAdapter(Document document) {
        this.document = document;
    }

    @Override
    public XPathFragment unmarshal(String v) throws Exception {
        XPathFragment xPathFragment = new XPathFragment();
        xPathFragment.set_expr(v);
        xPathFragment.set_parentNode(document.getDocumentElement());
        return xPathFragment;
    }

    @Override
    public String marshal(XPathFragment v) throws Exception {
        return v.get_expr();
    }

}

Demo

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;

public class Demo {

    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        File file = new File("input.xml");
        Document document = db.parse(file);

        JAXBContext jc = JAXBContext.newInstance(SomeRandomClass.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setAdapter(new XPathFragmentAdapter(document));
        SomeRandomClass src = (SomeRandomClass) unmarshaller.unmarshal(document);

        System.out.println(src.get_expression().get_parentNode() != null);
    }

}

SomeRandomClass

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement(name="someRandomElement")
class SomeRandomClass {

    private XPathFragment _expression;

    @XmlAttribute(name="xpath")
    @XmlJavaTypeAdapter(XPathFragmentAdapter.class)
    public XPathFragment get_expression() {
        return _expression;
    }

    public void set_expression(XPathFragment _expression) {
        this._expression = _expression;
    }

}

XPathFragment

import javax.xml.bind.annotation.XmlTransient;

import org.w3c.dom.Node;

class XPathFragment {
    String _expr;

    // we need this to look up namespace prefixes used in _expr
    Node _parentNode;

    public String get_expr() {
        return _expr;
    }

    public void set_expr(String _expr) {
        this._expr = _expr;
    }

    @XmlTransient
    public Node get_parentNode() {
        return _parentNode;
    }

    public void set_parentNode(Node _parentNode) {
        this._parentNode = _parentNode;
    }

}

Upvotes: 2

lexicore
lexicore

Reputation: 43671

For JAXB RI:

Write a custom XmlAdapter for your XPathFragment. You can access the current namespace context during unmarshalling via UnmarshallingContext.getInstance(). See how QName handling is implemented (check implementations of com.sun.xml.bind.v2.model.runtime.RuntimeBuiltinLeafInfo). Parsing of QName also needs namespace resolution, just like you XPathFragment case.

Upvotes: 0

Related Questions