English | Site Directory

Google Base Data API

Java Raw Protocol - QueryExample2

QueryExample2 queries the Google Base data API, parses the result, and displays the titles of the returned data items.

One major problem with QueryExample1 is that it simply dumps query results to the console, and the result is barely readable. In any real life application the query result would need to be parsed, interpreted, and the relevant information extracted and displayed to the user. In QueryExample2 we demonstrate a possible way of doing this by using a SAX parser to extract each data item's title from the result and display it to the console. Some very basic understanding of how SAX parsers work is necessary in order to fully understand this example.

One might argue that for this task we don't even need a SAX parser. We could just search for all <title> tags in the result and display the characters that they enclose. Unfortunately, that wouldn't work, as the Atom response also has a <title> tag, which is the title of the feed:

<feed>
  ...
  <title type="text">Items matching query: cars [item type : products]</title>
  ...
    <entry>
    ...
      <title type='text'>Great car for sale</title>
      ...  

Atom does not mandate that the feed's <title> tag should appear at a specific position inside the feed, so we need to make sure we only display the <title> tags which are sub-elements of an <entry> tag.

Contents

  1. Running QueryExample2
  2. Stepping through the QueryExample2 code

Running QueryExample2

  1. Obtain a developer key for an "installed application".
  2. Edit QueryExample2.java and fill in the DEVELOPER_KEY static string with your developer key.
  3. private static final String DEVELOPER_KEY = ""; 
  4. Compile and run the example using your favorite editor, or using the command line:
  5. javac com/google/api/gbase/examples/basic/QueryExample2.java
    java com/google/api/gbase/examples/basic/QueryExample2
    

The output will be as follows:

Item 1: Johnny Lightning MUSCLE CARS R8 1967 Chevelle SS
Item 2: Johnny Lightning MUSCLE CARS USA 2005 Ford GT
...
Item 25: The Cars movie Hinged tool Box Toy Organize lunch RARE  

Stepping through the QueryExample2 code

As in the previous example, we first send the query to the Google Base data API server and obtain an inputStream containing the response:

URL url = new URL(SNIPPETS_FEED + "?bq=" + 
  URLEncoder.encode(QUERY, "UTF-8") + "&key=" + DEVELOPER_KEY);
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpConnection.getInputStream();

We then use a standard SAX parser to parse the result. We obtain a SAXParser instance using a SAXParserFactory:

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();

We then parse the resulting inputStream using DisplayTitlesHandler(), our custom SAX event handler:

parser.parse(inputStream, new DisplayTitlesHandler());  

DisplayTitlesHandler() is derived from the no-op SAX parser, org.xml.sax.helpers.DefaultHandler. The logic inside DisplayTitlesHandler() is pretty simple: we keep a stack of the currently open XML tags and print all character data when we are inside a <title> tag that has an <entry> parent. The insideEntryTitle flag is turned on each time we are inside an <entry><title> pair.

public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
  if (qName.equals("title") && xmlTags.peek().equals("entry")) {
    insideEntryTitle = true;
    System.out.print("Item " + ++itemNo + ": ");
  } 
  xmlTags.push(qName);  

Since startElement() is invoked each time the SAX parser encounters an opening XML tag, we switch on insideEntryTitle only if the currently parsed opening tag is <title> and the tag on the top of the stack is <entry> . Here, we are also printing the itemNo messages, rather than in the characters method, as characters can be called multiple times for different chunks of the title's character data.

The endElement() method is invoked each time an XML tag closes. All we need to do here is to remove the closing XML tag from the stack and, if the removed XML tag was an entry's title, flip insideEntryTitle to false and go to a new line in the console in preparation for printing out the next title.

public void endElement(String uri, String localName, String qName) throws SAXException {
  xmlTags.pop();
  if (insideEntryTitle) {
    insideEntryTitle = false;
    System.out.println();
  }
}
  

The characters() method is invoked when the parser encounters character data inside an XML element. If we are inside the <title> tag; that is, if the insideEntryTitle flag is on, we display the current characters: length characters from the ch array, starting with start. As noted earlier, we can't use println here to get to a new line, as characters can be invoked multiple times for different chunks of the same title.

public void characters(char[] ch, int start, int length) throws SAXException {
  if (insideEntryTitle) {
    System.out.print(new String(ch, start, length));
  }
}

In the main method, all we do is create an instance of QueryExample2 and invoke its displayItems() method.

public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException {
  new QueryExample2().displayItems();
}

Go to QueryExample3