WebLogic XML Streaming API
Overview of the WebLogic XML Streaming API
The WebLogic XML Streaming API is used to parse and generate XML documents.
XML documents can be converted into a stream of events, or an XMLInputStream, which which you can methodically step through asking for certain types of events (such as the start of an element), iterate over the attributes of an element, skip ahead in the document, stop processing at any time, get sub-elements of a particular element, and filter out elements as desired. Because you are asking for events rather than reacting to them, using the streaming API is often referred to as pull parsing.
The WebLogic Streaming API uses the WebLogic FastParser as its default parser.
For a complete example of parsing an XML document using the streaming API, see...
$WL_HOME/samples/server/examples/src/examples/xml/orderParser 1The following table describes the main interfaces and classes of the WebLogic Streaming API.
Interface or Class
Description
XMLInputStreamFactory Factory used to create XMLInputStream objects for parsing XML documents. XMLInputStream Interface used to contain the input stream of events. BufferedXMLInputStream Extension of the XMLInputStream interface to allow marking and resetting of the stream. XMLOutputStreamFactory Factory used to create XMLOutputStream objects for generating XML documents. XMLOutputStream Interface used write events. ElementFactory Utility to create instances of the interfaces used in this API. XMLEvent Base interface for all types of events in an XML document, such as the start of an element, the end of an element, and so on. StartElement Most important of the XMLEvent sub-interfaces. Used to get information about a start element in an XML document. AttributeIterator Object used to iterate over the set of attributes of an element. Attribute Object that describes a particular attribute of an element.
Javadocs for the WebLogic XML Streaming API
The following Javadocs provide reference material for the WebLogic XML Streaming API features described in this chapter as well as additional features not explicitly documented:
Parsing an XML Document: Typical Steps
The following procedure describes the typical steps for using the WebLogic XML Streaming API to parse and manipulate an XML document.
The first two steps are required. The next steps you take depend on how you want to process the XML file.
- Import the weblogic.xml.stream.* classes.
- Get an XML stream of events from an XML file, a DOM tree, or a set of SAX events. You can also filter the XML stream to get only certain types of events, names of specific elements, and so on. See Getting an XML Input Stream.
- Iterate over the stream, returning generic XMLEvent types. See Iterating Over the Stream.
- For each generic XMLEvent type, determine the specific event type. Event types include the start of an XML document, the end of an element, an entity reference, and so on. See Determining the Specific XMLEvent Type.
- Get the attributes of an element. See Getting the Attributes of an Element.
- Position the stream by skipping over event, skipping to a particular event, and so on. See Positioning the Stream.
- Get the children of an element. See Getting a Substream.
- Close the stream. See Closing the Input Stream.
Example of Parsing an XML Document
The following program shows an example of using the XML Streaming API to parse an XML document.
The program takes a single parameter, an XML file, that it converts into an XML input stream. It then iterates over the stream, determining the type of each event, such as the start of an XML element, the end of the XML document, and so on. The program prints out information for three types of events: start elements, end elements, and the character data that forms the body of an element. The program does nothing when it encounters the other types of events, such as comments or start of the XML document. Note that the code in bold font is described in detail in the sections following the example.
package examples.xml.stream;import weblogic.xml.stream.Attribute;
import weblogic.xml.stream.AttributeIterator;
import weblogic.xml.stream.ChangePrefixMapping;
import weblogic.xml.stream.CharacterData;
import weblogic.xml.stream.Comment;
import weblogic.xml.stream.XMLEvent;
import weblogic.xml.stream.EndDocument;
import weblogic.xml.stream.EndElement;
import weblogic.xml.stream.EntityReference;
import weblogic.xml.stream.ProcessingInstruction;
import weblogic.xml.stream.Space;
import weblogic.xml.stream.StartDocument;
import weblogic.xml.stream.StartPrefixMapping;
import weblogic.xml.stream.StartElement;
import weblogic.xml.stream.EndPrefixMapping;
import weblogic.xml.stream.XMLInputStream;
import weblogic.xml.stream.XMLInputStreamFactory;
import weblogic.xml.stream.XMLName;
import weblogic.xml.stream.XMLStreamException;import java.io.FileInputStream;
import java.io.FileNotFoundException;public class ComplexParse {/** * Helper method to get a handle on a stream. * Takes in a name and returns a stream. This * method usese the InputStreamFactory to create an * instance of an XMLInputStream * @param name The file to parse * @return XMLInputStream the stream to parse */ public XMLInputStream getStream(String name) throws XMLStreamException, FileNotFoundException { XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); XMLInputStream stream = factory.newInputStream(new FileInputStream(name)); return stream; }/** * Determines the type of event, such as the start * of an element, end of a document, and so on. If the * event is of type START_ELEMENT, END_ELEMENT, or * CHARACTER_DATA, the method prints out appropriate info; * otherwise, it does nothing. * @param event The XML event that has been parsed */ public void parse(XMLEvent event) throws XMLStreamException { switch(event.getType()) { case XMLEvent.START_ELEMENT: StartElement startElement = (StartElement) event; System.out.print("<" + startElement.getName().getQualifiedName() ); AttributeIterator attributes = startElement.getAttributesAndNamespaces(); while(attributes.hasNext()){ Attribute attribute = attributes.next(); System.out.print(" " + attribute.getName().getQualifiedName() + "='" + attribute.getValue() + "'"); } System.out.print(">"); break; case XMLEvent.END_ELEMENT: System.out.print("</" + event.getName().getQualifiedName() +">"); break; case XMLEvent.SPACE: case XMLEvent.CHARACTER_DATA: CharacterData characterData = (CharacterData) event; System.out.print(characterData.getContent()); break; case XMLEvent.COMMENT: // Print comment break; case XMLEvent.PROCESSING_INSTRUCTION: // Print ProcessingInstruction break; case XMLEvent.START_DOCUMENT: // Print StartDocument break; case XMLEvent.END_DOCUMENT: // Print EndDocument break; case XMLEvent.START_PREFIX_MAPPING: // Print StartPrefixMapping break; case XMLEvent.END_PREFIX_MAPPING: // Print EndPrefixMapping break; case XMLEvent.CHANGE_PREFIX_MAPPING: // Print ChangePrefixMapping break; case XMLEvent.ENTITY_REFERENCE: // Print EntityReference break; case XMLEvent.NULL_ELEMENT: throw new XMLStreamException("Attempt to write a null event."); default: throw new XMLStreamException("Attempt to write unknown event ["+event.getType()+"]"); } } /** * Helper method to iterate over a stream * @param name The file to parse */ public void parse(XMLInputStream stream) throws XMLStreamException { while(stream.hasNext()) { XMLEvent event = stream.next(); parse(event); } stream.close(); }/** Main method. Takes a single argument: an XML file * that will be converted into an XML input stream. */ public static void main(String args[]) throws Exception { ComplexParse complexParse= new ComplexParse(); complexParse.parse(complexParse.getStream(args[0])); }
}
Getting an XML Input Stream
You can use the XML Streaming API to convert a variety of objects, such as XML files, DOM trees, or SAX events, into a stream of events.
The following example shows how to create a stream of events from an XML file:
XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance();
XMLInputStream stream = factory.newInputStream(new FileInputStream(name));First you create a new instance of the XMLInputStreamFactory, then use the factory to create a new XMLInputStream from the XML file referred to in the name variable.
The following example shows how to create a stream from a DOM tree:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new java.io.File(file));
XMLInputStream stream = XMLInputStreamFactory.newInstance().newInputStream(doc);
Getting a Buffered XML Input Stream
After you finish iterating over an XMLInputStream object, you cannot access the stream again. If, however, you need to process the stream again, such as send it to another application or iterate over it again in some other way, use a BufferedXMLInputStream object rather than a plain XMlInputStream object.
Use the newBufferedInputStream() method of the XMLInputStreamFactory class to create a buffered XML input stream, as shown in the following example:
XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance();
BufferedXMLInputStream bufstream = factory.newBufferedInputStream(factory.newInputStream(new FileInputStream(name)));You can use the mark() and reset() methods of the BufferedXMLInputStream object to mark a particular spot in the stream, continue processing the stream, then reset the stream back to the marked spot. See Marking and Resetting a Buffered XML Input Stream for more information.
Filtering the XML Stream
Filtering an XML stream refers to creating a stream that contains only specified types of events. For example, you can create a stream that contains only start elements, end elements, and the character data that make up the body of an XML element. Another example is filtering an XML stream so that only elements with a specified name appear in the stream.
To filter an XML stream, you specify a filter class as the second parameter to the XMLInputStreamFactory.newInputStream() method. You specify the events that you want in the XML stream as parameters to the filter class. The following example shows how to use the TypeFilter class to specify that you want only start and end XML elements and character data in the resulting XML stream:
import weblogic.xml.stream.util.TypeFilter;XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance();
XMLInputStream stream = factory.newInputStream(new FileInputStream(name), new TypeFilter(XMLEvent.START_ELEMENT | XMLEvent.END_ELEMENT | XMLEvent.CHARACTER_DATA));
The following table describes the filters provided by the WebLogic XML Streaming API. They are part of the weblogic.xml.stream.util package.
Name of Filter
Description
Sample Usage
TypeFilter Filter an XML stream based on specified event types, such as XMLEvent.START_ELEMENT, XMLEvent.END_ELEMENT, and so on. See Determining the Specific XMLEvent Type for a full list of event types.TypeFilter takes an integer bitmask as input; you OR the values to create this bitmask, as shown in the sample. new TypeFilter (XMLEvent.START_ELEMENT |
XMLEvent.END_ELEMENT |
XMLEvent.CHARACTER_DATA)NameFilter Filter an XML stream based on the name of an element in the XML document. new NameFilter ("Book") NameSpaceFilter Filter an XML stream based on the specified namespace URI. new NameSpaceFilter ("http://namespace.org") NamespaceTypeFilter Filter an XML stream based on specified event types and namespace URI. This filter combines the functionality of TypeFilter and NameSpaceFilter. new NamespaceFilter ("http://namespace.org", XMLEvent.START_ELEMENT)
The example returns a stream where all start elements have the specified namespace.
Creating a Custom Filter
You can also create your own filter if the ones included in the API do not meet your needs.
- Create a class that implements the ElementFilter interface and contains a method called accept(XMLEvent). This method tells the XMLInputStreamFactory.newInputStream() method whether to add a particular event to the stream or not, as shown in the following example:
package my.filters;import weblogic.xml.stream.XMLName;
import weblogic.xml.stream.ElementFilter;
import weblogic.xml.stream.events.NullEvent;public class SuperDooperFilter implements ElementFilter {protected String name;public SuperDooperFilter(String name) { this.name = name; }public boolean accept(XMLEvent e) { if (name.equals(e.getName().getLocalName())) return true; return false; }
}- In your XML application, be sure to import the new filter class:
import my.filters.SuperDooperFilter- Specify the filter as the second parameter to the newInputStream() method, passing to the filter class the types of events you want to appear in the XML stream in whatever format required by your filter class:
XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance();
XMLInputStream stream = factory.newInputStream(new FileInputStream(name), new SuperDooperFilter(param));
Iterating Over the Stream
Once you have a stream of events, the next step is to methodically step through it using the XMLInputStream.next() and XMLInputStream.hasNext() methods, as shown in the following example:
while(stream.hasNext()) { XMLEvent event = stream.next(); System.out.print(event); }
Determining the Specific XMLEvent Type
The XMLInputStream.next() method returns an object of type XMLEvent. XMLEvent has subinterfaces that further classify what this event might be, such as the start of the XML document, the end of an element, an entity reference, and so on. The XMLEvent interface also contains corresponding fields, or constants, as well as a set of methods that you can use to identify the actual event. The following diagram shows the hierarchy of the XMLEvent interface and its subinterfaces.
Figure 4-1 Hierarchy of the XMLEvent Interface and Its SubInterfaces
The following table lists the subclasses and fields of the XMLEvent class that you can use to identify a particular event while parsing the XML stream.
XMLEvent Subclass
Field of the XMLEvent Class used to Identify Subclass
Method used to Identify Subclass
Description of the Subclass Event
ChangePrefixMapping CHANGE_PREFIX_MAPPING isChangePrefixMapping Signals that a prefix mapping has changed from an old namespace to a new namespace. CharacterData CHARACTER_DATA isCharacterData Signals that the returned XMLEvent object contains the character data from the body of the element. Comment COMMENT isComment Signals that the returned XMLEvent object contains an XML comment. EndDocument END_DOCUMENT isEndDocument Signals the end of the XML document. EndElement END_ELEMENT isEndElement Signals the end of an element in the XML document. EndPrefixMapping END_PREFIX_MAPPING isEndPrefixMapping Signals that a prefix mapping has gone out of scope. EntityReference ENTITY_REFERENCE isEntityReference Signals that the returned XMLEvent object contains an entity reference. ProcessingInstruction PROCESSING_INSTRUCTION isProcessingInstruction Signals that the returned XMLEvent object contains a processing instruction. Space SPACE isSpace Signals that the returned XMLEvent object contains whitespace. StartDocument START_DOCUMENT isStartDocument Signals the start of an XML document. StartElement START_ELEMENT isStartElement Signals the start of a element in the XML document. StartPrefixMapping START_PREFIX_MAPPING isStartPrefixMapping Signals that a prefix mapping has started its scope. The following example shows how to use the Java case statement to determine the particular type of event that was returned by the XMLInputStream.next() method. For simplicity, the example simply prints that an event has been found; later sections show further processing of the event.
switch(event.getType()) { case XMLEvent.START_ELEMENT: // Start of an element System.out.println ("Start Element\n"); break;case XMLEvent.END_ELEMENT: // End of an element System.out.println ("End Element\n"); break;case XMLEvent.PROCESSING_INSTRUCTION: // Processing Instruction System.out.println ("Processing instruction\n"); break;case XMLEvent.SPACE: // Whitespace System.out.println ("White space\n"); break;case XMLEvent.CHARACTER_DATA: // Character data System.out.println ("Character data\n"); break;case XMLEvent.COMMENT: // Comment System.out.println ("Comment\n"); break;case XMLEvent.START_DOCUMENT: // Start of the XML document System.out.println ("Start Document\n"); break;case XMLEvent.END_DOCUMENT: // End of the XML Document System.out.println ("End Document\n"); break;case XMLEvent.START_PREFIX_MAPPING: // The start of a prefix mapping scope System.out.println ("Start prefix mapping\n"); break;case XMLEvent.END_PREFIX_MAPPING: // The end of a prefix mapping scope System.out.println ("End prefix mapping\n"); break;case XMLEvent.CHANGE_PREFIX_MAPPING: // Prefix mapping has changed namespaces System.out.println ("Change prefix mapping\n"); break;case XMLEvent.ENTITY_REFERENCE: // An entity reference System.out.println ("Entity reference\n"); break; default:throw new XMLStreamException("Attempt to parse unknown event [" + event.getType() + "]"); }
Getting the Attributes of an Element
To get the attributes of an element in an XML document, first cast the XMLEvent object that was returned by the XMLInputStream.next() method to a StartElement object.
Because you do not know how many attributes an element might have, first create an AttributeIterator object to contain the entire list of attributes, and then iterate over the list until there are no more attributes. The following example describes how to do this as part of the START_ELEMENT case of the switch statement shown in Iterating Over the Stream:
case XMLEvent.START_ELEMENT:StartElement startElement = (StartElement) event; System.out.print("<" + startElement.getName().getQualifiedName() ); AttributeIterator attributes = startElement.getAttributesAndNamespaces(); while(attributes.hasNext()){ Attribute attribute = attributes.next(); System.out.print(" " + attribute.getName().getQualifiedName() + "='" + attribute.getValue() + "'"); } System.out.print(">"); break;The example first creates a StartElement object by casting the returned XMLEvent to StartElement. It then creates an AttributeIterator object using the method StartElement.getAttributesAndNamespaces(), and iterates over the attributes using the AttributeIterator.hasNext() method. For each Attribute, it uses the Attributes.getName().getQualifiedName() and Attribute.getValue() methods to return the name and value of the attribute.
You can also use the getNamespace() and getAttributes() methods to return just the namespaces or attributes on their own.
Positioning the Stream
The following table describes the methods of the XMLInputStream interface that you can use to skip ahead to specific locations in the stream.
Method of XMLInputStream
Description
skip() Positions the input stream to the next stream event. Note: The next event might not necessarily be an actual element in the XML file; for example, it could be a comment or white space.
skip(int) Positions the input stream to the next event of this type. Examples of event types are XMLEvent.START_ELEMENT and XMLEvent.END_DOCUMENT. Refer to Table 4-3 for the full list of event types. skip(XMLName) Positions the input stream to the next event of this name. skip(XMLName, int) Positions the input stream to the next event of this name and type. skipElement() Skips to the next element (does not skip to the sub-elements of the current element). peek() Checks the next event without actually reading it from the stream. The following example shows how you can modify the basic code for iterating over an input stream to skip over the character data in the body of an XML element:
while(stream.hasNext()) { XMLEvent peek = stream.peek(); if (peek.getType() == XMLEvent.CHARACTER_DATA ) { stream.skip(); continue; } XMLEvent event = stream.next(); parse(event); }The example shows how to use the XMLInputStream.peek() method to determine the next event on the stream. If the type of event is XMLEvent.CHARACTER_DATA, then skip the event and go to the next one.
Getting a Substream
Use the XMLInputStream.getSubStream() method to get a copy of the next element, including all its subelements. The getSubstream() method returns an XMLInputStream object. Your position in the parent stream (or the stream from which you called getSubStream()) does not move. In the parent stream, if you want to skip the element you just got with getSubStream(), use the skipElement() method.
The getSubStream() method keeps a count of the START_ELEMENT and END_ELEMENT events it encounters, and as soon as the number is equal (or in other words, as soon as it finds the complete next element) it stops and returns the resulting substream as an XMLInputStream object.
For example, assume that you are using the XML Streaming API to parse the following XML document, but you are only interested in the substream delineated by the <content> and </content> tags:
<book> <title>The History of the World</title> <author>Juliet Shackell</author> <publisher>CrazyDays Publishing</publisher> <content> <chapter title='Just a Speck of Dust'> <synopsis>The world as a speck of dust</synopsis> <para>Once the world was just a speck of dust...</para> </chapter> <chapter title='Life Appears'> <synopsis>Move over dust, here comes life.</synopsis> <para>Happily, the dust got a companion: life...</para> </chapter> </content>
</book>The following code fragment shows how you can skip to the <content> start element tag, get the substream, and parse it using a separate ComplexParse object:
if (stream.skip( ElementFactory.createXMLName("content"))) { ComplexParse complexParse = new ComplexParse(); complexParse.parse(stream.getSubStream()); }When you call this method on the previous XML document, you get the following output:
<content> <chapter title='Just a Speck of Dust'> <synopsis>The world as a speck of dust</synopsis> <para>Once the world was just a speck of dust...</para> </chapter> <chapter title='Life Appears'> <synopsis>Move over dust, here comes life.</synopsis> <para>Happily, the dust got a companion: life...</para> </chapter>
</content>
Marking and Resetting a Buffered XML Input Stream
If you are using a BufferedXMLInputStream object, you can use the mark() and reset() methods to mark the stream at a particular spot, process the stream, and then subsequently reset the stream back to the marked spot. These methods are useful if you want to further manipulate the stream after initially iterating over it.
Note: If you read a buffered stream without marking it, you cannot access what you've just read. In other words, just because the stream is buffered, it does not automatically mean you can reread it. You must mark it first.
The following example shows a typical use of the BufferedXMLInputStream object:
XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); BufferedXMLInputStream bufstream = factory.newBufferedInputStream(factory.newInputStream(new FileInputStream(name)));// mark the start of the stream bufstream.mark();// process it locally bufferedParse.parse(bufstream);// reset the stream to the mark bufstream.reset();// send stream off to another application ComplexParse complexParse = new ComplexParse(); complexParse.parse(bufstream);
Closing the Input Stream
It is good programming practice to explicitly close the XML input stream when you are finished with it. To close an input stream, use the XMLInputStream.close() method, as shown in the following example:
// close the input stream
input.close();
Generating a New XML Document: Typical Steps
The following procedure describes the typical steps for using the WebLogic XML Streaming API to generate a new XML document.
The first two steps are required. The next steps you take depend on how you want to generate the XML file.
- Import the weblogic.xml.stream.* classes.
- Create an XML output stream to which to write the XML document. See Creating an XML Output Stream.
- Add events to the XML output stream. See Adding Elements to the Output Stream.
- Add attributes to the XML output stream. See Adding Attributes to an Element on the Output Stream.
- Add an input stream to the output stream. See Adding an Input Stream to an Output Stream.
- Print the output stream. See Printing an Output Stream.
- Close the output stream. See Closing the Output Stream.
Example of Generating an XML Document
The following program shows an example of using the XML Streaming API to generate an XML document.
The program first creates an output stream based on a PrintWriter object, then adds elements to the output stream to create a simple XML purchase order, described in the comments of the program. The program also shows how to add an input stream based on a separate XML file to the output stream. Note that the topics following the example describe it in more detail.
package examples.xml.stream;import weblogic.xml.stream.XMLInputStream;
import weblogic.xml.stream.XMLOutputStream;
import weblogic.xml.stream.XMLInputStreamFactory;
import weblogic.xml.stream.XMLName;
import weblogic.xml.stream.XMLEvent;
import weblogic.xml.stream.StartElement;
import weblogic.xml.stream.EndElement;
import weblogic.xml.stream.Attribute;
import weblogic.xml.stream.ElementFactory;
import weblogic.xml.stream.XMLStreamException;
import weblogic.xml.stream.XMLOutputStreamFactory;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintWriter;/**
* Program that prints out a very simple purchase order that looks
* like the following:
*
* <purchase_order>
* <name>Juliet Shackell</name>
* <item id="1234" quantity="2">Fabulous Chair</item>
* <!-- this is a comment-->
* <another_file>
* This comes from another file called "another_file.xml"
* </another_file>
* </purchase_order>
*
* In the preceding XML file, the <another_file> element is actually another
* XML file that is passed as an argument to the program, converted into an
* XMLInputStream, then added to the output stream.
*/
public class PrintPurchaseOrder {/** * Helper method to get a handle on a stream. * Takes in a name and returns a stream. This * method uses the InputStreamFactory to create an * instance of an XMLInputStream * @param name The file to parse * @return XMLInputStream the stream to parse */ public XMLInputStream getInputStream(String name) throws XMLStreamException, FileNotFoundException { XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); XMLInputStream stream = factory.newInputStream(new FileInputStream(name)); return stream; } public static void main(String args[]) throws Exception { PrintPurchaseOrder printer = new PrintPurchaseOrder(); // // Create an output stream. // XMLOutputStreamFactory factory = XMLOutputStreamFactory.newInstance(); XMLOutputStream output = factory.newOutputStream(new PrintWriter(System.out,true));// add the <purchase_order> root element output.add(ElementFactory.createStartElement("purchase_order")); output.add(ElementFactory.createCharacterData("\n"));// add the <name> element output.add(ElementFactory.createStartElement("name")); output.add(ElementFactory.createCharacterData("Juliet Shackell")); output.add(ElementFactory.createEndElement("name")); output.add(ElementFactory.createCharacterData("\n"));// add the <item> element along with the id and quantity attributes output.add(ElementFactory.createStartElement("item")); output.add(ElementFactory.createAttribute("id","1234")); output.add(ElementFactory.createAttribute("quantity","2")); output.add(ElementFactory.createCharacterData("Fabulous Chair")); output.add(ElementFactory.createEndElement("item")); output.add(ElementFactory.createCharacterData("\n"));// add a comment output.add("<!-- this is a comment-->"); output.add(ElementFactory.createCharacterData("\n"));// create an input stream from each XML file argument then add it to the output for (int i=0; i < args.length; i++) // // Get an input stream and add it to the output stream // output.add(printer.getInputStream(args[i]));// Finally, end the root "purchase_order" element output.add(ElementFactory.createEndElement("purchase_order")); output.add(ElementFactory.createCharacterData("\n"));// // Print the results to the screen // output.flush();// Close the output streams output.close(); }
}The preceding program produces the following output:
<purchase_order> <name>Juliet Shackell</name> <item id="1234" quantity="2">Fabulous Chair</item> <!-- this is a comment--> <another_file> This is from another file. </another_file>
</purchase_order>
Creating an XML Output Stream
One of the first steps in generating an XML document using the Weblogic XML Streaming API is to create an output stream which holds the document as it is being built. Creating an XML output stream is similar to creating an input stream: you first create an instance of the XMLOutputStreamFactory and then create an output stream with the XMLOutputStreamFactory.newOutputStream() method, as shown in the following example:
XMLOutputStreamFactory factory = XMLOutputStreamFactory.newInstance(); XMLOutputStream output = factory.newOutputStream(new PrintWriter(System.out,true));The following example shows how to create an XMLOutputStream based on a DOM tree:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(false); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().newDocument(); XMLOutputStream out = XMLOutputStreamFactory.newInstance().newOutputStream(doc);You can use the XMLOutputStreamFactory.newOutputStream() method to create an output stream based on the following four Java objects, depending on what the final form of the XML document will be (such as a file on the operating system, a DOM tree, and so on):
- java.io.OutputStream
- java.io.Writer
- org.xml.sax.ContentHandler
- org.w3c.dom.Document
Adding Elements to the Output Stream
Use the XMLOutputStream.add(XMLEvent) method to add elements to the output stream. Use the ElementFactory to create the particular element.
The ElementFactory interface includes methods to create each type of element; the general format is ElementFactory.createXXX() where XXX refers to the particular element, such as createStartElement(), createCharacterData(), and so on. You can create most elements by passing the name as a String or as an XMLName.
Warning: The XMLOutputStream does not validate your XML.
Note: Each time you create a start element, explicitly also create an end element at some point. The same rule applies to creating a start document.
For example, assume you want to create the following snippet of XML:
<name>Juliet Shackell</name>The Java code to add this element to an output stream is as follows:
output.add(ElementFactory.createStartElement("name")); output.add(ElementFactory.createCharacterData("Juliet Shackell")); output.add(ElementFactory.createEndElement("name")); output.add(ElementFactory.createCharacterData("\n"));The final createCharacterData() method adds a newline character to the output stream. This is optional, but useful if you want to create human-readable XML.
Adding Attributes to an Element on the Output Stream
Use the XMLOutputStream.add(Attribute) to add attributes to an element you have just created. Use the ElementFactory.createAttribute() method to create a particular attribute.
For example, assume you want to create the following snippet of XML:
<item id="1234" quantity="2">Fabulous Chair</item>The Java code to add this element to an output stream is as follows:
output.add(ElementFactory.createStartElement("item")); output.add(ElementFactory.createAttribute("id","1234")); output.add(ElementFactory.createAttribute("quantity","2")); output.add(ElementFactory.createCharacterData("Fabulous Chair")); output.add(ElementFactory.createEndElement("item")); output.add(ElementFactory.createCharacterData("\n"));Note: Be sure you add attributes to an element after you create the start element but before you create the corresponding end element. Otherwise, although your code will compile successfully, you will get a runtime error when you try to run the program. For example, the following code returns an error because the attributes are added to the <item> element after the element has been explicitly ended:
output.add(ElementFactory.createStartElement("item")); output.add(ElementFactory.createEndElement("item")); output.add(ElementFactory.createAttribute("id","1234")); output.add(ElementFactory.createAttribute("quantity","2")); output.add(ElementFactory.createCharacterData("Fabulous Chair")); output.add(ElementFactory.createCharacterData("\n"));
Adding an Input Stream to an Output Stream
When creating an XML output stream, you might want to add an existing XML document, such as an XML file or a DOM tree, to the output stream. To do this, first convert the XML document to an XML input stream, then use XMLOutputStream.add(XMLInputStream) method to add the input stream to the output stream.
The following example first shows a method called getInputStream() that creates an XML input stream from an XML file and then how to use the method to add the created input stream to an output stream:
/** * Helper method to get a handle on a stream. * Takes in a name and returns a stream. This * method uses the InputStreamFactory to create an * instance of an XMLInputStream * @param name The file to parse * @return XMLInputStream the stream to parse */public XMLInputStream getInputStream(String name) throws XMLStreamException, FileNotFoundException { XMLInputStreamFactory factory = XMLInputStreamFactory.newInstance(); XMLInputStream stream = factory.newInputStream(new FileInputStream(name)); return stream; }....// create an input stream from each XML file argument then add it to the outputfor (int i=0; i < args.length; i++) // // Get an input stream and add it to the output stream // output.add(printer.getInputStream(args[i]));
Printing an Output Stream
Use the XMLOutputStream.flush() method to print out the XML output stream to whatever object you created it from. For example, if you created an XML output stream from a PrintWriter object, then the flush() method prints the stream to the standard output.
Note: If you are writing to an XMLOutputStream based on a DOM tree, execute the flush() method before you can manipulate the DOM.
The following example shows how to print an output stream:
// // Print the results to the screen // output.flush();
Closing the Output Stream
It is good programming practice to explicitly close the XML output stream when you are finished with it. To close an output stream, use the XMLOutputStream.close() method, as shown in the following example:
// close the output stream
output.close();