OceanBlue
OceanBlue

Reputation: 9248

Complex search query through XML records

I have a list of objects which contain one XML String field. I have to execute an SQL like query for that field, and get a sub list that satisfies the values. I am trying to use XPath.

Firstly, I can't figure out the XPath string to achieve this. Secondly, there might be a better way of doing this. I tried searching through SO but the answers don't really address this problem

Details

I have a list of books:

List <Books> allBooks;

The Book class can have an id and details fields. The details is XML.

class Book
{
    String id;
    String details; //XML
}

Here is a sample of the details xml String:

<book>
   <name>Harry Potter and the sorcerer's stone</name>
   <author>J K Rowling</author>
   <genre>fantasy</genre>
   <keyword>wizard</keyword>
   <keyword>british</keyword>
   <keyword>hogwarts</keyword>
   <price>25</price>
</book>

So, uptil here it is all set in stone. It is part of existing code and I cannot change that design.

My work is to take the list allBooks & run a query through it, the logic of which is:

   WHERE author = "J K Rowling" AND
     genre = "fantasy" AND
     (keyword = "wizard" OR keyword="hogwarts")

I considered throwing this data in a DB to run an actual query, but since the list will only contain a couple of hundred records, the overhead of connection, loading data etc is not worth it.

Anyone know how to do this through XPath? Any better way of doing this?

Upvotes: 0

Views: 159

Answers (3)

Bionic_Geek
Bionic_Geek

Reputation: 536

You need to build the XPath queries first. I recommend referring to a previous answer for those (hoaz has a good listing here). Then you need to write the code to compile the query and evaluate it. Example:

  public List<Book> findBookInformation(List<Books> books)  
      throws ParserConfigurationException, SAXException, 
         IOException, XPathExpressionException {

    List<Book> foundBooks = new ArrayList<Book>(); // books matching criteria

    for (Book book : books) {
      DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
      domFactory.setNamespaceAware(true); // never forget this!
      DocumentBuilder builder = domFactory.newDocumentBuilder();
      Document doc = builder.parse(new InputSource(new StringReader(book.details))); // parse details XML into a Doc object

      XPathFactory factory = XPathFactory.newInstance();
      XPath xpath = factory.newXPath();
      //using one of the query examples
      XPathExpression expr = xpath.compile("/book[author = \"J K Rowling\" and genre = \"fantasy\" and (keyword = \"wizard\" or keyword = \"hogwarts\")]");

      Object result = expr.evaluate(doc, XPathConstants.NODESET); 
      NodeList nodes = (NodeList) result;
      if (null != nodes && nodes.getLength() > 0) {
        foundBooks.add(book); // add to your return list
      }
    }
    return foundBooks;
  }

You could extend a method like this to take in your query arguments to dynamically build your XPath query, but this should give you the basic idea.

Upvotes: 1

bhuang3
bhuang3

Reputation: 3633

Assume the Books is the root

/Books/Book[(author = "J K Rowling") and (genre = "fantasy") and (keyword = "wizard" or keyword = "hogwarts")]

Upvotes: 0

hoaz
hoaz

Reputation: 10161

We need book records

//book

with author "J K Rowling"

//book[author = "J K Rowling"]

and genre is "fantasy"

//book[author = "J K Rowling" and genre = "fantasy"]

and keyword is "wizard" or "hogwarts"

//book[author = "J K Rowling" and genre = "fantasy" and (keyword = "wizard" or keyword = "hogwarts")]

Upvotes: 1

Related Questions