As we have already said, Java provides two ways of processing XML: a Java API for XML processing (JAXP), and a Java API for XML binding (JAXB). Both of these APIs are complete in the sense that both fulfill all requirements for XML processing that might be required in any XML application. XML processing applications (such as P2P or Web services applications) will need to use one of them. We will consider Simple Object Access Protocol (SOAP) as an example to elaborate XML processing requirements. Please refer to Chapter 4, "P2P As a Framework for Distributed Computing," where we introduced SOAP, and Chapter 11, "Web Services Explained," where we discussed the structure of SOAP messages and SOAP request/response mechanism. We will use the SOAP request of Listing 12.3 and the response of Listing 12.4 to demonstrate the different capabilities of JAXP. Listing 12.3 SoapRequest.xml: A Simple SOAP Request to Demonstrate XML Authoring with DOM<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns: Listing 12.4 SoapResponse.xml: Sample SOAP Response to Demonstrate SAX and XSL Transformations<?xml version='1.0' encoding='UTF-8'?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"> <SOAP-ENV:Body> <ns1:getFreightResponse xmlns:ns1="urn:FreightCalculationService" SOAP-ENV:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/"> <return xsi:type="xsd:string">5000</return> </ns1:getFreightResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> SOAP Request Authoring Through DOM Using JAXPIn this section, we will describe the XML authoring process by using the DOM-related features of JAXP. We will use Listing 12.3 as a sample SOAP message to demonstrate XML authoring. DOM is a W3C specification. It specifies a way to process XML by representing it as a tree of nodes. Every element, attribute, content, comment, and processing instruction that appears inside an XML file becomes a node. You can traverse through, read, insert, edit, or delete nodes using the DOM specification. We are discussing DOM-related features of JAXP, which is mostly used on the Web server side, or as part of standalone applications. The same DOM specification is also used on the client side (inside a Web browser) to author or process XML. Although we will not discuss DOM inside a Web browser, it is worth noting that Netscape and Microsoft have implemented their own versions of DOM in their browsers. While authoring a SOAP request, we will start from scratch; that is, we do not have any XML file to begin with. We will first create a new empty XML document and then author XML nodes according to the SOAP structure one by one. At the end, we will get the completed XML string, ready to be sent via HTTP (or any other similar transport service). Listing 12.5 is a Java class named SOAPRequest. Look at the constructor. The first three lines are a standard code to create a new empty XML document: DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); ownerDoc = db.newDocument(); You create a new instance of DocumentBuilderFactory; then using the factory, you create a new DocumentBuilder, and finally using the DocumentBuilder, you create a new Document. This is a standard three-step procedure to create an empty XML document. This procedure gives you a reference for the newly created document. The private variable ownerDoc holds this reference for you. Listing 12.5 SOAPRequest.java: SOAP Request Authorimport org.w3c.dom.*; import javax.xml.parsers.*; import org.apache.crimson.tree.XmlDocument; import java.io.*; public class SOAPRequest { // Keeps reference of the complete XML document. private Document ownerDoc; // Keeps reference of the SOAP Envelope element. private Element soapEnvelope; // Keeps reference of the SOAP Body element. private Element soapBody; // We will author SOAPEnvelope // and an empty SOAP Body in the constructor. public SOAPRequest () { try { // Create a Document Builder Factory, // then create a Document Builder using the Factory, // then create a Document using the Builder. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); ownerDoc = db.newDocument(); }//try catch (ParserConfigurationException pce) { System.out.println ("ParserConfigException:"+ pce.getMessage()); }//catch try { // Create the Envelope. soapEnvelope = ownerDoc.createElement("SOAP-ENV:Envelope"); // Set namespaces. soapEnvelope.setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns: The next step is to start authoring the SOAP request. We will perform the common tasks of authoring an envelope and an empty body in the SOAPRequest constructor. This will allow you to later add user-defined structures to the body of your SOAP request. Look at the following lines of code: soapEnvelope = ownerDoc.createElement("SOAP-ENV:Envelope"); soapEnvelope.setAttributeNS ("http://www.w3.org/2000/xmlns/", "SOAP-ENV", "http://schemas. We have used the createElement method of the Document class to author the envelope (SOAP-ENV:Envelope) element. This envelope accompanies three namespace declarations. The next step is to create an empty child element Body that belongs to SOAP-ENV namespace and add it to the envelope. The following three lines accomplish this: soapBody = ownerDoc.createElement ("SOAP-ENV:Body"); soapEnvelope.appendChild(soapBody); doc.appendChild (soapEnvelope); This finishes the constructor in Listing 12.5. Listing 12.6 shows what we have authored in the constructor. Listing 12.6 SoapRequest.xml (partial)<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns: Adding a User-Defined Body to the SOAP RequestThe SOAP request constructor discussed previously creates an envelope and an empty body. The setBodyMethod() method will add the user-defined XML structure to the available empty body. The setBodyMethod() method takes a parameter bodyMethod of type Node. Look at the following two lines of code: Node importedNode = document.importNode(header, true); soapEnvelope.appendChild (importedNode); The first line imports the incoming node (bodyMethod) into the document (ownerDoc). This is necessary because the bodyMethod node will be supplied by other Java classes that will use SOAPRequest. Therefore, it will always belong to some other owner Document. The second line simply appends the newly imported child to the soapBody node. The rest of the lines in setBodyMethod() are only for demonstration. They are meant to save the authored XML structure as an XML file, so you can see what has been authored. The completed XML structure will look like Listing 12.3. How to Use the SOAP Request ClassOur SOAPRequest class is supposed to be a reusable component. It can be used inside a JFC/Swing application, or as a server-side component. But in order to keep Listing 12.5 simple, we have included a main() method within the SOAPRequest class. The main() method demonstrates the use of the constructor and setBodyMethod() for SOAP request authoring. It instantiates the SOAPRequest class, authors a new node, and passes it to setBodyMethod(). SOAP Response Processing Through Simple APIs for XML (SAX) Using JAXPSAX is a W3C specification. It was originally a Java-only API, the first widely accepted API for XML in Java. SAX represents an XML file (for example, a SOAP message) as a sequence of events. Every node in an XML document (start and end elements, text, and so on) is taken as an event, and the sequence of events represents an XML file. We have already discussed the use of JAXP DOM in authoring SOAP requests. In response to the request, we will receive another SOAP message, called a SOAP response. We will now demonstrate the use of SAX to process a SOAP response. We will also describe how SAX represents an XML file as a sequence of events, and develop a small Java application. SOAP Response Processing Inside a SOAP ClientRecall the SOAP request and response of Listings 12.3 and 12.4, respectively. Listing 12.4 contains a typical SOAP message that we would expect in response to our request in Listing 12.3. The SOAP response in Listing 12.4 contains the following information:
We would like to extract information out of this SOAP response and present it to the user. HTML is one of the most popular formats for presentation, so we will generate the HTML format after extracting information from the SOAP response. You can use a similar technique to generate other formats, as well. Listing 12.7 is a simple HTML file that we will generate from the SOAP response. This type of application, in which we take an XML file as input, read something from it and generate another format (for example, HTML), is referred to as XML transformation. This example helps to demonstrate what type of SOAP response processing is normally required. Listing 12.7 SoapResponse.html: Sample HTML File Generated by SAX and XSLT<html> <body bgcolor="whitesmoke"> <p align="center"><b> Method Name: getPriceResponse</b> <table> <tr> <td align="right"> Freight:</td> <td>5000</td> </tr> </table> </p> </body> </html> Compare the SOAP response of Listing 12.4 with the HTML file of Listing 12.7 to note the following important points:
We will now see how we accomplish HTML generation from SOAP responses through SAX. Simple API for XML (SAX)The XML structure of Listing 12.4 can be represented by the following SAX events (the order of events is important):
The preceding sequence of events suggests that you can have several types of SAX events in an XML file. The following is a list of the major types of SAX events (some of them don't occur in Listing 12.4):
Whenever you have a transformation requirement from XML to any format (for example, other XML DTDs, HTML, binary format, and so on), this event strategy will always help you. The simplest way of transforming XML through SAX events is to catch the events of your interest, read XML data in that event, and generate the output. Our SOAP response to the HTML transformation requirements can be accomplished through the following strategy:
Listing 12.8 is a Java class (SOAPResponse) that implements this parsing strategy using SAX implementation in JAXP. We will now have a detailed look at the working of SAX in the SOAPResponse class. Listing 12.8 SOAPResponse.java: Uses SAX Parser to Transform SOAP to HTMLimport javax.xml.parsers.*; import org.xml.sax.helpers.*; import org.xml.sax.*; import java.io.*; public class SOAPResponse extends DefaultHandler { //Holds the HTML that we are authoring. private String html="<html>"+ "<body bgcolor=\"whitesmoke\">"+ "<p align=\"center\ Using SAX to Read XML and Transform to Other FormatsThe SOAPResponse constructor takes a File object (this File object represents an XML file). It creates an instance of a SAXParserFactory and then builds a SAXParser using the factory. Once the SAX parser is ready, we can call its parse() method. Have a look at the following lines of code that accomplish this: SAXParserFactory parserfactory = SAXParserFactory.newInstance(); SAXParser parser = parserfactory.newSAXParser(); parser.parse(file,this); The parse() method takes two parameters. The first parameter is the File object that represents our XML file to be parsed. The second parameter is a reference of an object that would receive control whenever a SAX event is detected. We have passed the address of SOAPResponse object (this) as the value of the second parameter. Therefore, SOAPResponse will receive control to handle all SAX events. JAXP requires that classes that will handle SAX events should be derived from the DefaultHandler class. That's why our SOAPResponse class is derived from the DefaultHandler class. Now have a look at the startElement method. It is a SAX event handler, and receives control every time a start element is detected in the XML file being parsed. The parameters passed to this event handler specify the element name and attributes. We have to do three things in this event handler. First, we have to look for the Body element. When Body is found, we'll read the name of its first (and only) child element. Body's first child is the name of a SOAP method response, and should be written in our output HTML. The startElement method will then look for the return element, which is the only grandchild of Body element. When found, we will set the Value flag. The Value flag is used by the characters event handler to decide when to read contents. The characters event handler receives control every time content is detected in an XML file, and the detected content is passed to the event handler. This event handler will only write the content to output HTML if the Value flag is set, which means the content inside Body's grandchild will be written to output HTML. The main() and printHTML() methods in Listing 12.8 are only for demonstration, so you can run this class and save the resulting HTML. Comparing SAX and DOMSAX and DOM both represent the same information, but in different ways. SAX represents an XML document as a sequence of events, while DOM loads an XML file in memory and uses a hierarchical structure (a tree of nodes) to represent XML. SAX does not load the XML data in memory. It keeps on firing events as they occur. Therefore, SAX is more suitable for applications where large XML documents need to be parsed. Limitations of SAXAs we have seen while using JAXP's SAX parser, the order of SAX events corresponds to the XML file being parsed. All SAX events occur in an order that matches the arrangement of nodes in XML. This type of arrangement suits applications where you need to read specific bits of information from an XML file. What if our requirement calls for reading a fragment identifier from an XML file and then jumping to that fragment? The destination fragment might be present prior to its reference. This means we need to jump to a SAX event that has already occurred in the past. This type of requirement is a bit tricky to handle in SAX. DOM-based parsing is more suitable for such applications. XSLT in JAXPUntil now we have been writing Java code (either SAX- or DOM-based) to author, parse, process, or transform XML. But JAXP also allows the use of XSLT to process XML. XSLT code is itself XML, and is much easier to write compared to Java code. In this section we will write an XSLT file that transforms the SOAP response of Listing 12.4 to the HTML of Listing 12.7 (the same task that we accomplished through SAX in the previous section). We will also demonstrate how to use a XSLT stylesheet from within Java code. Most XML transformation tasks can be accomplished through XSLT. JAXP allows the use of XSLT code from within Java applications. Therefore, Java-based P2P applications can employ XSLT for P2P-related XML processing requirements. XSLT at WorkXSLT is an XML-based grammar with which to specify transformation criteria directly in XML format, without needing to write the parsing logic that we wrote while discussing SAX-based transformations. JAXP includes an XSLT engine that can be used from within Java applications to make XSLT files perform XML transformations. Listing 12.9 is an XSLT file that transforms the XML of Listing 12.4 to the HTML of Listing 12.7. This file basically contains three sections. The first section is the root element that contains namespace declarations, and the other two are templates. The first section declares the four namespaces we will use. The first namespace is the XSLT namespace itself. The other three are SOAP namespaces that occur in the SOAP response that we are going to transform. The use of namespaces is quite logical. As the XSLT file itself is XML, the transformation instructions in XSLT are also XML. Namespace declarations are used to identify which tags are part of XSLT code. The second section starts with a template definition: <xsl:template match="SOAP-ENV:Envelope/SOAP-ENV:Body/node()[position()=2]"> The match attribute of this template element is an XPath query. XPath is another W3C specification that is normally used in conjunction with XSLT to specify particular sections within an XML document. The XPath query says: "Find the section in the input XML file in which a SOAP Envelope element is the parent of a SOAP Body (SOAP-ENV:Envelope/SOAP-ENV:Body/). When you have found the SOAP Body, get its second node (node()[position()=2]">)." Body's second child node is the <getFreightResponse> element in the SOAP response (the first is the white space between two elements). Once you have reached the <getFreightResponse> element, you want to output it to the HTML file being authored. The following XSLT code accomplishes this: <xsl:value-of select="local-name(.)"/> The next step is to find the contents of the <return> element. For this purpose, we have another XSLT template element. The following line jumps from one template to another template: <xsl:apply-templates select="return"/> The apply-templates element says "Now is the time to jump to the template whose match attribute matches my select attribute." Look at the second template element (the third section of Listing 12.9): <xsl:template match="return"> This template will output the contents of the <return> element and finish our transformation job. Listing 12.9 XSLT That Transforms a SOAP Response to HTML<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns: How to Use XSLT from Within Java CodeThe use of XSLT files from Java code is very simple in JAXB. The following lines of code accomplish this: TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(new StreamSource(XSLTDocument)); transformer.transform( new StreamSource(XMLDocument), new StreamResult(new FileOutputStream(ResultDocument))); XSLTDocument, XMLDocument, and ResultDocument are three String type objects that specify the names of XSLT, XML, and the resulting output (for example, HTML) files, respectively. First create an instance of TransformerFactory. Then pass the XSLT stream to the newTransformer() method of TransformerFactory. This returns a Transformer object. Then call the transform() method of the Transformer object and pass on the XML stream and a reference to an output stream. The transform() method will generate the output and write it to the output stream. |