|
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="salesdata"> <xsd:complexType> <xsd:sequence> <xsd:element name="year" type="YearType" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:complexType name="YearType"> <xsd:sequence> <xsd:element name="theyear" type="xsd:string"/> <xsd:element name="sales" type="SalesType"/> <xsd:element name="region" type="RegionType" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="SalesType"> <xsd:simpleContent> <xsd:extension base="xsd:double"> <xsd:attribute name="unit" type="xsd:string"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> <xsd:complexType name="RegionType"> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="sales" type="SalesType"/> </xsd:sequence> </xsd:complexType> </xsd:schema> |
|
<?xml version="1.0"?>
<salesdata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="salesdata.xsd"> <year> <theyear>1997</theyear> <region> <name>west</name> <sales unit="millions">32</sales> </region> <region> <name>central</name> <sales unit="millions">11</sales> </region> <region> <name>east</name> <sales unit="millions">19</sales> </region> </year> <year> <theyear>1998</theyear> <region> <name>west</name> <sales unit="millions">35</sales> </region> <region> <name>central</name> <sales unit="millions">12</sales> </region> <region> <name>east</name> <sales unit="millions">25</sales> </region> </year> <year> <theyear>1999</theyear> <region> <name>west</name> <sales unit="millions">36</sales> </region> <region> <name>central</name> <sales unit="millions">12</sales> </region> <region> <name>east</name> <sales unit="millions">31</sales> </region> </year> <year> <theyear>2000</theyear> <region> <name>west</name> <sales unit="millions">37</sales> </region> <region> <name>central</name> <sales unit="millions">11</sales> </region> <region> <name>east</name> <sales unit="millions">40</sales> </region> </year> </salesdata> |
|
package com.ibm.xj.samples.totals;
import java.io.FileInputStream; import com.ibm.xj.io.XMLDocumentOutputStream; import com.ibm.xj.samples.driver.Benchmark; import com.ibm.xj.samples.totals.salesschema.*; public class Totals implements Benchmark { private salesdata document; 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(); } public void doParse(String filename) { try { document = new salesdata(new FileInputStream(filename)); } catch (java.io.IOException e) { throw new Error("Cannot parse input file"); } } public void doExecute() { computeSales(document); } private static void computeSales(salesdata sd) { int min = 70; System.out.println("Total Sales"); double grandTotal = 0; Sequence<year> ys = sd[|year[sum(.//sales) > $min]|]; if (ys.isEmpty()) System.out.println("No elements matched"); XMLCursor<year> y = ys.iterator(); while (y.hasNext()) { year ytmp = y.next(); String str = ytmp[|theyear|]; System.out.print(str + "\t"); double total = 0; XMLCursor<sales> s = ytmp[|.//sales|].iterator(); while (s.hasNext()) { sales stmp = s.next(); total = total + stmp; } grandTotal += total; System.out.println(total); } double conversionFactor = 1.8; sales s2 = new sales(<sales unit="GBP">{conversionFactor * grandTotal}</sales>); XMLDocumentOutputStream out = new XMLDocumentOutputStream(System.out); out.println(s2); System.out.println("\n Grand Total: " + grandTotal); } } |
We now examine this program, statement by statement, and explain the various XJ features that are employed.
The preamble:
The above specifies the package in which the Java class resides.
As an XJ program is a Java program, one can import any Java classes and interfaces.
This statement notifies the XJ compiler that the XML schema entities (elements and their types) in the file "salesschema.xsd" in package com.ibm.xj.samples.totals should be imported into the program.
The file defines a Java class -- Totals that implements a Java
interface Benchmark
. 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.
This main method creates an object of class Totals and asks it to perform two tasks:
Consider the statement document = new salesdata(new FileInputStream(filename));
It performs loading, parsing and validation
of the data in file
filename and associates an XML value with the XML variable
document.
Method doExecute performs the data processing task by invoking the computeSales static method on the document field.
Method computeSales has a single argument, an XML parameter sd of type salesdata. It first prints the output heading and initializes a double value grandTotal to 0. Then, it performs:
This statement defines an XJ sequence, ys, parameterized
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.
This statement checks if the above sequence is empty, and prints a message if so. The isEmpty() method is defined on all Sequences.
Here, an XMLCursor is created for the ys sequence. An XMLCursor is very similar to the Java Iterator, but is generic.
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 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.
The XMLCursor s will iterate over the sales elements within the current year element.
The loop iterates through the sales elements in s. Variable stmp is the current sales element.
The total for this year element is updated. Note that there's an implicit coercion from the XML element sales that has contents of type xsd:double to double.
The grandTotal (over all years) is incremented; the total for this year is printed.
The following demonstrates the XML value construction facilities of XJ:
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:
Next,
A new com.ibm.xj.io.XMLDocumentOutputStream object is created, which adds XML output capability to the java.io.PrintStream class. Then,
s2 is serialized into plain XML and is printed to standard output via the XMLDocumentOutputStream class.
Finally, " Grand Total: 239.0" is printed.
The compilation and execution are as follows:
|
[$XJ_HOME/samples]$
export JAVA_HOME="c:/Program Files/IBM/Java14"
[$XJ_HOME/samples]$ ../bin/xjc com/ibm/xj/samples/totals/Totals.xj [$XJ_HOME/samples]$ ../bin/xj com.ibm.xj.samples.totals.Totals com/ibm/xj/samples/totals/chart.xml Total Sales 1998 72.0 1999 79.0 2000 88.0 <?xml version="1.0" encoding="UTF-8"?> <sales unit="GBP">430.2</sales> Grand Total: 239.0 [$XJ_HOME/samples]$ |
![[*]](footnote.png)
![[*]](footnote.png)
![[*]](footnote.png)