The Node interface available that is when you use the DOM parser contains all the standard W3C DOM methods for navigating in a document, including getNextSibling, getPreviousSibling, getFirstChild, getLastChild, and getParent. It's different when you use a SAX parser, however, because this parser does not create a tree of nodes, so those methods don't apply.
Instead, if you want to find a particular element, you have to find it yourself. In the previous chapter, I found the third person's name in meetings.xml:
<?xml version="1.0"?> <MEETINGS> <MEETING TYPE="informal"> <MEETING_TITLE>XML In The Real World</MEETING_TITLE> <MEETING_NUMBER>2079</MEETING_NUMBER> <SUBJECT>XML</SUBJECT> <DATE>6/1/2002</DATE> <PEOPLE> <PERSON ATTENDANCE="present"> <FIRST_NAME>Edward</FIRST_NAME> <LAST_NAME>Samson</LAST_NAME> </PERSON> <PERSON ATTENDANCE="absent"> <FIRST_NAME>Ernestine</FIRST_NAME> <LAST_NAME>Johnson</LAST_NAME> </PERSON> <PERSON ATTENDANCE="present"> <FIRST_NAME>Betty</FIRST_NAME> <LAST_NAME>Richardson</LAST_NAME> </PERSON> </PEOPLE> </MEETING> </MEETINGS>
It's not difficult to do the same thing here, but in SAX programming, finding a specific element takes a little code. I start by finding the third <PERSON> element and setting a variable named thirdPersonFlag true when I find it:
public void startElement(String uri, String localName, String rawName, Attributes attributes) { if(rawName.equals("PERSON")) { personCount++; } if(personCount == 3) { thirdPersonFlag = true; } . . . }
When the SAX parser is parsing the third person's <FIRST_NAME> element, I'll set a variable named firstNameFlag to true; when it's parsing the third person's <LAST_NAME> element, I'll set a variable named lastNameFlag to true.
public void startElement(String uri, String localName, String rawName, Attributes attributes) { if(rawName.equals("PERSON")) { personCount++; } if(personCount == 3) { thirdPersonFlag = true; } if(rawName.equals("FIRST_NAME") && thirdPersonFlag) { firstNameFlag = true; } if(rawName.equals("LAST_NAME") && thirdPersonFlag) { firstNameFlag = false; lastNameFlag = true; } }
Watching the variables firstNameFlag and lastNameFlag, I can store the person's first and last names in the character callback:
public void characters(char characters[], int start, int length) { String characterData = (new String(characters, start, length)).trim(); if(characterData.indexOf(" ") < 0 && characterData.length() > 0) { if(firstNameFlag) { firstName = characterData; } if(lastNameFlag) { lastName = characterData; } } }
When the SAX parser is done parsing the third <PERSON> element, I'll display that person's name:
public void endElement(String uri, String localName, String rawName) { if(thirdPersonFlag && lastNameFlag){ System.out.println("Third name: " + firstName + " " + lastName); thirdPersonFlag = false; firstNameFlag = false; lastNameFlag = false; } }
And that's the technique you use when you're hunting a specific element using a SAX parser—you just wait until the parser hands it to you. Here are the results:
%java navSAX meetings.xml Third name: Betty Richardson
You can see the full code for this program, navSAX.java, in Listing 12.5.