A limited view on a given XML document instance

exercise No. 62

A specific view on memo documents Create comment in forum

Q:

We reconsider the following memo instance:

<memo>
  <from>
    <name>Martin</name>
    <surname>Goik</surname>
  </from>
  <to>
    <name>Adam</name>
    <surname>Hacker</surname>
  </to>
  <to>
    <name>Eve</name>
    <surname>Intruder</surname>
  </to>
  <date year="2005" month="1" day="6"/>
  <subject>Firewall problems</subject>
  <content>
    <para>Thanks for your excellent work.</para>
    <para>Our firewall is definitely broken!</para>
  </content>
</memo>

Every memo instance does have exactly one sender and one subject. Write a SAX application to achieve the following output:

Sender: Martin Goik
Subject: Firewall problems

Hint: The callback implementation of org.xml.sax.helpers.DefaultHandler.characters(char[],int,int) may be used to filter the desired output. You have to limit its output to <from> and <subject> descendant content. Taking the <subject>Firewall problems</subject> element as an example the corresponding event sequence reads:

Event Corresponding callback
... ...
Opening <subject> element startElement(...)
Firewall problems characters(...)
Closing </subject> element endElement(...)
... ...

Limiting output of our org.xml.sax.helpers.DefaultHandler.characters(char[],int,int) callback method can be achieved by introducing instance scope boolean variables being set to true or false inside your org.xml.sax.helpers.DefaultHandler.startElement(String uri,String localName,String qName,org.xml.sax.Attributes attributes) and org.xml.sax.helpers.DefaultHandler.endElement(String uri, String localName, String qName) implementations accordingly to keep track of the current event state.

A:

package sax.view;
...
/** A view on memo documents restricting to sender name an subject. */
public class MemoViewHandler extends DefaultHandler {

  // These variables help us to keep track of the current event state spanning
  // each startElement(...) -- character(...) -- endElement(...) event sequence
  boolean inFromContext = false,
      inSubjectContext = false;

  public void startElement(String namespaceUri, String localName,
      String rawName, Attributes attrs) {
    switch(rawName) {
    case "from":
      inFromContext = true;
      System.out.print("Sender: ");
      break;
    case "subject":
      inSubjectContext = true;
      System.out.print("Subject: ");
      break;
    case "surname":
      if (inFromContext) {
        System.out.print(" "); // Adding additional space between <name>
      }                        // and <surname>  content.
      break;
    }
  }

  @Override
  public void endElement(String uri, String localName, String rawName)
      throws SAXException {
    switch(rawName) {
    case "from":
      inFromContext = false;
      System.out.println();
      break;
    case "subject":
      inSubjectContext = false;
      System.out.println();
      break;
    }
  }

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