Skip to main content

JXPath to rescue!

Posted by mister__m on December 31, 2003 at 7:36 AM PST

Querying a database is no big deal. SQL has been around for a long time and has become the de facto standard for doing that. So has JDBC, even though nowadays it is being used more as the foundation of other solutions and frameworks. But what you do when you have to query objects? Most people wouldn't be able to answer it, really. Three more common ways of querying your objects in Java are custom indexing, OQL and JXPath. This entry is specifically about JXPath.

Jakarta Commons JXPath basically defines a simple XPath interpreter that can be applied to general object graphs: POJOs, Maps, Servlet contexts, DOMs and more. XPath is a W3C standard originally conceived for navigating XML nodes, but can be easily applied to Java.

Let's see it in action. To ilustrate its use and advantages, we will work with the classical Order problem (Order, LineItem and Product). Let's assume all Orders are stored in a Collection which is a property of our OrderHistory object. What if we wanted to get all the Orders which contained more than 5 CDs? In plain Java:

Collection selectedOrders = new ArrayList();
Order order;
LineItem item;

for (Iterator orders = orderHistory.getOrders().iterator(); orders.hasNext(); ) {
    order = (Order)orders.next();

    for (final Iterator items = order.getLineItems().iterator(); items.hasNext(); ) {
      item = (LineItem)items.next();

      if (item.getQuantity() > 5 && item.getProduct().getType().getName().equals("CD")) {
         selectedOrders.add(order);
      }
    }
}

return selectedOrders.iterator();

To avoid being unfair, using 1.5 sintax:

Collection selectedOrders = new ArrayList();

for (Order order : orderHistory.getOrders()) {
    for (LineItem item : order.getLineItems()) {
      if (item.getQuantity() > 5 && item.getProduct().getType().getName().equals("CD")) {
         selectedOrders.add(order);
      }
    }
}

return selectedOrders.iterator();

With JXPath:

JXPathContext history = JXPathContext.newContext(orderHistory);

return history.iterate("/orders[lineItems[quantity = 5 and product/type/name = 'CD']]");

That is it. As simple as that. JXPath becomes more valuable as your queries become more complex, but I am not going to show an example here.

Someone might ask: hey, but when I would like to manipulate objects in memory? There are a lot of occasions, actually. One very common is when you have a small application that needs to persist a small amount of data. If you combine Prevayler - an option to databases, as it keeps everything in memory and performs persistence through serialization and guarantees data integrity - and JXPath, you have a very fast solution with fewer lines of code. Consider using it when you have the chance.

As a final note, JXPath has many powerful features, as compiled expressions and variables - similar to PreparedStatements -, pointer, and many more, but you can find more about these by yourself. Go to the above link, download and start using it. The User Manual in the docs is probably the best one for a Apache Project and is highly recommended reading. Try it as soon as you can: you may become addicted to it...

Related Topics >>