Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternatives to XPath for XML to Domain Object converter

Tags:

java

xml

Our Java application receives XML messages from a number of external systems and from these we want to create domain objects. We do not have schemas for these documents.

Currently we are are using XPaths to pull out strings from the XML and then calling setters on the new domain object. We use a home-baked XmlUtils class to do this.

foo.setBar(XmlUtils.number("/bar", document));

What alternative Java-based approaches are there, which do not require access to the document's schema?

like image 522
Paul McKenzie Avatar asked Jul 13 '11 07:07

Paul McKenzie


2 Answers

Note: I'm the EclipseLink JAXB (MOXy) lead, and a member of the JAXB 2.X (JSR-222) expert group.

MOXy offers the @XmlPath extension which enables you to do XPath based mapping:

Path Based Mapping

Match the bar element under the foo element:

@XmlPath("foo/bar/text()")
public int getBar() {
    return bar;
}

Position Based Mapping

Match the second bar element:

@XmlPath("bar[2]/text()")
public int getBar() {
    return bar;
}

Predicate Based Mapping

Match the bar element that has a type attribute with value foo:

@XmlPath("bar[@type='foo']/text()")
public int getBar() {
    return bar;
}

Combined

All of the above concepts can be used together:

@XmlPath("foo[2]/bar[@type='foo']/text()")
public int getBar() {
    return bar;
}

For More Information

  • http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
  • http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
  • http://bdoughan.blogspot.com/2011/03/map-to-element-based-on-attribute-value.html
like image 163
bdoughan Avatar answered Sep 19 '22 15:09

bdoughan


I recommend using Apache Commons Digester for this. The usage pattern is something like this:

digester.addObjectCreate("parent", Parent.class);
digester.addObjectCreate("parent/child", Child.class);
digester.addCallMethod("parent/child", "setName", 1);
digester.addCallParam("parent/child/name", 0);
digester.addSetNext("parent/child", "addChild");

Also if you already have domain objects with structure similar to source xml, you can try to annotate it manually to unmarshal with JAXB.

like image 27
Sergey Aslanov Avatar answered Sep 19 '22 15:09

Sergey Aslanov