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.
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;
}
}
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.
精彩评论