Customizing External Entity Resolution So far, you have seen how the SAX parser resolves entities defined within the scope of the document. However, XML specifications provide the capability to refer and use entities that are defined outside the document. For example, an XML document can refer to an external DTD or an external parameter entity. A parameter entity enables an application to reuse parts of a DTD in multiple places in an XML document. This is analogous to general entities, which enable the text to be reused in multiple places in an XML document. Normally, the SAX parser automatically processes the external entities. However, the SAX package provides an interface called EntityResolver, with which an application can implement its own customized handling for external entities. You will now modify the CarParts.xml file and make it refer to an external DTD, as well as change the MyXMLHandler application to provide customized handling for the external entity resolution. The application, on finding the external DTD reference, will redirect it to a DTD description that you will provide in the application code itself. Modifying the CarParts.xml File To make the CarParts.xml file refer to a DTD defined in http://www.carpartsheaven.com/xml/dtds/carparts.dtd, make the change to CarParts.xml as listed in bold in Listing 4.7. Listing 4.7 Adding DOCTYPE to CarParts.xml<?xml version="1.0" encoding='us-ascii'?> <!DOCTYPE carparts SYSTEM "http://www.carpartsheaven.com/xml/dtds/carparts.dtd"> <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> </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> Next, we'll modify the MyXMLHandler application to resolve the reference to the external DTD to the DTD description provided in the application code. This is done by using the EntityResolver interface. Using the EntityResolver The following things need to be done to provide customized external entity resolution: -
Implement the EntityResolver interface. -
Register an instance of the EntityResovler interface with the parser using the setEntityResolver() method. The parser will then permit the application to intercept any external entities before including them. -
Provide the necessary application logic in the resolveEntity() method of the EntityResolver interface. To provide customized external entity resolution in the MyXMLHandler application, do the following: -
Import the StringReader class. The StringReader is required to convert the string that holds the DTD information to an InputSource. -
Create an internal static class called MyEntityResolver that implements EntityResolver. -
Register an instance of the class with the parser. -
Create the DTD structure as a String in the MyEntityResolver class, and define the resolveEntity() method to redirect the parser to use this DTD structure instead of the external DTD reference. First, import the StringReader class. To do so, add the following line listed in bold: import javax.xml.parsers.*; import org.xml.sax.*; import org.xml.sax.helpers.*; import org.xml.sax.ext.LexicalHandler; import java.io.StringReader; Next, create the class that implements the EntityResolver. To do so, add the following lines listed in bold: static class MyErrorHandler implements ErrorHandler { .......... } static class MyEntityResolver implements EntityResolver { public InputSource resolveEntity(java.lang.String publicId, java.lang.String systemId) { } } Next, register the class with the parser. To do so, add the following line listed in bold: static public void main(String[] args) throws Exception { .................... xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", new MyXMLHandler( )); /*Override the entity resolver*/ xmlReader.setEntityResolver(new MyEntityResolver()); /*set the error handler*/ xmlReader.setErrorHandler(new MyErrorHandler()); ...................... } Finally, create the DTD structure as a string in the MyEntityResolver class, and define the resolveEntity() method to redirect the parser to use this DTD structure instead of the external DTD reference. To do so, add the following lines listed in bold in Listing 4.8. Listing 4.8 Implementing EntityResolverstatic class MyEntityResolver implements EntityResolver { static String xmlDTD = "<!ENTITY companyname \"Heaven Car Parts (TM)\">"+ "<!ENTITY companyweb \"http://carpartsheaven.com\">"+ "<!ELEMENT carparts (supplier,engines,carbodies, wheels,carstereos, forCDATA)>"+ "<!ELEMENT engines (engine+)>"+ "<!ELEMENT carbodies (carbody+)>"+ "<!ELEMENT wheels (wheel+)>"+ "<!ELEMENT carstereos (carstereo+)>"+ "<!ELEMENT forCDATA ANY>"+ "<!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"+ ">"; public InputSource resolveEntity(java.lang.String publicId, java.lang.String systemId) { if (systemId.equals ("http://www.carpartsheaven.com/xml/dtds/carparts.dtd")) { System.out.println("Redirecting to local DTD for "+systemId); return new InputSource(new StringReader(xmlDTD)); } else { return null; } } } The xmlDTD string contains the DTD structure for the CarParts.xml document. The resolveEntity() method checks whether the referenced DTD is http://www.carpartsheaven.com/xml/dtds/carparts.dtd, and then redirects the application to use the DTD defined in the application. NOTE The code discussed here is available in the example0403 folder. This folder also contains the sample CarParts.xml file. You can now compile and run the program. The output should be similar to Listing 4.9. The output from the EntityResolver method is listed in bold. Also, the application is now using the DTD defined in the application code itself to validate the CarParts.xml document. Listing 4.9 Output of MyXMLHandler with EntityResolverVersion 0403.0 of MyXMLHandler in example0403 Locator :file:///D:/sams_work/Java Api/Chapter 4- SAX APIs - Advanced Use/example0403/ CarParts.xml Start Document: -----Reading the document CarParts.xml with MyXMLHandler------ Starting DTD :http://www.carpartsheaven.com/xml/dtds/carparts.dtd Redirecting to local DTD for http://www.carpartsheaven.com/xml/dtds/carparts.dtd Starting entity :[dtd] Ending entity :[dtd] Ending DTD Location of event at line number :4 Start Element-> carparts Total Number of Attributes: 0 Location of event at line number :6 Start Element-> supplier Total Number of Attributes: 2 Attribute: name = Heaven Car Parts (TM) Attribute: URL = http://carpartsheaven.com Characters: Starting entity :companyname Characters: Heaven Car Parts (TM) Ending entity :companyname Characters: End Element-> supplier Location of event at line number :9 Start Element-> engines Total Number of Attributes: 0 Location of event at line number :10 Start Element-> engine Price= 3500 Characters: Engine 1 Characters: End Element-> engine End Element-> engines Location of event at line number :14 Start Element-> carbodies Total Number of Attributes: 0 Location of event at line number :15 Start Element-> carbody Total Number of Attributes: 3 Attribute: id = C32 Attribute: type = Tallboy Attribute: color = blue Characters: Car Body 1 Characters: End Element-> carbody End Element-> carbodies Location of event at line number :19 Start Element-> wheels Total Number of Attributes: 0 Location of event at line number :20 Start Element-> wheel Price= 120 Characters: Wheel Set 1 Characters: End Element-> wheel End Element-> wheels Location of event at line number :24 Start Element-> carstereos Total Number of Attributes: 0 Location of event at line number :25 Start Element-> carstereo Total Number of Attributes: 4 Attribute: id = C2 Attribute: manufacturer = MagicSound Attribute: model = T76w Attribute: Price = 500 Characters: Car Stereo 1 Characters: End Element-> carstereo End Element-> carstereos Location of event at line number :29 Start Element-> forCDATA Total Number of Attributes: 0 Starting CDATA Section Characters: Special Text: <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>SAMS Publishing is the &best& <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>.. Ending CDATA Section End Element-> forCDATA End Element-> carparts End Document: ----------------Finished Reading the document------------------- |