Wednesday, October 5, 2011

Xpath = JxPath


Quite often while implementing   SOAP based service we  need to  traverse   xpath.
So, my XSD looks like this;
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="myorg.xml.com" targetNamespace="myorg.xml.com">
<element name="employeeDetails">
<complexType >
<sequence>
<element name="employee" type="tns:Employee" minOccurs="1" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>

    <complexType name="Employee">
    <sequence>
    <element  name="employeeId" type="int" />
    <element name="employeeName" type="string" />
    <element name="department" type="tns:Department"/>
    <element name="EmployeeDesignation" type="tns:Designation"/>
    </sequence>
    </complexType>

    <complexType name="Department">
    <sequence>
    <element  name="departmentId" type="int" />
    <element name="departmentName" type="string" />
    </sequence>
    </complexType>
   
   <simpleType name="Designation">
    <restriction base="string">
    <enumeration value="Associate"/>
    <enumeration value="Software Engineer"/>
    <enumeration value="Senior Software Engineer"/>
    <enumeration value="Manager"/>
    <enumeration value="Executive"/>
   
    </restriction>
    </simpleType>
</schema>

And a sample XML:
<?xml version="1.0" encoding="UTF-8"?>
<tns:employeeDetails xmlns:tns="myorg.xml.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="myorg.xml.com Employee.xsd ">
  <employee>
    <employeeId>230</employeeId>
    <employeeName>Jim</employeeName>
    <department>
      <departmentId>1</departmentId>
      <departmentName>IT</departmentName>
    </department>
    <EmployeeDesignation>Associate</EmployeeDesignation>
  </employee>
 
  <employee>
    <employeeId>231</employeeId>
    <employeeName>Tim</employeeName>
    <department>
      <departmentId>12</departmentId>
      <departmentName>Admin</departmentName>
    </department>
    <EmployeeDesignation>Manager</EmployeeDesignation>
  </employee>
</tns:employeeDetails>

JXPath (http://commons.apache.org/jxpath/)  provides APIs for traversal of graphs of JavaBeans, DOM and other types of objects using the XPath syntax. Both child and attribute axis of a node is mapped to Java Beans Properties.

Below is the code to be used for xpath.
private Object traverseXpath(EmployeeDetails details , String xpath){
  JXPathContext context = JXPathContext.newContext(details);
  return context.getValue(xpath);
}
JXPath   supports indexed properties according to the JavaBeans specification. Hence  following xpath
Employee employee = (Employee)consumeDetails.traverseXpath(employeeDetails, "employee[1]");
System.out.println(employee.getEmployeeName());
will return the EmployeeName of  first object in the  list of employee.   Output will be “Jim”
Few points to be taken care:
1.       In XPath the first element of a collection has index 1, not 0.
2.       The node names in xpath should be as per the generated JAXB classes not the xml.
Example:
In the above XSD  inside Employee complex type we have following element
<element name="EmployeeDesignation" type="tns:Designation"/>
When classes are generated using XJC command we will have following property inside Employee Class

@XmlElement(name = "EmployeeDesignation", required = true)
protected Designation employeeDesignation;

but in XML we will have following node
<EmployeeDesignation>Associate</EmployeeDesignation>


 Following code
Object obj = consumeDetails.traverseXpath(employeeDetails, "employee[1]/EmployeeDesignation");
                  System.out.println(obj);
Will shoot JXPathNotFoundException.

But below code will
Object obj = consumeDetails.traverseXpath(employeeDetails, "employee[1]/EmployeeDesignation");
System.out.println(obj);
Generate output as “Associate” ,as expected

1 comment:

Tee Chess said...

Awesome post. I am so thankful to you for sharing this code. I have been working on it but is getting error. I tried many times but my code is still giving error.
digital signature certificate