Photo
A Sample XJ Program
The preamble:
package com.ibm.xj.samples.totals;

The above specifies the package in which the XJ class resides.


import java.io.IOException;
import java.io.FileInputStream;

As XJ is an extension of Java, one can import any class or interface that is pure Java.


import com.ibm.xj.samples.totals.salesschema.*;

This statement notifies the XJ compiler that the XML Schema global element in the file "salesschema.xsd" in package com.ibm.xj.samples.totals should be imported into the program. The compiler first attempts to discover packages that correspond to the import. If that fails it attempts to find a schema.


public class Totals {
    private salesdata document;

The file defines a Java class - Totals. Within this class, the first declaration is of a private variable named document. Its type is salesdata, which is an XML type. The XJ compiler will find the definition of salesdata in the imported schema file.


    public static void main(String[] argv) {
        if (argv.length != 1) {
            System.err.println("Usage: Totals <filename>");
            System.exit(-1);
        }
        Totals t = new Totals();
        t.doParse(argv[0]);
        t.doExecute();
    }

This main method creates an object of class Totals and asks it to perform two tasks:

  • parse the filename passed on the command line by calling instance method doParse, and
  • perform its data processing tasks by calling instance method doExecute.


    public void doParse(String filename) {
        try {
            document = new salesdata(new FileInputStream(filename));
        }
        catch (java.io.IOException e) {
            throw new Error("Cannot parse input file");
        }
    }

Consider the statement document = new salesdata(new FileInputStream(filename));

It performs loading, parsing and validation6 of the data in file "filename" and associates an XML value with the XML variable document.


    public void doExecute() {
        computeSales(document);
    }

Method doExecute performs the data processing task by invoking the computeSales static method on the document field.


    private static void computeSales(salesdata sd) {
        int min = 70;
        System.out.println("Total Sales");
        int grandTotal = 0;

Method computeSales has a single argument, an XML parameter sd of type salesdata. It first prints the output heading and initializes integer grandTotal to 0. Then, it performs:


        Sequence<year> ys = sd[|year[sum(.//sales) > $min]|];

This statement defines an XJ sequence, ys, parameterized7 by the XML type year. This sequence will contain, at run-time, references to XML values. It is obtained by applying an XPath expression to the XML value referenced by variable sd (the argument to computeSales). The XPath expression is sd[|year[sum(.//sales) > $min]|], which finds all years for which the sum of the values contained in the sales elements is greater than the value of min. Note that this XPath expression refers to the XJ variable min. At runtime, the value of min would be substituted before the evaluation of the XPath expression. Formally, this expression results in a sequence of XML items (all are nodes in this case). XJ's implementation is to populate the sequence with references to XML elements or instances of atomic classes as appropriate.


        if (ys.isEmpty())
            System.out.println("No elements matched");

This statement checks if the above sequence is empty, and prints a message if so. The isEmpty method is defined on all Sequences.


        XMLCursor<year> y = ys.iterator();

Here, an XMLCursor is created for the ys sequence. An XMLCursor extends the java.util.Iterator class, and is generic.


        while (y.hasNext()) {
            year ytmp = y.next();

The while loop iterates over the elements of y. These elements are references to year elements. Variable ytmp references the current year element.


            String str = ytmp[|theyear|];
            System.out.print(str + "\t");
            int total = 0;

String str is assigned the character content of theyear sub-element of element year. The variable total, the sum for this year, is initialized to zero. At this point the sales of the current year element are to be added.


            XMLCursor<sales> s = ytmp[|.//sales|].iterator();

The XMLCursor s is assigned the sales elements within the current year element.


            while (s.hasNext()) {
                sales stmp = s.next();

The loop iterates through the sales elements in s. Variable stmp is the current sales element.


                total = total + stmp;

The total for this year element is incremented.


            }
            grandTotal += total;
            System.out.println(total);

The grandTotal (over all years) is incremented; the total for this year is printed.

The following demonstrates the XML value construction facilities of XJ:


        }
        double conversionFactor = 1.8;
        sales s2 = new sales(<sales unit="GBP">{conversionFactor * grandTotal}</sales>);

It creates a new XML value using the literal XML constructor and stores in the variable s2. The braces "{}" enclose an XJ expression which is evaluated at runtime to generate a value that is embedded in the constructed XML.

Variable s2 references the newly constructed XML value. The statement illustrates one way in which data can be assigned to this element. The XML value of s2 at runtime is:


<sales unit="GBP">430.2</sales>

Next,


        XMLDocumentOutputStream out = new XMLDocumentOutputStream(System.out);
        out.println(s2);

s2 is serialized into plain XML and is printed to standard output.


        System.out.println("Grand Total: " + grandTotal);
    }
}

Finally, "Grand Total: 239.0" is printed.


 

    About IBM Privacy Contact