Home | Download | PDF | API | FAQ | Search | Feedback | History

> ## Sample Code

> This section steps through the sample StAX code included in the Java EE 5 Tutorial bundle. All sample directories used in this section are located off the `<javaee.tutorial.home>/examples/stax` directory.

> The topics covered in this section are as follows:

> - Sample Code Organization
> - Configuring Your Environment for Running the Samples
> - Running the Samples
> - Sample XML Document
> - cursor Sample - CursorParse.java
> - cursor2event Sample - CursorApproachEventObject.java
> - event Sample - EventParse.java
> - filter Sample - MyStreamFilter.java
> - readnwrite Sample - EventProducerConsumer.java
> - writer Sample - CursorWriter.java

> ### Sample Code Organization

> There are six StAX sample directories in `<javaee.tutorial.home>/examples/stax`:

> - cursor contains `CursorParse.java`, which illustrates how to use the `XMLStreamReader` (cursor) API to read an XML file.
> - cursor2event contains `CursorApproachEventObject.java`, which illustrates how an application can get information as an `XMLEvent` object when using cursor API.
> - event contains `EventParse.java`, which illustrates how to use the `XMLEventReader` (event iterator) API to read an XML file.
> - filter contains `MyStreamFilter.java`, which illustrates how to use the StAX Stream Filter APIs. In this example, the filter accepts only `StartElement` and `EndElement` events and filters out the remainder of the events.
> - readnwrite contains `EventProducerConsumer.java`, which illustrates how the StAX producer/consumer mechanism can be used to simultaneously read and write XML streams.
> - writer contains `CursorWriter.java`, which illustrates how to use `XMLStreamWriter` to write an XML file programatically.

> All of the StAX examples except for the writer example use a sample XML document, `BookCatalog.xml`.

> ### Configuring Your Environment for Running the Samples

> The instructions for configuring your environment are the same as those for running the other Java EE 5 Tutorial samples. Specifically, to configure your environment for running the StAX examples, follow the steps below.

> Note: If you are configuring the samples to run in a Microsoft Windows environment, use UNIX-style forward slashes (`/`) rather than Windows-style backslashes (`\`) to separate directory names when specifying paths in the steps below. For example, if your Application Server PE installation is in `c:\Sun\AppServer`, specify `c:/Sun/AppServer` instead.

> 1. Build properties common to all the examples are specified in the `<``INSTALL``>/javaeetutorial5/examples/bp-project/build.properties` file. This file must be created before you run the examples. We've included a sample file `<``INSTALL``>/javaeetutorial5/examples/bp-project/build.properties.sample` that you should rename to `<``INSTALL``>/javaeetutorial5/examples/bp-project/build.properties` and edit to reflect your environment. After you create the `build.properties` file, set the following properties:
> - javaee.home to the directory in which SJSAS PE 9.0 is installed
> - javaee.tutorial.home to the directory in which the Java EE 5 Tutorial is installed.
> 2. Specify the admin password used for your Application Server installation in `<javaee.tutorial.home>/examples/common/admin-password.txt`.
> 3. You may also need to specify the path to the `ant` command in your `PATH` environment variable; for example, on UNIX/Linux:

>       export PATH=$PATH:/opt/SUNWappserver/lib/ant/bin/

>     or, on Windows:

>       set PATH=%PATH%;c:\Sun\AppServer\lib\ant\bin

>     Be sure to use this Ant implementation when running the tutorial samples rather than any other Ant implementation you may have installed on your system.

> 4. Finally, note that the `build.xml` files in the various `stax` sample directories include classpath references to `<javaee.home>/lib/javaee.jar` and `<javaee.home>/lib/appserv-ws.jar`. You should not change these values, and if you create your own `build.xml` files, be sure to include these classpath references.

> ### Running the Samples

> The samples are run by executing the build targets, defined in the `<javaee.tutorial.home>/examples/stax/<`example`>/build.xml` file. When you run any of the samples, the compiled class files are placed in a directory named `./build`. This directory is created if it does not exist already.

> There is a separate `build.xml` file in each of the `stax` sample directories, and each `build.xml` file provides the same targets. Switch to the directory containing the sample you want to run, and then run the desired `build.xml` target from there.

> The Ant targets you use for the StAX `examp`les are:

> - run-<example-name> - Compiles, runs all classes, then runs the example
> - clean - Cleans all compiled files and sample directories when you are done

> For example, to run the `cursor` example:

>     cd <javaee.tutorial.home>/examples/stax/cursor
>     ant run-cursor
>     ant clean

> ### Sample XML Document

> The sample XML document, `BookCatalogue.xml`, used by most of the StAX sample classes, is a simple book catalog based on the common `BookCatalogue` namespace. The contents of `BookCatalogue.xml` are listed below:

>     <?xml version="1.0" encoding="UTF-8"?>
>     <BookCatalogue xmlns="http://www.publishing.org">
>       <Book>
>         <Title>Yogasana Vijnana: the Science of Yoga</Title>
>         <author>Dhirendra Brahmachari</Author>
>         <Date>1966</Date>
>         <ISBN>81-40-34319-4</ISBN>
>         <Publisher>Dhirendra Yoga Publications</Publisher>
>         <Cost currency="INR">11.50</Cost>
>       </Book>
>       <Book>
>         <Title>The First and Last Freedom</Title>
>         <Author>J. Krishnamurti</Author>
>         <Date>1954</Date>
>         <ISBN>0-06-064831-7</ISBN>
>         <Publisher>Harper &amp; Row</Publisher>
>         <Cost currency="USD">2.95</Cost>
>       </Book>
>     </BookCatalogue>

> ### cursor Sample - CursorParse.java

> Located in the `<javaee.tutorial.home>/examples/stax/cursor` directory, `CursorParse.java` demonstrates using the StAX cursor API to read an XML document. In this sample, the application instructs the parser to read the next event in the XML input stream by calling `<code>next()</code>`.

> Note that `<code>next()</code>` just returns an integer constant corresponding to underlying event where the parser is positioned. The application needs to call the relevant function to get more information related to the underlying event.

> You can imagine this approach as a virtual cursor moving across the XML input stream. There are various accessor methods which can be called when that virtual cursor is at particular event.

> #### Stepping Through Events

> In this example, the client application pulls the next event in the XML stream by calling the `next()` method on the parser; for example:

>     try
>       {
>         for(int i =  0 ; i  < count ; i++)
>           {
>             //pass the file name.. all  relative  entity
>             //references will be resolved against  this as
>             //base URI.
>             XMLStreamReader xmlr  = xmlif.createXMLStreamReader(filename, new
>     FileInputStream(filename));
>             //when XMLStreamReader is created, it is positioned at START_DOCUMENT
>     event.
>             int eventType = xmlr.getEventType();
>             //printEventType(eventType);
>             printStartDocument(xmlr);
>             //check if there are  more events  in  the input stream
>             while(xmlr.hasNext())
>               {
>                 eventType =  xmlr.next();
>                 //printEventType(eventType);
>                 //these functions  prints the information about the  particular event by
>     calling relevant function
>                 printStartElement(xmlr);
>                 printEndElement(xmlr);
>                 printText(xmlr);
>                 printPIData(xmlr);
>                 printComment(xmlr);
>               }
>           }

> Note that `next()` just returns an integer constant corresponding to the event underlying the current cursor location. The application calls the relevant function to get more information related to the underlying event. There are various accessor methods which can be called when the cursor is at particular event.

> #### Returning String Representations

> Because the `next()` method only returns integers corresponding to underlying event types, you typically need to map these integers to string representations of the events; for example:

>     public final static  String getEventTypeString(int  eventType)
>     {
>       switch  (eventType)
>         {
>             case XMLEvent.START_ELEMENT:
>               return "START_ELEMENT";
>             case XMLEvent.END_ELEMENT:
>               return "END_ELEMENT";
>             case XMLEvent.PROCESSING_INSTRUCTION:
>               return "PROCESSING_INSTRUCTION";
>             case XMLEvent.CHARACTERS:
>               return "CHARACTERS";
>             case XMLEvent.COMMENT:
>               return "COMMENT";
>             case XMLEvent.START_DOCUMENT:
>               return "START_DOCUMENT";
>             case XMLEvent.END_DOCUMENT:
>               return "END_DOCUMENT";
>             case XMLEvent.ENTITY_REFERENCE:
>               return "ENTITY_REFERENCE";
>             case XMLEvent.ATTRIBUTE:
>               return "ATTRIBUTE";
>             case XMLEvent.DTD:
>               return "DTD";
>             case XMLEvent.CDATA:
>               return "CDATA";
>             case XMLEvent.SPACE:
>               return "SPACE";
>         }
>       return  "UNKNOWN_EVENT_TYPE ,   "+ eventType;
>     }

> #### Running the Sample

> When you run the `CursorParse` sample, the class is compiled, and the XML stream is parsed and returned to `STDOUT`.

> ### cursor2event Sample - CursorApproachEventObject.java

> Located in the `<javaee.tutorial.home>/examples/stax/cursor2event` directory, `CursorApproachEventObject.java` demonstrates how to get information returned by an `XMLEvent` object even when using the cursor API.

> The idea here is that the cursor API's `XMLStreamReader` returns integer constants corresponding to particular events, where as the event iterator API's `XMLEventReader` returns immutable and persistent event objects. `XMLStreamReader` is more efficient, but `XMLEventReader` is easier to use, as all the information related to a particular event is encapsulated in a returned `XMLEvent` object. However, the disadvantage of event approach is the extra overhead of creating objects for every event, which consumes both time and memory.

> With this mind, `XMLEventAllocator` can be used to get event information as an XMLEvent object, even when using the cursor API.

> #### Instantiating an XMLEventAllocator

> The first step is to create a new `XMLInputFactory` and instantiate an `XMLEventAllocator`:

>     XMLInputFactory xmlif = XMLInputFactory.newInstance();
>     System.out.println("FACTORY: " + xmlif);
>     xmlif.setEventAllocator(new XMLEventAllocatorImpl());
>     allocator = xmlif.getEventAllocator();
>     XMLStreamReader xmlr = xmlif.createXMLStreamReader(filename, new
>     FileInputStream(filename));

> #### Creating an Event Iterator

> The next step is to create an event iterator:

>     int eventType = xmlr.getEventType();
>     while(xmlr.hasNext()){
>       eventType = xmlr.next();
>       //Get all "Book" elements as XMLEvent object
>       if(eventType == XMLStreamConstants.START_ELEMENT &&
>     xmlr.getLocalName().equals("Book")){
>         //get immutable XMLEvent
>         StartElement event = getXMLEvent(xmlr).asStartElement();
>         System.out.println("EVENT: " + event.toString());
>       }
>     }

> #### Creating the Allocator Method

> The final step is to create the `XMLEventAllocator` method:

>     private static XMLEvent getXMLEvent(XMLStreamReader reader) throws
>     XMLStreamException{
>       return allocator.allocate(reader);
>     }

> #### Running the Sample

> When you run the `CursorApproachEventObject` sample, the class is compiled, and the XML stream is parsed and returned to `STDOUT`. Note how the `Book` events are returned as strings.

> ### event Sample - EventParse.java

> Located in the `<javaee.tutorial.home>/examples/stax/event` directory, `EventParse.java` demonstrates how to use the StAX event API to read an XML document.

> #### Creating an Input Factory

> The first step is to create a new instance of `XMLInputFactory`:

>     XMLInputFactory factory = XMLInputFactory.newInstance();
>     System.out.println("FACTORY: " + factory);

> #### Creating an Event Reader

> The next step is to create an instance of XMLEventReader:

>     XMLEventReader r = factory.createXMLEventReader(filename, new
>     FileInputStream(filename));

> #### Creating an Event Iterator

> The third step is to create an event iterator:

>     XMLEventReader r = factory.createXMLEventReader(filename, new
>     FileInputStream(filename));
>     while(r.hasNext()) {
>       XMLEvent e = r.nextEvent();
>       System.out.println(e.toString());
>     }

> #### Getting the Event Stream

> The final step is to get the underlying event stream:

>     public final static String getEventTypeString(int eventType)
>     {
>       switch (eventType)
>         {
>           case XMLEvent.START_ELEMENT:
>             return "START_ELEMENT";
>           case XMLEvent.END_ELEMENT:
>             return "END_ELEMENT";
>           case XMLEvent.PROCESSING_INSTRUCTION:
>             return "PROCESSING_INSTRUCTION";
>           case XMLEvent.CHARACTERS:
>             return "CHARACTERS";
>           case XMLEvent.COMMENT:
>             return "COMMENT";
>           case XMLEvent.START_DOCUMENT:
>             return "START_DOCUMENT";
>           case XMLEvent.END_DOCUMENT:
>             return "END_DOCUMENT";
>           case XMLEvent.ENTITY_REFERENCE:
>             return "ENTITY_REFERENCE";
>           case XMLEvent.ATTRIBUTE:
>             return "ATTRIBUTE";
>           case XMLEvent.DTD:
>             return "DTD";
>           case XMLEvent.CDATA:
>             return "CDATA";
>           case XMLEvent.SPACE:
>             return "SPACE";
>         }
>       return "UNKNOWN_EVENT_TYPE " + "," + eventType;
>     }

> #### Running the Sample

> When you run the `EventParse` sample, the class is compiled, and the XML stream is parsed as events and returned to `STDOUT`. For example, an instance of the `Author` element is returned as:

>     <['http://www.publishing.org']::Author>
>     Dhirendra Brahmachari
>     </['http://www.publishing.org']::Author>

> Note in this example that the event comprises an opening and closing tag, both of which include the namespace. The content of the element is returned as a string within the tags.

> Similarly, an instance of the `Cost` element is returned as:

>     <['http://www.publishing.org']::Cost currency='INR'>
>     11.50
>     </['http://www.publishing.org']::Cost>

> In this case, the `currency` attribute and value are returned in the opening tag for the event.

> See earlier in this chapter, in the "Iterator API" and "Reading XML Streams" sections, for a more detailed discussion of StAX event parsing.

> ### filter Sample - MyStreamFilter.java

> Located in the `<javaee.tutorial.home>/examples/stax/filter` directory, `MyStreamFilter.java` demonstrates how to use the StAX stream filter API to filter out events not needed by your application. In this example, the parser filters out all events except `StartElement` and `EndElement`.

> #### Implementing the StreamFilter Class

> The MyStreamFilter implements `javax.xml.stream.StreamFilter`:

>     public class MyStreamFilter implements javax.xml.stream.StreamFilter{

> #### Creating an Input Factory

> The next step is to create an instance of XMLInputFactory. In this case, various properties are also set on the factory:

>     XMLInputFactory xmlif = null ;
>     try{
>     xmlif = XMLInputFactory.newInstance();
>     xmlif.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES,Boolean.T
>     RUE);
>     xmlif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES,Boolean.
>     FALSE);
>     xmlif.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE , Boolean.TRUE);
>     xmlif.setProperty(XMLInputFactory.IS_COALESCING , Boolean.TRUE);
>     }catch(Exception ex){
>       ex.printStackTrace();
>     }
>     System.out.println("FACTORY: " + xmlif);
>     System.out.println("filename = "+ filename);

> #### Creating the Filter

> The next step is to instantiate a file input stream and create the stream filter:

>     FileInputStream fis = new FileInputStream(filename);

>     XMLStreamReader xmlr = xmlif.createFilteredReader(xmlif.createXMLStreamReader(fis),
>     new MyStreamFilter());

>     int eventType = xmlr.getEventType();
>     printEventType(eventType);
>     while(xmlr.hasNext()){
>       eventType = xmlr.next();
>       printEventType(eventType);
>       printName(xmlr,eventType);
>       printText(xmlr);
>       if(xmlr.isStartElement()){
>         printAttributes(xmlr);
>       }
>       printPIData(xmlr);
>       System.out.println("-----------------------------");
>     }

> #### Capturing the Event Stream

> The next step is to capture the event stream. This is done in basically the same way as in the `event Sample - EventParse.java` sample.

> #### Filtering the Stream

> The final step is the filter the stream:

>     public boolean accept(XMLStreamReader reader) {
>       if(!reader.isStartElement() && !reader.isEndElement())
>         return false;
>       else
>         return true;
>     }

> #### Running the Sample

> When you run the `MyStreamFilter` sample, the class is compiled, and the XML stream is parsed as events and returned to `STDOUT`. For example an `Author` event is returned as follows:

>     EVENT TYPE(1):START_ELEMENT
>     HAS NAME: Author
>     HAS NO TEXT
>     HAS NO ATTRIBUTES
>     -----------------------------
>     EVENT TYPE(2):END_ELEMENT
>     HAS NAME: Author
>     HAS NO TEXT
>     -----------------------------

> Similarly, a `Cost` event is returned as follows:

>     EVENT TYPE(1):START_ELEMENT
>     HAS NAME: Cost
>     HAS NO TEXT

>     HAS ATTRIBUTES:
>     ATTRIBUTE-PREFIX:
>     ATTRIBUTE-NAMESP: null
>     ATTRIBUTE-NAME:   currency
>     ATTRIBUTE-VALUE: USD
>     ATTRIBUTE-TYPE:  CDATA

>     -----------------------------
>     EVENT TYPE(2):END_ELEMENT
>     HAS NAME: Cost
>     HAS NO TEXT
>     -----------------------------

> See earlier in this chapter, in the "Iterator API" and "Reading XML Streams" sections, for a more detailed discussion of StAX event parsing.

> ### readnwrite Sample - EventProducerConsumer.java

> Located in the `<javaee.tutorial.home>/examples/stax/`readnwrite directory, `EventProducerConsumer.java` demonstrates how to use a StAX parser simultaneously as both a producer and a consumer.

> The StAX `XMLEventWriter` API extends from the `XMLEventConsumer` interface, and is referred to as an event consumer. By contrast, `XMLEventReader` is an event producer. StAX supports simultaneous reading and writing, such that it is possible to read from one XML stream sequentially and simultaneously write to another stream.

> This sample shows how the StAX producer/consumer mechanism can be used to read and write simultaneously. This sample also shows how a stream can be modified, and new events can be added dynamically and then written to different stream.

> #### Creating an Event Producer/Consumer

> The first step is to instantiate an event factory and then create an instance of an event producer/consumer:

>     XMLEventFactory m_eventFactory=XMLEventFactory.newInstance();
>     public EventProducerConsumer() {
>     }
>     .
>     .
>     .
>     try{
>       EventProducerConsumer ms = new EventProducerConsumer();

>       XMLEventReader reader =
>     XMLInputFactory.newInstance().createXMLEventReader(new
>     java.io.FileInputStream(args[0]));
>       XMLEventWriter writer =
>     XMLOutputFactory.newInstance().createXMLEventWriter(System.out);

> #### Creating an Iterator

> The next step is to create an iterator to parse the stream:

>     while(reader.hasNext())
>       {
>         XMLEvent event = (XMLEvent)reader.next();
>         if(event.getEventType() == event.CHARACTERS)
>           {
>             writer.add(ms.getNewCharactersEvent(event.asCharacters()));
>           }
>         else
>           {
>             writer.add(event);
>           }
>       }
>     writer.flush();

> #### Creating a Writer

> The final step is to create a stream writer in the form of a new `Character` event:

>     Characters getNewCharactersEvent(Characters event){
>       if(event.getData().equalsIgnoreCase("Name1")){
>         return m_eventFactory.createCharacters(Calendar.getInstance().getTime().toString());

>       }
>       //else return the same event
>       else return event;
>     }

> #### Running the Sample

> When you run the `EventProducerConsumer` sample, the class is compiled, and the XML stream is parsed as events and written back to `STDOUT`:

>     <?xml version="1.0" encoding="UTF-8"?>
>     <BookCatalogue xmlns="http://www.publishing.org">
>       <Book>
>         <Title>Yogasana Vijnana: the Science of Yoga</Title>
>         <Author>Dhirendra Brahmachari</Author>
>         <Date>1966</Date>
>         <ISBN>81-40-34319-4</ISBN>
>         <Publisher>Dhirendra Yoga Publications</Publisher>
>         <Cost currency="INR">11.50</Cost>
>       </Book>

>       <Book>
>         <Title>The First and Last Freedom</Title>
>         <Author>J. Krishnamurti</Author>
>         <Date>1954</Date>
>         <ISBN>0-06-064831-7</ISBN>
>         <Publisher>Harper &amp; Row</Publisher>
>         <Cost currency="USD">2.95</Cost>
>       </Book>
>     </BookCatalogue>

> ### writer Sample - CursorWriter.java

> Located in the `<javaee.tutorial.home>/examples/stax/writer` directory, `CursorWriter.java` demonstrates how to use the StAX cursor API to write an XML stream.

> #### Creating the Output Factory

> The first step is to create an instance of `XMLOutputFactory`:

>     XMLOutputFactory xof =  XMLOutputFactory.newInstance();

> #### Creating a Stream Writer

> The next step is to create an instance of `XMLStreamWriter`:

>     XMLStreamWriter xtw = null;

> #### Writing the Stream

> The final step is to write the XML stream. Note that the stream is flushed and closed after the final `EndDocument` is written:

>     xtw = xof.createXMLStreamWriter(new FileWriter(fileName));
>     xtw.writeComment("all elements here are explicitly in the HTML namespace");
>     xtw.writeStartDocument("utf-8","1.0");
>     xtw.setPrefix("html", "http://www.w3.org/TR/REC-html40");
>     xtw.writeStartElement("http://www.w3.org/TR/REC-html40","html");
>     xtw.writeNamespace("html", "http://www.w3.org/TR/REC-html40");
>     xtw.writeStartElement("http://www.w3.org/TR/REC-html40","head");
>     xtw.writeStartElement("http://www.w3.org/TR/REC-html40","title");
>     xtw.writeCharacters("Frobnostication");
>     xtw.writeEndElement();
>     xtw.writeEndElement();
>     xtw.writeStartElement("http://www.w3.org/TR/REC-html40","body");
>     xtw.writeStartElement("http://www.w3.org/TR/REC-html40","p");
>     xtw.writeCharacters("Moved to");
>     xtw.writeStartElement("http://www.w3.org/TR/REC-html40","a");
>     xtw.writeAttribute("href","http://frob.com");
>     xtw.writeCharacters("here");
>     xtw.writeEndElement();
>     xtw.writeEndElement();
>     xtw.writeEndElement();
>     xtw.writeEndElement();
>     xtw.writeEndDocument();
>     xtw.flush();
>     xtw.close();

> #### Running the Sample

> When you run the `CursorWriter` sample, the class is compiled, and the XML stream is parsed as events and written to a file named `dist/CursorWriter-Output`:

>     <!--all elements here are explicitly in the HTML namespace-->
>     <?xml version="1.0" encoding="utf-8"?>
>     <html:html xmlns:html="http://www.w3.org/TR/REC-html40">
>     <html:head>
>     <html:title>Frobnostication</html:title></html:head>
>     <html:body>
>     <html:p>Moved to <html:a href="http://frob.com">here</html:a>
>     </html:p>
>     </html:body>
>     </html:html>

> Note that in the actual `dist/CursorWriter-Output` file, this stream is written without any linebreaks; the breaks have been added here to make the listing easier to read. In this example, as with the object stream in the `event Sample - EventParse.java` sample, the namespace prefix is added to both the opening and closing HTML tags. This is not required by the StAX specification, but it is good practice when the final scope of the output stream is not definitively known.