440 likes | 645 Views
Chapter 9 – Simple API for XML (SAX). Outline 9.1 Introduction 9.2 DOM vs. SAX 9.3 SAX-based parsers 9.4 Setup 9.5 Events 9.6 Example: Tree Diagram 9.7 Case Study: Using SAX with the Day Planner Application 9.8 SAX 2.0. 9.1 Introduction. SAX Simple API for XML
E N D
Chapter 9 – Simple API for XML (SAX) Outline9.1 Introduction9.2 DOM vs. SAX9.3 SAX-based parsers9.4 Setup9.5 Events9.6 Example: Tree Diagram9.7 Case Study: Using SAX with the Day Planner Application9.8 SAX 2.0
9.1 Introduction • SAX • Simple API for XML • Another method for accessing XML document’s contents • Developed by XML-DEV mailing-list members • Uses event-based model • Notifications (events) are raised as document is parsed
9.2 DOM vs. SAX • DOM • Tree-based model • Stores document data in node hierarcy • Data is accessed quickly • Provides facilities for adding and removing nodes • SAX • Invoke methods when markup (specific tag) is encountered • Greater performance than DOM • Less memory overhead than DOM • Typically used for reading documents (not modifying them)
9.3 SAX-based Parsers • SAX-based parsers • Available for variety of programming languages • e.g., Java, Python, etc. • We use Sun Microsystem’s JAXP
9.4 Setup • Java applications to illustrate SAX API • Java 2 Standard Edition required • Download at www.java.sun.com/j2se • Installation instructions • www.deitel.com/faq/java3install.htm • JAXP required • Download at java.sun.com/xml/download.html
9.5 Events • SAX parser • Invokes certain methods (Fig. 9.2) when events occur • Programmers override these methods to process data
9.6 Example: Tree Diagram • Java application • Parse XML document with SAX-based parser • Output document data as tree diagram • extendsorg.xml.sax.HandlerBase • implements interface EntityResolver • Handles external entities • implements interface DTDHandler • Handles notations and unparsed entities • implements interface DocumentHandler • Handles parsing events • implements interface ErrorHandler • Handles errors
1 // Fig. 9.3 : Tree.java 2 // Using the SAX Parser to generate a tree diagram. 3 import specifies location of classes needed by application 4 import java.io.*; 5 import org.xml.sax.*; // for HandlerBase class 6 import javax.xml.parsers.SAXParserFactory; Assists in formatting 7 import javax.xml.parsers.ParserConfigurationException; 8 import javax.xml.parsers.SAXParser; 9 Override method to output parsed document’s URL 10 public class Tree extends HandlerBase { 11 private int indent = 0; // indentation counter 12 13 // returns the spaces needed for indenting 14 private String spacer( int count ) 15 { 16 String temp = ""; 17 18 for ( int i = 0; i < count; i++ ) 19 temp += " "; 20 21 return temp; 22 } 23 24 // method called before parsing 25 // it provides the document location 26 public void setDocumentLocator( Locator loc ) 27 { 28 System.out.println( "URL: " + loc.getSystemId() ); 29 } 30 Fig. 9.3 Application to create a tree diagram for an XML document.import specifies location of classes needed by applicationAssists in formattingOverride method to output parsed document’s URL
31 // method called at the beginning of a document Overridden method called when root node encountered 32 public void startDocument() throws SAXException 33 { Overridden method called when end of document is encountered 34 System.out.println( "[ document root ]" ); 35 } 36 Overridden method called when start tag is encountered 37 // method called at the end of the document 38 public void endDocument() throws SAXException Output each attribute’s name and value (if any) 39 { 40 System.out.println( "[ document end ]" ); 41 } 42 43 // method called at the start tag of an element 44 public void startElement( String name, 45 AttributeList attributes ) throws SAXException 46 { 47 System.out.println( spacer( indent++ ) + 48 "+-[ element : " + name + " ]"); 49 50 if ( attributes != null ) 51 52 for ( int i = 0; i < attributes.getLength(); i++ ) 53 System.out.println( spacer( indent ) + 54 "+-[ attribute : " + attributes.getName( i ) + 55 " ] \"" + attributes.getValue( i ) + "\"" ); 56 } 57 Fig. 9.3 Application to create a tree diagram for an XML document. (Part 2)Overridden method called when root node encounteredOverridden method called when end of document is encounteredOverridden method called when start tag is encounteredOutput each attribute’s name and value (if any)
58 // method called at the end tag of an element 59 public void endElement( String name ) throws SAXException Overridden method called when end of element is encountered 60 { 61 indent--; Overridden method called when processing instruction is encountered 62 } 63 64 // method called when a processing instruction is found Overridden method called when character data is encountered 65 public void processingInstruction( String target, 66 String value ) throws SAXException 67 { 68 System.out.println( spacer( indent ) + 69 "+-[ proc-inst : " + target + " ] \"" + value + "\"" ); 70 } 71 72 // method called when characters are found 73 public void characters( char buffer[], int offset, 74 int length ) throws SAXException 75 { 76 if ( length > 0 ) { 77 String temp = new String( buffer, offset, length ); 78 79 System.out.println( spacer( indent ) + 80 "+-[ text ] \"" + temp + "\"" ); 81 } 82 } 83 Fig. 9.3 Application to create a tree diagram for an XML document. (Part 3)Overridden method called when end of element is encounteredOverridden method called when processing instruction is encounteredOverridden method called when character data is encountered
84 // method called when ignorable whitespace is found 85 public void ignorableWhitespace( char buffer[], 86 int offset, int length ) 87 { 88 if ( length > 0 ) { 89 System.out.println( spacer( indent ) + "+-[ ignorable ]" ); 90 } Overridden method called when ignorable whitespace is encountered Overridden method called when error (usually validation) occurs Overridden method called when problem is detected (but not considered error) 91 } 92 93 // method called on a non-fatal (validation) error Method main starts application 94 public void error( SAXParseException spe ) 95 throws SAXParseException 96 { 97 // treat non-fatal errors as fatal errors 98 throw spe; 99 } 100 101 // method called on a parsing warning 102 public void warning( SAXParseException spe ) 103 throws SAXParseException 104 { 105 System.err.println( "Warning: " + spe.getMessage() ); 106 } 107 108 // main method 109 public static voidmain( String args[] ) 110 { 111 boolean validate = false; 112 Fig. 9.3 Application to create a tree diagram for an XML document. (Part 4)Overridden method called when ignorable whitespace is encounteredOverridden method called when error (usually validation) occursOverridden method called when problem is detected (but not considered error)Method main starts application
113 if ( args.length != 2 ) { 114 System.err.println( "Usage: java Tree [validate] " + 115 "[filename]\n" ); 116 System.err.println( "Options:" ); Allow command-line arguments (if we want to validate document) 117 System.err.println( " validate [yes|no] : " + 118 "DTD validation" ); 119 System.exit( 1 ); 120 } SAXParserFactory can instantiate SAX-based parser 121 122 if ( args[ 0 ].equals( "yes" ) ) 123 validate = true; 124 125 SAXParserFactory saxFactory = 126 SAXParserFactory.newInstance(); 127 128 saxFactory.setValidating( validate ); 129 Fig. 9.3 Application to create a tree diagram for an XML document. (Part 5)Allow command-line arguments (if we want to validate document)SAXParserFactory can instantiate SAX-based parser
130 try { 131 SAXParser saxParser = saxFactory.newSAXParser(); 132 saxParser.parse( new File( args[ 1 ] ), new Tree() ); Instantiate SAX-based parser 133 } 134 catch ( SAXParseException spe ) { 135 System.err.println( "Parse Error: " + spe.getMessage() ); Handles errors (if any) 136 } 137 catch ( SAXException se ) { 138 se.printStackTrace(); 139 } 140 catch ( ParserConfigurationException pce ) { 141 pce.printStackTrace(); 142 } 143 catch ( IOException ioe ) { 144 ioe.printStackTrace(); 145 } 146 147 System.exit( 0 ); 148 } 149 } Fig. 9.3 Application to create a tree diagram for an XML document. (Part 6)Instantiate SAX-based parserHandles errors (if any)
1 <?xml version = "1.0"?> XML document does not reference DTD 2 XML document with elements test, example and object 3 <!-- Fig. 9.4 : spacing1.xml --> 4 <!-- Whitespaces in nonvalidating parsing --> Root element test contains attribute name with value “ spacing 1 ” 5 <!-- XML document without DTD --> 6 7 <test name = " spacing 1 "> 8 <example><object>World</object></example> Note that whitespace is preserved: attribute value (line 7), line feed (end of line 7), indentation (line 8) and line feed (end of line 8) 9 </test> Fig. 9.4 XML document spacing1.xml. XML document does not reference DTDXML document with elements test, example and objectRoot element test contains attribute name with value “ spacing 1 ”Note that whitespace is preserved: attribute value (line 7), line feed (end of line 7), indentation (line 8) and line feed (end of line 8) URL: file:C:/Tree/spacing1.xml[ document root ]+-[ element : test ] +-[ attribute : name ] " spacing 1 " +-[ text ] "" +-[ text ] " " +-[ element : example ] +-[ element : object ] +-[ text ] "World" +-[ text ] ""[ document end ]
1 <?xml version = "1.0"?> 2 DTD checks document’s characters, so any “removable” whitespace is ignorable 3 <!-- Fig. 9.5 : spacing2.xml --> 4 <!-- Whitespace and nonvalidated parsing --> 5 <!-- XML document with DTD --> 6 7 <!DOCTYPE test [ 8 <!ELEMENT test (example)> Line feed at line 14, spaces at beginning of line 15 and line feed at line 15 are ignored 9 <!ATTLIST test name CDATA #IMPLIED> 10 <!ELEMENT element (object*)> 11 <!ELEMENT object(#PCDATA)> 12 ]> 13 14 <test name = " spacing 2 "> 15 <example><object>World</object></example> 16 </test> Fig. 9.5 XML document spacing2.xml.DTD checks document’s characters, so any “removable” whitespace is ignorableLine feed at line 14, spaces at beginning of line 15 and line feed at line 15 are ignored URL: file:C:/Tree/spacing2.xml[ document root ]+-[ element : test ] +-[ attribute : name ] " spacing 2 " +-[ ignorable ] +-[ ignorable ] +-[ element : example ] +-[ element : object ] +-[ text ] "World" +-[ ignorable ][ document end ]
1 <?xml version = "1.0"?> Invalid document because element example cannot contain element item 2 3 <!-- Fig. 9.6 : notvalid.xml --> 4 <!-- Validation and non-validation --> 5 6 <!DOCTYPE test [ Validation disabled, so document parses successfully 7 <!ELEMENT test (example)> 8 <!ELEMENT example (#PCDATA)> Parser does not process text in CDATA section and returns character data 9 ]> 10 11 <test> 12 <?test message?> 13 <example><item><![CDATA[Hello & Welcome!]]></item></example> 14 </test> Fig. 9.6 Well-formed XML document.Invalid document because element example cannot contain element itemValidation disabled, so document parses successfullyParser does not process text in CDATA section and returns character data URL: file:C:/Tree/notvalid.xml[ document root ]+-[ element : test ] +-[ ignorable ] +-[ ignorable ] +-[ proc-inst : test ] "message" +-[ ignorable ] +-[ ignorable ] +-[ element : example ] +-[ element : item ] +-[ text ] "Hello & Welcome!" +-[ ignorable ][ document end ]
Validation enabled Parsing terminates when fatal error occurs at element item URL: file:C:/Tree/notvalid.xml[ document root ]+-[ element : test ] +-[ ignorable ] +-[ ignorable ] +-[ proc-inst : test ] "message" +-[ ignorable ] +-[ ignorable ] +-[ element : example ]Parse Error: Element "example" does not allow "item" Fig. 9.6 Well-formed XML document.(Part 2)Validation enabledParsing terminates when fatal error occurs at element item
1 <?xml version = "1.0"?> 2 3 <!-- Fig. 9.7 : valid.xml --> 4 <!-- DTD-less document --> 5 6 <test> Validation disabled in first output, so document parses successfully Validation enabled in second output, and parsing fails because DTD does not exist 7 <example>Hello & Welcome!</example> 8 </test> Fig. 9.7 Checking an XML document without a DTD for validity.Validation disabled in first output, so document parses successfullyValidation enabled in second output, and parsing fails because DTD does not exist URL: file:C:/Tree/valid.xml[ document root ]+-[ element : test ] +-[ text ] "" +-[ text ] " " +-[ element : example ] +-[ text ] "Hello " +-[ text ] "&" +-[ text ] " Welcome!" +-[ text ] ""[ document end ] URL: file:C:/Tree/valid.xml[ document root ]Warning: Valid documents must have a <!DOCTYPE declaration.Parse Error: Element type "test" is not declared.
9.7 Case Study: Using SAX with the Day Planner Application • Use SAX with day-planner application • Reparse document each time query is performed • GUI (Fig. 9.8) • SAXPlanner(Fig. 9.9)
1 // Fig. 9.8: DayPlanner.java 2 // Program for GUI interface for day planner. 3 4 import java.awt.*; 5 import java.awt.event.*; GUI is identical to that of DOM DayPlanner (Fig. 8.18) except for instantiating SAXPlanner instead of DOMPlanner 6 import javax.swing.*; 7 import javax.swing.event.*; 8 9 public class DayPlanner extends JFrame 10 implements ActionListener { 11 12 // GUI components 13 private JTextArea display; 14 private JComboBox year, month, day, time; 15 private JButton query; 16 private JPanel panel1, panel2; 17 private SAXPlanner handler; 18 19 public DayPlanner() 20 { 21 super( "Day planner using SAX" ); 22 23 // set the output font 24 Font font = new Font( "Monospaced", 25 java.awt.Font.BOLD, 16 ); 26 display = new JTextArea(); 27 display.setFont( font ); 28 display.setEditable( false ); 29 Fig. 9.8 User interface for a day-planning application.GUI is identical to that of DOM DayPlanner (Fig. 8.18) except for instantiating SAXPlanner instead of DOMPlanner
30 handler = new SAXPlanner( display ); 31 32 // initialize the user interface components 33 year = new JComboBox( handler.getYears() ); Instantiate SAXPlanner object 34 35 String months[] = new String[ 13 ]; 36 months[ 0 ] = "ANY"; 37 38 for ( int i = 1; i < 13; i++ ) 39 months[ i ] = "" + ( i ); 40 41 month = new JComboBox( months ); 42 43 String days[] = new String[ 32 ]; 44 days[ 0 ] = "ANY"; 45 46 for ( int i = 1; i < 32; i++ ) 47 days[ i ] = "" + ( i ); 48 49 day = new JComboBox( days ); 50 51 String times[] = { "ANY", "Morning", "Afternoon", 52 "Evening", "Night" }; 53 time = new JComboBox( times ); 54 55 query = new JButton( "Get Schedules" ); 56 query.addActionListener( this ); 57 Fig. 9.8 User interface for a day-planning application. (Part 2)Instantiate SAXPlanner object
58 // panel containing components for querying 59 panel1 = new JPanel(); 60 panel1.setLayout( new GridLayout( 4, 2 ) ); 61 panel1.add( new JLabel( "Year" ) ); 62 panel1.add( year ); 63 panel1.add( new JLabel( "Month" ) ); 64 panel1.add( month ); 65 panel1.add( new JLabel( "Day" ) ); 66 panel1.add( day ); 67 panel1.add( new JLabel("Time") ); 68 panel1.add( time ); 69 70 // panel containing text area for output 71 // and panel2 containing other GUI components 72 panel2 = new JPanel(); 73 panel2.setLayout( new GridLayout( 1, 2 ) ); 74 panel2.add( panel1 ); 75 panel2.add( query ); 76 77 Container c = getContentPane(); 78 c.setLayout( new BorderLayout() ); 79 c.add( new JScrollPane( display ), BorderLayout.CENTER ); 80 c.add( panel2, BorderLayout.SOUTH ); 81 setSize( 600, 450 ); 82 show(); 83 } 84 Fig. 9.8 User interface for a day-planning application. (Part 3)
85 // method executed when query button is pressed 86 public void actionPerformed( ActionEvent e ) 87 { 88 if ( e.getSource() == query ) { 89 int yearIndex, monthIndex, dayIndex, timeIndex; 90 91 // get the integer values of all the query parameters 92 yearIndex = 93 getIntegerValue( ( String ) year.getSelectedItem() ); 94 monthIndex = 95 getIntegerValue( ( String ) month.getSelectedItem() ); 96 dayIndex = 97 getIntegerValue( ( String ) day.getSelectedItem() ); 98 timeIndex = time.getSelectedIndex() - 1; 99 100 // get the result of query 101 handler.getQueryResult( yearIndex, monthIndex, 102 dayIndex, timeIndex ); 103 } 104 } 105 Fig. 9.8 User interface for a day-planning application. (Part 4)
106 // method to convert the string value to integer 107 public int getIntegerValue( String str ) 108 { 109 110 // if ANY value is selected, return -1 111 if ( str.equals( "ANY" ) ) 112 return -1; 113 else 114 return Integer.parseInt( str ); 115 } 116 117 public static void main( String s[] ) 118 { 119 DayPlanner d = new DayPlanner(); 120 d.addWindowListener( 121 122 new WindowAdapter() 123 { 124 public void windowClosing( WindowEvent e ) 125 { 126 System.exit( 0 ); 127 } 128 } 129 ); 130 } 131 } Fig. 9.8 User interface for a day-planning application. (Part 5)
132 // Fig. 9.9 : SAXPlanner.java 133 // Using the JAXP Parser to retrieve schedules 134 135 import java.io.*; 136 import java.util.*; 137 import javax.swing.*; 138 import org.xml.sax.*; 139 import javax.xml.parsers.SAXParserFactory; Used for storing processed data 140 import javax.xml.parsers.ParserConfigurationException; Used for storing search data 141 import javax.xml.parsers.SAXParser; 142 Used for tracking current location within XML document 143 public class SAXPlanner extends HandlerBase { 144 145 // variables used for parsing 146 private File fileXML; 147 private SAXParserFactory saxFactory; 148 149 // variables used for returning data 150 privatestatic String strYear, strOutput; 151 152 // variables used for querying 153 private static int queryYear = -1; 154 private static int queryMonth = -1; 155 private static int queryDay = -1; 156 private static int queryTime = -1; 157 158 // variables used for node state 159 private boolean boolYear, boolDate, boolNote; 160 Fig. 9.9 Day-planning application with SAX .Used for storing processed dataUsed for storing search dataUsed for tracking current location within XML document
161 // variables used for information state 162 private int currYear, currMonth, currDay, currTime; Used for storing current date and time 163 164 // variable for display Constructor sets planner.xml as XML document to be parsed 165 private JTextArea display; 166 167 public SAXPlanner(){} 168 Initialize strYear and strOutput to empty Strings when root element is encountered 169 public SAXPlanner( JTextArea output ) 170 { 171 display = output; 172 173 // the XML document needed is "planner.xml" 174 init( "planner.xml" ); 175 } 176 177 public void startDocument() throws SAXException 178 { 179 strYear = ""; 180 strOutput = ""; 181 } 182 Fig. 9.9 Day-planning application with SAX . (Part 2)Used for storing current date and timeConstructor sets planner.xml as XML document to be parsedInitialize strYear and strOutput to empty Strings when root element is encountered
183 public void startElement( String name, Process document elements 184 AttributeList attributes ) throws SAXException If year element, process year element 185 { Store years available in document 186 if ( name.equals( "year" ) ) { 187 currYear = 188 Integer.parseInt( attributes.getValue( 0 ) ); Allow date elements (in year element) to be processed if year matches query 189 190 strYear += attributes.getValue( 0 ) + " "; If date element, process date element 191 Retrieve month and day attributes 192 boolYear = false; 193 boolDate = false; 194 boolNote = false; 195 196 // check the elements within this year 197 if ( queryYear == -1 || queryYear == currYear ) 198 boolYear = true; 199 200 } 201 else if ( boolYear && name.equals( "date" ) ) { 202 currMonth = 203 Integer.parseInt( attributes.getValue( 0 ) ); 204 currDay = 205 Integer.parseInt( attributes.getValue( 1 ) ); 206 207 boolDate = false; 208 boolNote = false; 209 Fig. 9.9 Day-planning application with SAX . (Part 3)Process document elementsIf year element, process year elementStore years available in documentAllow date elements (in year element) to be processed if year matches query If date element, process date element Retrieve month and day attributes
210 if ( ( queryMonth == -1 || queryMonth == currMonth ) && Allow month and day attributes to be processed if they match query 211 ( queryDay == -1 || queryDay == currDay ) ) { 212 213 // check the elements within this date 214 boolDate = true; Retrieve attribute time 215 } 216 } Allow attribute time element to be processed if time matches query 217 else if ( boolDate && name.equals( "note" ) ) { If note element, process note element 218 219 if ( attributes.getValue( 0 ) != null ) 220 currTime = 221 Integer.parseInt( attributes.getValue( 0 ) ); 222 else 223 currTime = -1; 224 225 boolNote = false; 226 227 switch ( queryTime ) { 228 229 case 0: 230 231 if ( currTime >= 500 && currTime < 1200 ) 232 boolNote = true; 233 234 break; 235 236 case 1: 237 Fig. 9.9 Day-planning application with SAX . (Part 4)Allow month and day attributes to be processed if they match queryIf note element, process note elementRetrieve attribute timeAllow attribute time element to be processed if time matches query
238 if ( currTime >= 1200 && currTime < 1800 ) 239 boolNote = true; 240 241 break; 242 243 case 2: 244 245 if ( currTime >= 1800 && currTime < 2100 ) 246 boolNote = true; 247 248 break; 249 250 case 3: 251 252 if ( currTime >= 2100 && currTime < 500 ) 253 boolNote = true; 254 255 break; 256 257 default: 258 boolNote = true; 259 } 260 261 if ( currTime == -1 ) 262 boolNote = true; 263 } 264 } 265 Fig. 9.9 Day-planning application with SAX . (Part 5)
266 public void characters( char buffer[], int offset, Process character data only if boolNote is true 267 int length ) throws SAXException 268 { 269 if ( boolNote ) { 270 String value = new String( buffer, offset, length ); Use current date and time for strOutput, which GUI displays 271 value = value.trim(); 272 273 if ( !value.equals( "" ) ) { 274 strOutput += "\nDATE: D " + currDay + " M " + Overridden method called if error occurs 275 currMonth + " Y " + currYear + "\n"; 276 277 if ( currTime != -1 ) 278 strOutput += "TIME: " + currTime + " > " + 279 value + "\n"; 280 else 281 strOutput += "ALL DAY > " + value + "\n"; 282 283 strOutput += "* * * * * * * * * *"; 284 } 285 } 286 } 287 288 public void error( SAXParseException spe ) 289 throws SAXParseException 290 { 291 throw spe; 292 } 293 Fig. 9.9 Day-planning application with SAX . (Part 6)Process character data only if boolNote is trueUse current date and time for strOutput, which GUI displaysOverridden method called if error occurs
294 public void warning( SAXParseException spe ) Overridden method called if problem is detected 295 throws SAXParseException 296 { 297 System.err.println( "Warning: " + spe.getMessage() ); Sets file to be parsed and obtain SAX-based validating parser 298 } 299 Returns String array containing day-planner document’s years 300 public void init( String filename ) 301 { 302 fileXML = new File( filename ); 303 saxFactory = SAXParserFactory.newInstance(); 304 saxFactory.setValidating( true ); 305 } 306 307 public String[] getYears() 308 { 309 String buffer[]; 310 StringTokenizer tokens; 311 int i; 312 313 try { 314 315 // parse the file 316 SAXParser saxParser = saxFactory.newSAXParser(); 317 saxParser.parse( fileXML, new SAXPlanner() ); 318 } 319 catch ( SAXParseException spe ) { 320 Fig. 9.9 Day-planning application with SAX . (Part 7)Overridden method called if problem is detectedSets file to be parsed and obtain SAX-based validating parser Returns String array containing day-planner document’s years
321 // parser error 322 System.out.println( "Parse Error: " + 323 spe.getMessage() ); 324 } 325 catch ( Exception e ) { 326 e.printStackTrace(); 327 } 328 329 tokens = new StringTokenizer( strYear ); Call method getResult to process XML document (output query result) 330 331 buffer = new String[ tokens.countTokens() + 1 ]; 332 buffer[ 0 ] = "ANY"; 333 i = 1; 334 335 while ( tokens.hasMoreTokens() ) 336 buffer[ i++ ] = tokens.nextToken(); 337 338 return buffer; 339 } 340 341 public void getQueryResult( int year, int month, 342 int day, int time ) 343 { 344 queryYear = year; 345 queryMonth = month; 346 queryDay = day; 347 queryTime = time; 348 display.setText( "*** YOUR DAY PLANNER ***" ); 349 display.append( getResult() ); 350 } 351 Fig. 9.9 Day-planning application with SAX . (Part 8)Call method getResult to process XML document (output query result)
352 public String getResult() 353 { 354 try { Parsing XML document outputs result 355 356 // parse the file 357 SAXParser saxParser = saxFactory.newSAXParser(); 358 359 saxParser.parse( fileXML, new SAXPlanner() ); 360 } 361 catch( SAXParseException spe ) { 362 363 // parser error 364 System.err.println( "Parse Error: " + 365 spe.getMessage() ); 366 spe.printStackTrace(); 367 368 } 369 catch ( Exception e ) { 370 e.printStackTrace(); 371 } 372 373 return strOutput; 374 } 375 } Fig. 9.9 Day-planning application with SAX . (Part 9)Parsing XML document outputs result
9.8 SAX 2.0 • SAX 2.0 • Recently released • We have been using JAXP • JAXP supports only SAX 1.0 (currently) • Xerces parser (Apache) supports SAX 2.0
9.8 SAX 2.0 (cont.) • SAX 2.0 major changes • Class HandlerBase replaced with DefaultHandler • Element and attribute processing support namespaces • Loading and parsing processes has changed • Methods for retrieving and setting parser properties • e.g., whether parser performs validation
1 // Fig. 9.10 : printXML.java 2 // Using the SAX Parser to indent an XML document. 3 4 import java.io.*; Replace class HandlerBase with class DefaultHandler 5 import org.xml.sax.*; 6 import org.xml.sax.helpers.*; 7 import javax.xml.parsers.SAXParserFactory; 8 import javax.xml.parsers.ParserConfigurationException; 9 import javax.xml.parsers.SAXParser; 10 Provides same service as that of SAX 1.0 11 publicclass PrintXML extends DefaultHandler { 12 privateint indent = 0; // indention counter 13 14 // returns the spaces needed for indenting 15 private String spacer( int count ) 16 { 17 String temp = ""; 18 19 for ( int i = 0; i < count; i++ ) 20 temp += " "; 21 22 return temp; 23 } 24 25 // method called at the beginning of a document 26 publicvoid startDocument() throws SAXException 27 { 28 System.out.println( "<?xml version = \"1.0\"?>" ); 29 } 30 Fig. 9.10 Java application that indents an XML document.Replace class HandlerBase with class DefaultHandlerProvides same service as that of SAX 1.0
31 // method called at the end of the document 32 publicvoid endDocument() throws SAXException 33 { 34 System.out.println( "---[ document end ]---" ); Method startElement now has four arguments (namespace URI, element name, qualified element name and element attributes) 35 } 36 37 // method called at the start tag of an element Attributes are now stored in Attributes object 38 publicvoid startElement( String uri, String eleName, Method endElement now has three arguments (namespace URI, element name and qualified element name) 39 String raw, Attributes attributes ) throws SAXException 40 { Provides same service as that of SAX 1.0 41 42 System.out.print( spacer( indent ) + "<" + eleName ); 43 44 if ( attributes != null ) 45 46 for ( int i = 0; i < attributes.getLength(); i++ ) 47 System.out.print( " "+ attributes.getLocalName( i ) + 48 " = " + "\"" + 49 attributes.getValue( i ) + "\"" ); 50 System.out.println( ">" ); 51 indent += 3; 52 } 53 54 // method called at the end tag of an element 55 publicvoid endElement( String uri, String eleName, 56 String raw ) throws SAXException 57 { 58 indent -= 3; 59 System.out.println( spacer(indent) + "</" + eleName + ">"); 60 } 61 Fig. 9.10 Java application that indents an XML document. (Part 2)Provides same service as that of SAX 1.0Method startElement now has four arguments (namespace URI, element name, qualified element name and element attributes)Attributes are now stored in Attributes objectMethod endElement now has three arguments (namespace URI, element name and qualified element name)
62 // method called when characters are found 63 publicvoid characters( char buffer[], int offset, 64 int length ) throws SAXException 65 { 66 if ( length > 0 ) { 67 String temp = new String( buffer, offset, length ); 68 69 if ( !temp.trim().equals( "" ) ) 70 System.out.println( spacer(indent) + temp.trim() ); 71 } Provides same service as that of SAX 1.0 Provides same service as that of SAX 1.0 72 } 73 74 // method called when a processing instruction is found 75 publicvoid processingInstruction( String target, 76 String value ) throws SAXException 77 { 78 System.out.println( spacer( indent ) + 79 "<?" + target + " " + value + "?>"); 80 } 81 82 // main method 83 public static void main( String args[] ) 84 { 85 Fig. 9.10 Java application that indents an XML document. (Part 3)Provides same service as that of SAX 1.0Provides same service as that of SAX 1.0
86 try { 87 XMLReader saxParser = ( XMLReader ) Class.forName( 88 "org.apache.xerces.parsers.SAXParser" ).newInstance(); Create Xerces SAX-based parser 89 SAX-based parser parses InputSource 90 saxParser.setContentHandler( new PrintXML() ); 91 FileReader reader = new FileReader( args[ 0 ] ); 92 saxParser.parse( new InputSource( reader ) ); 93 } 94 catch ( SAXParseException spe ) { 95 System.err.println( "Parse Error: " + spe.getMessage() ); 96 } 97 catch ( SAXException se ) { 98 se.printStackTrace(); 99 } 100 catch ( Exception e ) { 101 e.printStackTrace(); 102 } 103 104 System.exit( 0 ); 105 } 106 } Fig. 9.10 Java application that indents an XML document. (Part 4)Create Xerces SAX-based parserSAX-based parser parses InputSource
1 <?xml version = "1.0"?> 2 3 <!-- Fig. 9.11 : test.xml --> 4 Processing instruction that links to stylesheet 5 <?xml:stylesheet type = "text/xsl" href = "something.xsl"?> 6 7 <test> 8 <example value = "100">Hello and Welcome!</example> 9 10 <a> 11 <b>12345</b> 12 </a> 13 </test> Fig. 9.11 Sample execution of printXML.javaProcessing instruction that links to stylesheet Output <?xml version = "1.0"?> <?xml:stylesheet type = "text/xsl" href = "something.xsl"?> <test> <example value = "100"> Hello and Welcome! </example> <a> <b> 12345 </b> </a> </test> ---[ document end ]---