2

I'm trying to learn some XML Parsing here and I've been given some code to start out with. I've done some research into the different API's i'm using and I've gradually been able to debug my code into something I hope will work. I'm trying to parse XML files by hard wiring the XPath Query's into a string variable. I'm also using DocumentBuilderFactory if that helps at all. Anyway, I keep getting this exception: Java.lang.String cannot be cast to org.w3c.dom.Node (I've marked it in the code below). I understand what the errors is. The String Query doesn't seem to agree with the parameters of the "evaluate" method. Just don't know how to fix it. I've tried all sorts of different casts and they aern't working. Something tells me I'm doing something horribly wrong here...please help! PS. I'm sorry my code is a but messy, i'm totally new to parsing, I also know there are some unnecessary imports but I figure I may need them if I make a few changes.

Code:

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;

import org.jaxen.JaxenException;
import org.jaxen.dom.DOMXPath;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class Parser 
{
public static void main(String[] args) 
{
    boolean isNamespaceAware = true;
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(isNamespaceAware);
    DocumentBuilder builder = null;
    try 
    {
        builder = dbf.newDocumentBuilder();
    } 
    catch (ParserConfigurationException e2)
    {
        e2.printStackTrace();
    } 
    try 
    {
        Document workingDocument =
builder.parse("C:\\Users\\Brandon\\Job\\XPath\\XPath_Sample_Stuff\\XPath_Objects.xml");
    } 
    catch (SAXException e1) 
    {
        e1.printStackTrace();
    } 
    catch (IOException e1) 
    {
        e1.printStackTrace();
    } 
    String xPathQuery = "/book/author"; 
    DOMXPath generatedPath;
    String results = null;
    try 
    {
        generatedPath = new DOMXPath(xPathQuery);
//Here is the errror
        results = generatedPath.evaluate(xPathQuery); 
    } 
    catch (JaxenException e) 
    {
        e.printStackTrace();
    }   
    if(results == null)
        System.err.println("There was an issue processing the xpath, and
 results were still null.");
    for (int i=0; i<= results.getLength();i++)
    {
        System.out.println(results.item(i));
    }
}                   

}

Here is some XML from an XML file I was given:

 <?xml version="1.0"?>
 <catalog> 
 <book id="bk101"> 
  <author>Gambardella, Matthew</author> 
  <title>XML Developer's Guide</title> 
  <genre>Computer</genre>
  <price>44.95</price>
  <publish_date>2000-10-01</publish_date> 
  <description>An in-depth look at creating applications with XML.</description> 
</book> 
8
  • What is Jaxen and DOMXPath? These are not part of core Java as far as I know and not usually used with XPath (again as far as I know). Why not simply use standard Java classes to do this? Commented Jul 1, 2012 at 4:00
  • Also you will want to start with a relatively simple XML file and post that file here with your question. Commented Jul 1, 2012 at 4:10
  • Yeah, Like i said i was given the code, so i'm not really sure myself. I also imported an external jar so that's may be where DOMXPath came from. Sigh...But i'm trying to get the code I was given to work, I don't want to write a whole new parser class unless i have to. Commented Jul 1, 2012 at 4:12
  • 1
    OK, then who gave you this non-standard code? Perhaps you should ask them about it. For my money, when learning something complex like this, I would start out with the class's available in the core Java library and go through some tutorials that are available online. I would ditch this code if I were you. Commented Jul 1, 2012 at 4:14
  • Yeah, fair enough, I think you're right. I'l just write another Parser from scratch, that way i can actually learn more about the API anyway...sorry this was my first post and i'm starting to think it was just a bug mistake. I'll mark it solved in a little bit, but I just want to make sure nobody else has anything to say. Commented Jul 1, 2012 at 4:19

2 Answers 2

1

The error is telling you that the DOMXPath#evaluate(...) method returns a String. You are trying to cast it as a NodeList, which it is not. The API for this method will explain all -- but again, that API is not part of standard Java but instead is part of Jaxen. But the result makes sense even for core Java since its XPath#evaluate(...) method also usually returns a String (except for one overload).

Again, perhaps you don't want to use Jaxen just now, unless you have some strong reasons for doing so but haven't told us yet.

Edit
Say you had an XML in a file, Catalog.xml, that looked like so:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<catalog>
    <book id="bk101">
        <author>Smith, John</author>
        <title>Fubars Rule</title>
        <price>100.1</price>
        <date>2012-10-01</date>
        <description>A witty exposé</description>
    </book>
    <book id="bk102">
        <author>Python, Monty</author>
        <title>Your Hovercraft is full of Eels</title>
        <price>250.5</price>
        <date>10-01-01</date>
        <description>an even wittier exposé</description>
    </book>
</catalog>

JAXB could marshall/unmarshall that sucker with just some annotations in your regular classes. It makes doing this almost idiot proof. For example:

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

public class CatalogTest {
   private static final String PATH_NAME = "Catalog.xml";



   public static void main(String[] args) {
      // comment one of the lines below and un-comment the other to test
      // marshallTest(); 
      unmarshallTest();
   }



   private static void unmarshallTest() {
      JAXBContext context;
      try {
         context = JAXBContext.newInstance(Catalog.class);
         Unmarshaller unmarshaller = context.createUnmarshaller();
         File catalogFile  = new File(PATH_NAME);
         Catalog catalog = (Catalog) unmarshaller.unmarshal(catalogFile  );
         System.out.println(catalog);
      } catch (JAXBException e) {
         e.printStackTrace();
      }

   }



   private static void marshallTest() {
      try {
         Book[] books = {
               new Book("bk101", "Smith, John", "Fubars Rule", 100.10, "2012-10-01", "A witty exposé"),
               new Book("bk102", "Python, Monty", "Your Hovercraft is full of Eels", 250.50, "10-01-01", "an even wittier exposé")
         };
         Catalog catalog = new Catalog();
         for (Book book : books) {
            catalog.addBook(book);
         }
         JAXBContext context = JAXBContext.newInstance(Catalog.class);
         Marshaller marshaller = context.createMarshaller();
         marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

         File catalogFile = new File(PATH_NAME);
         marshaller.marshal(catalog, catalogFile);

      } catch (JAXBException e) {
         e.printStackTrace();
      }
   }
}

@XmlRootElement
class Catalog {
   @XmlElement(name = "book")
   private List<Book> bookList = new ArrayList<Book>();

   public List<Book> getBookList() {
      return bookList;
   }

   public void addBook(Book book) {
      bookList.add(book);
   }

   @Override
   public String toString() {
      return "Catalog [bookList=" + bookList + "]";
   }


}

@XmlRootElement
@XmlType(propOrder = { "author", "title", "price", "date", "description"})
class Book {
   private String id;
   private String author;
   private String title;
   private double price;
   private String date;
   private String description;

   public Book() {
   }

   public Book(String id, String author, String title, double price,
         String date, String description) {
      this.id = id;
      this.author = author;
      this.title = title;
      this.price = price;
      this.date = date;
      this.description = description;
   }

   @XmlAttribute(name = "id")
   public String getId() {
      return id;
   }

   public void setId(String id) {
      this.id = id;
   }

   public String getAuthor() {
      return author;
   }

   public void setAuthor(String author) {
      this.author = author;
   }

   public String getTitle() {
      return title;
   }

   public void setTitle(String title) {
      this.title = title;
   }

   public double getPrice() {
      return price;
   }

   public void setPrice(double price) {
      this.price = price;
   }

   public String getDate() {
      return date;
   }

   public void setDate(String date) {
      this.date = date;
   }

   public String getDescription() {
      return description;
   }

   public void setDescription(String description) {
      this.description = description;
   }

   @Override
   public String toString() {
      return "Book [id=" + id + ", author=" + author + ", title=" + title
            + ", price=" + price + ", date=" + date + ", description="
            + description + "]";
   }

}
Sign up to request clarification or add additional context in comments.

4 Comments

Hmm, I changed the results to a String and took out the NodeList cast but I have the same error. I think the error might actually be telling me that the XPathQuery is the string that's causing the problem, which would basically make this code impossible to fix without completely changing how i'm going to go about this...
Full Error: Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to org.w3c.dom.Node Line: results = generatedPath.evaluate(xPathQuery)
cool, thanks for your help man. I found a tutorial and I'll be writing an entirely new Parser tomorrow...with some different libraries :)
@MiniatureBeast: please see edit to see simplicity of JAXB solution -- the one I usually recommend.
0

If starting from scratch, I would suggest JDOM or DOM4J as alternatives (look at tutorials for both) to the Java library standard classes (org.w3c.dom.*). They are easier to work with. Jaxen will work with both of them.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.