PurchaseOrder Sample

You will find C# and Java PurchaseOrder sample programs in csharp/samples/PurchaseOrder and java/samples/PurchaseOrder, respectively.

The sample consists of the following:

When you build the sample, XBinder is used to compile the sample schema and the C#/Java compiler is used to compile the writer and reader programs. When XBinder compiles the schema, it generates classes that serve both as data structures, modeling the schema data, and as encoder-decoders, encoding and decoding the data structures to/from XML. The reader and writer programs depend on these generated classes.

To build the C# sample program, execute the makefile in the PurchaseOrder folder via the “nmake” command.

To build the Java sample program, execute the build.bat or build.sh script

Writer

The Writer program creates an XML file. Its code populates the data structures generated by XBinder, and encodes this data to XML using the generated encode method. The Reader program decodes an XML file, using the generated decode method, into the data structures generated by XBinder. It then prints this data to standard output. By default, the writer encodes to message.xml, and the reader decodes from message.xml. To run the writer for Java, use the writer.bat or writer.sh script; for C# run writer.exe.

   PurchaseOrder_CC root = new PurchaseOrder_CC();

This code creates the document codec, which contains convenience methods for encoding/decoding an entire XML document. You can think of it as representing the document as a whole and containing a single element (purchaseOrder).

   PurchaseOrderType purchaseOrder = new PurchaseOrderType();
   root.setPurchaseOrder(purchaseOrder);

This code creates an object of the purchaseOrder element's type (PurchaseOrderType), and supplies it to the root as being the data for the purchaseOrder element.

Java

   XBXmlEncoder encoder;
   encoder = new XBXmlEncoder(bos, charset);
   root.encodeDocument(encoder);
   encoder.close();

C#:

   XBXmlEncoder encoder;
   encoder = new XBXmlEncoder(fout, charset);
   root.encodeDocument(encoder);
   encoder.Close();

This code performs the encoding. After all of the data structures are populated, we create encoder1, supplying it with an OutputStream and a character set. We then pass the encoder to the PurchaseOrder_CC encodeDocument method, which encodes the data into a purchaseOrder element. Lastly, we close the encoder. [1]

Controlling XML Namespaces for encoding

The PurchaseOrder sample doesn't involve XML namespaces. However, we can still look at the generated code to see the facilities that XBinder provides for controlling XML namespaces.

Class _po includes the following declaration:

   public static XBXmlNamespace[] namespaceContext = {};

Class _po is a "schema class" (generated for each schema you compile). The namespaceContext field is used to hold namespace declarations that you may want to use, derived from the XSD you compiled. This sample doesn't use XML namespaces, so the array is empty. For schemas that do use namespaces, you can manipulate this array, and use the following code to tell the encoder to encode those namespaces with the document root:

   encoder.setNamespaces(_po.namespaceContext);

XBinder will try to guess whether the schema's target namespace should be encoded as the default namespace, or using a namespace prefix. This choice will be reflected in the contents of the namespaceContext array. Whether this choice is used or not depends on whether you change the contents of the array and/or actually invoke setNamespaces prior to invoking encodeDocument.

Another way to control namespaces, assuming your root element is of a complex type, is to use a method provided in class XBComplexType. All classes generated for complex types ultimately derive from XBComplexType. (In our sample, PurchaseOrderType is a complex type and so it extends XBComplexType) The method is XBComplexType.addNamespace:

   public void addNamespace(String nsUri, String prefix)

Reader

The Reader program decodes an XML file using the generated classes, which provide both the data structure to decode into, as well as the logic for decoding. It then prints the decoded information to the standard output.

The reader program first creates a source to read from:

C#:

   XmlTextReader reader = null;
   try
   {
      FileStream fin = new FileStream(inputFile, FileMode.Open, FileAccess.Read);
      reader = new XmlTextReader(fin);

Java:

   XMLStreamReader[2] reader = null;
   try {
      XMLInputFactory inputFactory = XMLInputFactory.newInstance();
      reader = inputFactory.createXMLStreamReader( inputFile,
               new BufferedInputStream(
                     new FileInputStream(inputFile) ) );

Next, as with the Writer, an instance of PurchaseOrder_CC is created. Then, decodeDocument is invoked:

   PurchaseOrder_CC root = new PurchaseOrder_CC();
   root.decodeDocument(reader);

Finally, the decoded data is printed to an output stream (pw or System.Console.Out):

Java:

   root.print(pw, "", 0);

C#:

   root.print(System.Console.Out, "", 0);

The print method invoked above is generated when the -print option is given to XBinder (as is done in the sample build script). The information is printed in terms of generated fields, rather than XML elements.



[1] We use "encoder" to refer to two different things, but the context should make it clear what is being referenced. Both PurchaseOrder_CC and XBXmlEncoder are encoders, but they work at different levels of abstraction. PurchaseOrder_CC (and the other classes generated by XBinder) encode/decode specific XML structures, while XBXmlEncoder provides generic XML encoding services. Here, we are obviously referring to the XBXmlEncoder object.

[2] XMLStreamReader is defined as part of the StAX API. As of JSE 6, this API is a part of the JSE. It was defined under JSR-173.