Jump to: navigation, search

Difference between revisions of "EclipseLink/UserGuide/MOXy/Advanced Concepts/XPath Predicates"

(New page: {{EclipseLink_UserGuide |eclipselink=y |eclipselinktype=MOXy |info=y |api=y |apis= * [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/oxm/annotations/XmlPath.html Xml...)
 
m (Replacing page with 'See http://www.eclipse.org/eclipselink/documentation/2.4/moxy/advanced_concepts005.htm')
 
Line 1: Line 1:
{{EclipseLink_UserGuide
+
See http://www.eclipse.org/eclipselink/documentation/2.4/moxy/advanced_concepts005.htm
|eclipselink=y
+
|eclipselinktype=MOXy
+
|info=y
+
|api=y
+
|apis= * [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/oxm/annotations/XmlPath.html XmlPath]
+
|toc=y
+
}}
+
 
+
= Mapping using XPath Predicates =
+
 
+
As we have seen in previous examples, by default, JAXB will use the Java field name as the XML element name:
+
 
+
{|border="0" cellpadding="5"
+
|-valign="top"
+
|width="50%"|<source lang="java">
+
public class Customer {
+
  @XmlElement
+
  private String firstName;
+
  @XmlElement
+
  private String lastName;
+
}
+
</source>
+
|width="50%"|<div style="height:100%">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<customer>
+
  <firstName>Bob</firstName>
+
  <lastName>Roberts</lastName>
+
</customer>
+
</source>
+
</div>
+
|}
+
 
+
Or, the XML name can be customized using the '''name''' attribute of the '''@XmlElement''' annotation:
+
 
+
{|border="0" cellpadding="5"
+
|-valign="top"
+
|width="50%"|<source lang="java">
+
public class Customer {
+
  @XmlElement(name="f-name")
+
  private String firstName;
+
  @XmlElement(name="l-name")
+
  private String lastName;
+
}
+
</source>
+
|width="50%"|<div style="height:100%">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<customer>
+
  <f-name>Bob</f-name>
+
  <l-name>Roberts</l-name>
+
</customer>
+
</source>
+
</div>
+
|}
+
 
+
However, sometimes elements need to be mapped based on their position in the document, or based on an attribute value of an element:
+
 
+
<div style="width:500px">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<node>
+
  <name>Jane</name>
+
  <name>Doe</name>
+
  <node name="address">
+
      <node name="street">123 A Street</node>
+
  </node>
+
  <node name="phone-number" type="work">555-1111</node>
+
  <node name="phone-number" type="cell">555-2222</node>
+
</node>
+
</source>
+
</div>
+
 
+
 
+
For cases like this, EclipseLink MOXy allows you to use XPath predicates to define an expression that will specify the XML element's name.
+
 
+
 
+
== XPath Predicates ==
+
 
+
An XPath predicate represents an expression that will be evaluated against the element specified.  For example, the XPath statement:
+
 
+
<div style="width:500px">
+
<source lang="text">
+
node[2]
+
</source>
+
</div>
+
 
+
Would match the second occurrence of the '''node''' element ("DEF"):
+
 
+
<div style="width:500px">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<data>
+
  <node>ABC</node>
+
  <node>DEF</node>
+
</data>
+
</source>
+
</div>
+
 
+
Predicates can also match based on an attribute value:
+
 
+
<div style="width:500px">
+
<source lang="text">
+
node[@name='foo']
+
</source>
+
</div>
+
 
+
Would match the '''node''' element with the attribute '''name="foo"''' ("ABC").  It would not match the node that contains "DEF":
+
 
+
<div style="width:500px">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<data>
+
  <node name="foo">ABC</node>
+
  <node name="bar">DEF</node>
+
</data>
+
</source>
+
</div>
+
 
+
 
+
<div style="width:800px">
+
{{tip||For more information on XPath Predicates, see "2.4 Predicates" of the [http://www.w3.org/TR/xpath/ XML Path Language (XPath)] specification.}}
+
</div>
+
 
+
 
+
== Mapping based on Position ==
+
 
+
In the following example, our XML contains two '''name''' elements; the first occurrence of '''name''' should represent the '''Customer's''' first name, and the second '''name''' will be their last name.  To map this, we will specify XPath expressions for each property that will match the appropriate XML element.  Note that we also use '''@XmlType(propOrder)''' to ensure that our elements will always be in the proper positions.
+
 
+
<div style="width:700px">
+
<source lang="java">
+
package example;
+
+
import javax.xml.bind.annotation.*;
+
 
+
import org.eclipse.persistence.oxm.annotations.XmlPath;
+
+
@XmlRootElement
+
@XmlType(propOrder={"firstName", "lastName"})
+
@XmlAccessorType(XmlAccessType.FIELD)
+
public class Customer {
+
    @XmlPath("name[1]/text()")
+
    private String firstName;
+
+
    @XmlPath("name[2]/text()")
+
    private String lastName;
+
 
+
    ...
+
}
+
</source>
+
</div>
+
 
+
This same configuration can be expressed in an EclipseLink XML Bindings document as follows:
+
 
+
<div style="width:700px">
+
<source lang="xml">
+
...
+
<java-type name="Customer">
+
  <xml-root-element/>
+
  <xml-type prop-order="firstName lastName"/>
+
  <java-attributes>
+
      <xml-element java-attribute="firstName" xml-path="name[1]/text()"/>
+
      <xml-element java-attribute="lastName" xml-path="name[2]/text()"/>
+
  </java-attributes>
+
</java-type>
+
...
+
</source>
+
</div>
+
 
+
This will give us the desired XML representation:
+
 
+
<div style="width:700px">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<customer>
+
  <name>Bob</name>
+
  <name>Smith</name>
+
</customer>
+
</source>
+
</div>
+
 
+
 
+
== Mapping based on an Attribute Value ==
+
 
+
Since EclipseLink MOXy '''2.3''', you can also map to an XML element based on an Attribute value.  In this example, all of our XML elements are named '''node''', differentiated by the value of their '''name''' attribute:
+
 
+
<div style="width:700px">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<node>
+
  <node name="first-name">Bob</node>
+
  <node name="last-name">Smith</node>
+
  <node name="address">
+
      <node name="street">123 A Street</node>
+
  </node>
+
  <node name="phone-number" type="work">555-1111</node>
+
  <node name="phone-number" type="cell">555-2222</node>
+
</node>
+
</source>
+
</div>
+
 
+
We can use an XPath in the form of '''''element-name[@attribute-name='value']''''' to map each Java field:
+
 
+
<div style="width:700px">
+
<source lang="java">
+
package example;
+
+
import javax.xml.bind.annotation.*;
+
 
+
import org.eclipse.persistence.oxm.annotations.XmlPath;
+
 
+
@XmlRootElement(name="node")
+
@XmlAccessorType(XmlAccessType.FIELD)
+
public class Customer {
+
 
+
    @XmlPath("node[@name='first-name']/text()")
+
    private String firstName;
+
+
    @XmlPath("node[@name='last-name']/text()")
+
    private String lastName;
+
+
    @XmlPath("node[@name='address']")
+
    private Address address;
+
+
    @XmlPath("node[@name='phone-number']")
+
    private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();
+
 
+
    ...
+
}
+
</source>
+
</div>
+
 
+
<div style="width:700px">
+
<source lang="java">
+
package example;
+
+
import javax.xml.bind.annotation.*;
+
 
+
import org.eclipse.persistence.oxm.annotations.XmlPath;
+
 
+
@XmlAccessorType(XmlAccessType.FIELD)
+
public class Address {
+
 
+
    @XmlPath("node[@name='street']/text()")
+
    private String street;
+
 
+
    ...
+
}
+
</source>
+
</div>
+
 
+
<div style="width:700px">
+
<source lang="java">
+
package example;
+
+
import javax.xml.bind.annotation.*;
+
 
+
@XmlAccessorType(XmlAccessType.FIELD)
+
public class PhoneNumber {
+
 
+
    @XmlAttribute
+
    private String type;
+
 
+
    @XmlValue
+
    private String number;
+
 
+
    ...
+
}
+
</source>
+
</div>
+
 
+
 
+
== "Self" Mappings ==
+
 
+
EclipseLink allows you to configure your one-to-one mappings so the data from the target object will appear inside the source object's XML element. Expanding on the previous example, we could map the '''Address''' information so that it would appear directly under the '''customer''' element, and '''''not''''' wrapped in its own element.  This is referred to as a "self" mapping, and is achieved by setting the target object's XPath to <tt>'''"."'''</tt> (dot). 
+
 
+
The following example demonstrates a self mapping declared in annotations.
+
 
+
<div style="width:700px">
+
<source lang="java">
+
package example;
+
 
+
import javax.xml.bind.annotation.*;
+
 
+
import org.eclipse.persistence.oxm.annotations.XmlPath;
+
 
+
@XmlRootElement(name="node")
+
@XmlAccessorType(XmlAccessType.FIELD)
+
public class Customer {
+
 
+
    @XmlPath("node[@name='first-name']/text()")
+
    private String firstName;
+
+
    @XmlPath("node[@name='last-name']/text()")
+
    private String lastName;
+
+
    @XmlPath(".")
+
    private Address address;
+
+
    @XmlPath("node[@name='phone-number']")
+
    private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();
+
 
+
    ...
+
}
+
</source>
+
</div>
+
 
+
Using a self mapping, EclipseLink produces the desired XML.  The '''street''' data is stored in the root '''node'''.
+
 
+
<div style="width:700px">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<node>
+
  <node name="first-name">Bob</node>
+
  <node name="last-name">Smith</node>
+
  <node name="street">123 A Street</node>
+
  <node name="phone-number" type="work">555-1111</node>
+
  <node name="phone-number" type="cell">555-2222</node>
+
</node>
+
</source>
+
</div>
+

Latest revision as of 10:31, 8 November 2012

See http://www.eclipse.org/eclipselink/documentation/2.4/moxy/advanced_concepts005.htm