In our context, a DOM application is a Java application that implements the javax.xml.parsers and org.w3c.dom packages to process an XML document by creating a DOM from it. You will create such an application and call it MyDOMHandler.java. The XML file you will use is the same CarParts.xml file that we used to explain the workings of a SAX parser. The CarParts.xml File The CarParts.xml file is displayed in Listing 5.2. Listing 5.2 The CarParts.xml File<?xml version='1.0' encoding='us-ascii'?> <!-- XML file that describes car parts --> <!DOCTYPE carparts SYSTEM "CarParts.dtd" [ <!ENTITY companyname "Heaven Car Parts (TM)"> <!ENTITY companyweb "http://carpartsheaven.com"> ]> <carparts> <?supplierformat format="X13" version="3.2"?> <supplier name="&companyname;" URL="&companyweb;"> &companyname; </supplier> <engines> <engine type="Alpha37" capacity="2500" price="3500"> Engine 1 </engine> <engine type="Beta37" capacity="2500" price="4500"> Engine 2 </engine> </engines> <carbodies> <carbody type="Tallboy" color="blue"> Car Body 1 </carbody> </carbodies> <wheels> <wheel type="X3527" price="120"> Wheel Set 1 </wheel> </wheels> <carstereos> <carstereo manufacturer="MagicSound" model="T76w" Price="500"> Car Stereo 1 </carstereo> </carstereos> <forCDATA><![CDATA[Special Text: <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>SAMS Publishing is the &best& <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>..]]> </forCDATA> </carparts> The corresponding DTD, CarParts.dtd, is shown in Listing 5.3. Listing 5.3 The CarParts.dtd File<?xml version='1.0' encoding='us-ascii'?> <!-- DTD for the XML file that describes car parts --> <!ELEMENT carparts (supplier,engines,carbodies,wheels,carstereos,forCDATA)> <!ELEMENT engines (engine+)> <!ELEMENT carbodies (carbody+)> <!ELEMENT wheels (wheel+)> <!ELEMENT carstereos (carstereo+)> <!ELEMENT forCDATA (CDATA)> <!ELEMENT supplier (#PCDATA)> <!ATTLIST supplier name CDATA #REQUIRED URL CDATA #REQUIRED > <!ELEMENT engine (#PCDATA)*> <!ATTLIST engine id CDATA #REQUIRED type CDATA #REQUIRED capacity (1000 | 2000 | 2500 ) #REQUIRED price CDATA #IMPLIED text CDATA #IMPLIED > <!ELEMENT carbody (#PCDATA)*> <!ATTLIST carbody id CDATA #REQUIRED type CDATA #REQUIRED color CDATA #REQUIRED > <!ELEMENT wheel (#PCDATA)*> <!ATTLIST wheel id CDATA #REQUIRED type CDATA #REQUIRED price CDATA #IMPLIED size (X | Y | Z) #IMPLIED > <!ELEMENT carstereo (#PCDATA)*> <!ATTLIST carstereo id CDATA #REQUIRED manufacturer CDATA #REQUIRED model CDATA #REQUIRED Price CDATA #REQUIRED > Sequence of Steps in Implementing a DOM Parser The sequence of steps to implement a DOM parser in an application is as follows: -
Import the JAXP and other packages and classes. -
Declare the Document object. Whenever you parse (or create) an XML document using DOM, an instance of the Document class is created. -
Get an instance of the DocumentBuilderFactory class. -
Get an instance of the DocumentBuilder class. This class is the parser, and is created by using the newDocumentBuilder() method of the DocumentBuilderFactory class. -
Provide an error-handling mechanism. This is required to trap and gracefully handle errors that might be generated while parsing an XML file using DOM APIs. -
Provide the XML document to parse. Importing the JAXP Classes Let's begin writing the MyDOMHandler.java application. MyDOMHandler is a simple application that parses the CarParts.xml file and handles the errors generated during the DOM creation and document-parsing process. The first step is to import the classes necessary for the application to access the JAXP and DOM APIs. In the MyDOMHandler.java file, add the following lines: import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import java.io.File; import java.io.IOException; import org.w3c.dom.*; import org.xml.sax.ErrorHandler; DocumentBuilder, DocumentBuilderFactory, FactoryConfigurationError and ParserConfigurationException are the JAXP classes that enable an application to get a DOM parser and handle related errors. The next two in the list are SAXException and SAXParseException. You might wonder what role they have in a DOM application. They have been included because the JAXP specification requires that a document builder throw SAX exceptions when it has problems parsing an XML document. Therefore, these two classes are imported to handle the SAX exceptions. Next, the File and IOException classes are imported to handle the task of reading the XML file, and to handle errors related to I/O tasks. Finally, the classes in the org.w3c.dom package provide the necessary APIs for working with DOM. The ErrorHandler class enables the application to provide an error-handling mechanism for the validation errors and warnings. Because the JAXP-compliant parsers throw SAX exceptions, the error-handling mechanism is very similar to the ones implemented in the SAX applications. After importing the packages, the next step is to provide the class declaration and create the Document object. Creating the MyDOMHandler Class Declaration To create the MyDOMHandler class declaration, enter the following line of code: public class MyDOMHandler { Next, create a reference to the Document object. To do so, enter the following line of code: static Document document; Finally, enter the main() method for the application by entering the following lines of code: public static void main(String argv[]) { } So far, you have imported the necessary classes and provided the class declaration. The next step is to access the DOM parser. Accessing the DOM Parser To set up the DOM parser, add the following bold lines of code in the main() method: public static void main(String argv[]) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); System.out.println("\n----------------- Creating the DOM from the CarParts.xml File ---------- \n"); document = builder.parse( new File("CarParts.xml") ); System.out.println("\n----------------- DOM Created from the CarParts.xml file ---------- \n"); }//End of main First, an instance of the DocumentBuilderFactory is obtained. Next, using the newDocumentBuilder() method of the DocumentBuilderFactory instance, get an instance of DocumentBuilder. Using the parse() method of the DocumentBuilder instance, the parser is informed which XML file to parse. The parse() method returns a Document object, which is stored in the reference to the Document object that was declared earlier. Handling Errors A DOM application might throw errors while trying to parse an XML document. The reasons can be varied, ranging from a malformed XML document, to an inability to create the parser because of some system problems, such as a missing class file. In such cases, the parser generates an error. Three types of errors are generated by the parser: a fatal error, an error, and a warning. It is important to remember that the errors and warnings are generated only when the validating mode is switched on for the parser and a DTD is being used. In a nonvalidating mode, only the fatal errors are reported. A fatal error occurs when the parser is unable to continue the parsing of the XML document. An error occurs when the XML document fails the validity constraint, because of a problem such as the presence of an invalid tag. A warning is generated when there is a problem that, although not illegal in XML, might have occurred inadvertently. For example, a tag might have been defined twice in the DTD. Depending on the type of error, the parser throws one of the following exceptions: SAXException and SAXParseException are thrown when the parser finds an error in the XML file. The SAXParserFactory class generates ParserConfigurationException if it fails to create a parser. To handle such errors, you need to provide an exception-handling mechanism that can handle them. Creating a class that implements the ErrorHandler interface and registering that class with the DOM parser provides the necessary error-handling mechanism. The ErrorHandler interface has three methods that need to be defined: fatalError(), error(), and warning(). These three methods handle all possible error scenarios. If you do not provide an ErrorHandler, then all other errors other than the fatal errors are not reported by the parser, and consequently not handled. The MyDOMHandler application needs to be updated with the error handling code. To add the error-handling code, you need to do the following: -
Create a class that implements the ErrorHandler interface. Name the class MyErrorHandler. -
Register the class by using the setErrorHandler() method. -
Put in a try-catch block to catch the exceptions. You need to catch SAXException, SAXParseException, ParserConfigurationException, and IOException to handle all parsing errors. -
Turn on the validating option of the parser. To create the class that implements the ErrorHandler interface, add the following lines listed in bold: }// End of main static class MyErrorHandler implements ErrorHandler { public void fatalError(SAXParseException saxException) { System.out.println("Fatal Error occurred "+ saxException); } public void error(SAXParseException saxException) { System.out.println("Error occurred "+ saxException); } public void warning(SAXParseException saxException) { System.out.println("warning occurred "+ saxException); } } } // End of MyDOMHandler This creates an internal static class MyErrorHandler, which implements the ErrorHandler interface. The three methods of the ErrorHandler interface will handle all the different types of errors that are generated by the DOM parser. Next, the MyErrorHandler is to be registered with the application. To do so, add the line displayed in bold to the application: DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler(new MyErrorHandler()); System.out.println("\n----------------- Creating the DOM from the CarParts.xml File ---------- \n"); document = builder.parse( new File("CarParts.xml") ); System.out.println("\n----------------- DOM Created from the CarParts.xml file ---------- \n"); Next, the try-catch block needs to be added. To do so, add the lines of code displayed in bold: public static void main(String argv[]) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler(new MyErrorHandler()); System.out.println("\n----------------- Creating the DOM from the CarParts. xml File ---------- \n"); document = builder.parse( new File("CarParts.xml") ); System.out.println("\n----------------- DOM Created from the CarParts.xml file ---------- \n"); } catch (SAXParseException saxException) { /* If there are errors in XML data are trapped and location is displayed*/ System.out.println("\n\nError in CarParts.xml at line:"+saxException. getLineNumber()+"("+saxException.getColumnNumber()+")\n"); System.out.println(saxException.toString()); } catch (SAXException saxEx) { /* If there are errors in XML data, the detailed message of the exception is displayed*/ System.out.println(saxEx.getMessage()); } catch (ParserConfigurationException pce) { // Stack trace is printed if the parser with specified options can't be built pce.printStackTrace(); } catch (IOException ioe) { // Stack trace is printed if there is an I/O error ioe.printStackTrace(); } }// End of main Finally, the parser needs to be set to validating. To do so, add the line of code displayed here in bold: public static void main(String argv[]) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); try { ........... The application is now ready to handle the different types of errors that can be generated while parsing the XML file. NOTE The code discussed so far is available in the example0501 folder. This folder also contains the sample CarParts.xml file. Compile and run the application. The output should be similar to the following: ----------------- Creating the DOM from the CarParts.xml File ---------- ----------------- DOM Created from the CarParts.xml file ---------- Don't be surprised that so little is displayed. The important part to remember is that the Document object has been created in the memory. The application can now manipulate the DOM as required. Next, you will update the application to access various data from the DOM created out of the CarParts.xml file. |