The Source for Java Technology Collaboration
User: Password:



Michael Nascimento Santos

Michael Nascimento Santos's Blog

JXPath to rescue!

Posted by mister__m on December 31, 2003 at 07:36 AM | Comments (6)

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...


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Code error?
    Should that be:
    return history.iterate("/orders[lineItems[quantity = 5 and product/type/name = 'CD']]"); ?

    Posted by: mrweather on December 31, 2003 at 09:54 AM

  • Re: Code error?
    Yes, you are absolutely correct. Silly mistake :-D
    I've already changed it. Thank you for pointing it out.

    Posted by: mister__m on December 31, 2003 at 10:02 AM

  • how does one deal with map-ifying a collection. E.g., if an object has an array of Object foo[] with field member foo.fieldMember, how would jxpath retrieve all foo.fieldMember in order to assign it to map( fieldMember, result[] )?

    TIA

    Posted by: nukeuser on December 20, 2005 at 11:37 PM

  • O.k

    I need to know..if the time in process execution is lower than
    a simple method like :
    for (Iterator companies =
    database.getCompanies().iterator();
    companies.hasNext();) {

    Company company = (Company)companies.next(); ...etc etc..

    ..if JXPath reduce this measure...it“ld be a good tool for my implementations.

    greettings from Costa Rica, pura vida !! :)

    Posted by: rocasaca on August 03, 2006 at 03:47 PM

  • Hi rocasa,

    I doubt it is faster, since there is a lot happening behind the scenes, but I can tell you from experience and profiling that the overhead is negligible, at least if you use CompiledExpressions.

    Posted by: mister__m on August 04, 2006 at 06:25 AM

  • Well,
    the performance hit is pretty considerable.
    For the expression like this iterating couple of lists : "executionItems[@role='S']/priceQuantityAssociations/quantity/value"

    Time is 100 times more

    For the plain java object 1000 iterations: 1.6 ms
    For the JXPath compiled expression 1000 iterations: 200 ms

    Is there any additional performace optimization available?

    Thanks

    Posted by: lenisha on June 26, 2007 at 08:24 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds