You will find C# and Java PurchaseOrder sample programs in csharp/samples/PurchaseOrder and java/samples/PurchaseOrder, respectively.
The sample consists of the following:
Sample XML schema (po.xsd)
Sample Writer program (Writer.cs/Writer.java)
Sample Reader program (Reader.cs/Reader.java)
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
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]
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)
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.