XML offers a rich and extensible form for representing data, based on a simple idea: tagged text.
Quick offers a way to convert XML files into a structure of objects, using the classes of your choice.
Quick can generate new classes, when needed. It has an simple API. And it does not complicate your programs in any way. Quick will work with most of your code, unmodified.
To use Quick, you will need to learn some XML. And you will need to learn a little about binding schema.
Quick is Open Source. The CVS repository
can be found at
Contents
<address> <name>JXML, Inc.</name> <street>17 Trowbridge St., Apt 17</street> <city>Cambridge</city> <state>MA</state> <zip>02138</zip> </address>There is a real advantage to working with XML--it is relatively easy for a program to extract the information held by the text file.
But instead of thinking of XML as tagged text, it is better to think of it as a syntax for representing various types of data, where each type of data must conform to a particular model. For the above example, we could say that we have a data model with 6 elements:
One way to define the data model for an XML markup language is to use a DTD, which deals mostly with the structure of an XML document. Here's the DTD for the data model we defined above:
<!ELEMENT address (name,street,city,state,zip)> <!ELEMENT name (#PCDATA)> <!ELEMENT street (#PCDATA)> <!ELEMENT city (#PCDATA)> <!ELEMENT state (#PCDATA)> <!ELEMENT zip (#PCDATA)>In this section, we have hardly covered the basics of XML. But we have introduced a number of key issues:
Quick does not use XML DTDs, but uses a schema language, QJML, to define markup languages and their relationship to Java classes. Once you have specified an XML markup language in QJML, you can use Quick to perform a number of activities:
Quick also includes a wild-card facility to support the processing of documents which contain undefined elements.
But perhaps the most important feature of Quick is its support for validating the content of an XML document. This is handled by the inclusion of programmer-supplied JavaBean PropertyEditors in the QJML binding schema.
The design goals of Quick were:
In this section we covered the key features of
Quick.
When developing programs which use XML documents to exchange data, one of the first steps is to design the data model for those documents.
Once the data model has been specified, work can then proceed on the implementation of the Java classes for the objects which comprise the internal representation of the XML documents. As an internal representation, these objects need to correspond closely to the various elements and data items contained by the XML documents.
Indeed, when developing a program which exchanges XML documents with other programs, the data model specification will either be a cooperative effort, since it impacts the design of all the programs participating in those exchanges, or the data model specification will have already been completed.
In contrast, when using XML documents as a file format for persistant data, fewer developers will be involved in the specification of the data model. But even in this case, the data model should not be specific to a particular version of the program that produces it. Rather, the data model should reflect the overall application.
There are two advantages to using an application-based data model for persistant data (instead of using a data model that is specific to the implementation of the program which produces the persistant data):
In this section, the key point covered is the
importance of designing an XML data model, rather than deriving the data
model from the design of the program.
Here is a sample of an XML document, a simple list, that we would like to process:
<list> <item>XML should be easy to use.</item> <item>Quick keeps it simple, too.</item> </list>The data model for list documents has only two elements:
<!ELEMENT list (item*)> <!ELEMENT item (#PCDATA)>(The * after item says that the contents of a list element can include any number of item elements.)
The information expressed in a DTD can also be expressed in a QDML document. (A QDML schema is itself an XML document.) Here is the QDML schema for list documents:
<qdml> <element name="list"> <child element="item" optional="True" repeating="True"/> </element> <element name="item" content="PCDATA"/> </qdml>Ouch! The first thing we see here is that XML documents tend to be verbose. This is the price we pay for having a common syntax. But having a common syntax is also an advantage, because once we become familiar with XML, it is realatively easy to read documents expressed in any XML markup language.
On second glance, we see that XML elements can take two different forms, and that elements can have attributes.
What we saw before were elements which had content, be it text or other elements. Elements which have content are expressed using a start and end tag:
<myElement>The content of my element.</myElement>The second form of an element can be used when an element has no content. When using this form, the element is expressed as a single tag:
<myElement/>Attributes add to the complexity of the XML syntax, but are perhaps justified by reducing, if only slightly, the overall verbosity. Here are some things you should know about attributes:
<qdml> <element name="list"> <child element="item" optional="True" repeating="True"/> </element> <element name="item" content="PCDATA"/> </qdml>The above QDML document uses 3 kinds of elements:
<list> <item>A DTD or Schema</item> <item>may describe a Data Model,</item> <item>but how do they help with</item> <item>processing XML documents?</item> </list>In Java, one way to represent the List data model would be to use an ArrayList to hold the list, and to use String for each item. Here's a QJML document which specifies exactly that:
<qjml root="list"> <element name="list"> <targetClass>java.util.ArrayList</targetClass> <child element="item" optional="True" repeating="True" class="com.jxml.quick.access.QListAccess"/> </element> <element name="item" content="string"/> </qjml>The QJML markup language is the keystone of Quick. This markup language has 11 elements which are used to describe relationships between XML data models and Java classes.
Once you have written a QJML binding schema, processing the XML documents described by that schema is easy.
In this section, the key point is that QJML will
make it easy to process XML documents.
First, we need a few import statements:
We need this import statement for the List example, since we will be using ArrayList.
import java.io.*;
This import statement lets us catch an IOException, which might be thrown when an XML document is read.
import com.jxml.quick.*;
We will be calling static methods on the Quick class and referencing the QDom interface, which are all part of the Quick package.
import org.xml.sax.*;
The methods on the Quick class throw a SAXException, which is part of the SAX package, when an error is encountered.
import org.xml.sax.helpers.*;
QDom objects are used by Quick to hold structures of objects, and related meta data (element IDs).
Before we begin processing XML documents, we need to process the appropriate QJML binding schema.
Here is the initialization code needed for List documents:
QDoc listSchema=Quick.parseQJML("list.qjml");
Here we parse the QJML binding schema for the List markup language. The parse results are placed in a newly created QDoc object.
ArrayList list1=new ArrayList(); list1.add("This is a list"); list1.add("with three"); list1.add("items."); QDoc listDoc1=Quick.createDoc(list1,listSchma); String xml1=Quick.express(listDoc1); System.out.println(xml1);Here's the output:
<?xml version="1.0" encoding="ISO-8859-1"?> <list> <item>This is a list</item> <item>with three</item> <item>items.</item> </list>
QDoc sampleDoc=Quick.parse(listSchema,"sample.list"); ArrayList sampleList=(ArrayList)Quick.getRoot(sampleDoc); int sampleSize=sampleList.size(); int i; for (i=0;i<sampleSize;++i) { System.out.println(sampleList.get(i)); }And here's the output:
XML should be easy to use. Quick keeps it simple, too.In this section we were introduced to the QDoc object. And we learned how easy it is to process XML, once we have a QJML binding schema.
Quick has an internal binding schema, QIML, whose elements correspond to various classes of the Quick engine. When parsing a QJML document, Quick translates the data structure to QIML and uses that to compose an assemblage of objects capable of operating on documents of the type defined by the QJML document.
But instead of converting a QJML file into a QIML data structure each time a program is run, the QJML2QIML utility can be used to create a .qiml file. Quick can then use the .qiml file instead of the .qjml file.
So why have both QJML and QIML? Well, QIML is really the internal data structure used by Quick. QIML is not friendly. The transformation between QJML and QIML is where a lot of the friendliness of QJML is handled.
But there is also a very good reason for having Quick accept QIML files. The QJML binding schema is not exactly a standard. QJML was intended as something easy to implement, but easier to use than QIML. (An early alpha of Quick was based on QIML, and it was impossible to use!) But there are, no doubt, much superior alternatives to QJML. With Quick accepting QIML files, we now have the opportunity of using a different binding schema and converting it directly to QIML, rather than be limited to using QJML directly. (QIML has interesting capabilities like inheritance, which are missing from QJML.)
Windows users:
dtd2qdml x.dtd x.qdmlis a lot easier to type than
java com.jxml.quick.util.dtd2qdml.DTD2QDML x.dtd x.qdml
Advanced users:
Quick includes utilities for creating QDML schema, QJML binding schema, DTDs, and even Java source code.
If you are starting with a DTD, you can do the following:
DTD2XML is a utility for converting DTD files into XML. Here's the command line:
java com.jxml.quick.util.dtd2xml.DTD2XML X.dtd X.xmlwhere X.dtd is the name of the DTD file and X.xml is the name of the XML file being created.
DTD2QDML is a utility for converting DTD files to QDML schema. Here's the command line:
java com.jxml.quick.util.dtd2qdml.DTD2QDML X.dtd X.qdmlwhere X.dtd is the name of the DTD file and X.qdml is the name of the QDML file being created.
DTD2QDML will print warning messages when either mixed mode elements or the ANY construct are encountered, as these do not translate directly into QDML.
QDML2QJML is a utility for converting QJML schema to QJML binding schema. Here's the command line:
java com.jxml.quick.util.qdml2qjml.QDML2QJML X.qdml root package X.qjmlwhere
x.qdml is the QDML file to be converted,
root is the root element,
package is the package containing the Java classes for the various elements, and
x.qjml is the name of the QJML file to be created.
QDML2QJML tries to guess how the various elements will be mapped into Java classes. For some applications, the generated QJML file will be good enough. But for other applications, the generated file is only a starting point.
The QJML Wizard is a tool for editing and validating the QJML files needed by Quick.
The QJML Wizard is somewhat forgiving of the file you are editing--it allows you to edit QJML files which are missing various elements and attributes. This means that you can use DTD2QDML to create a QDML file, change the root element from QDML to QJML, and then use the QJML Wizard to add the required binding information. (A bit more pre-editing may be needed if the DTD has elements with MIXED content.)
Here's the command line for running the QJML Wizard:
java com.jxml.quick.qtil.qjmlWizard.wizard.Main
The wizard display includes an element tree on the left and an attribute list on the right. The contents of the element buffer (used for element cut and paste operations) apears in the line above the element tree. There is also an error list below the element tree and attribute list. Errors are reported for the selected portion of the element tree, including all subordinate elements.
When you select an element in the element tree, the attributes are shown on the right. Select an attribute and a dialog box pops up for editing.
Adding new elements is done in a few simple steps:
QJML2Java is a utility for generating Java classes from a QJML file. Here's the command line:
java com.jxml.quick.util.qjml2java.QJML2Java [-cqprtf1] [-gpackage.name] schema.qjml output_folderwhere
QJML2QIML is a utility for converting QJML files to QIML. Here's the command line:
java com.jxml.quick.util.qjml2qiml.QJML2QIML X.qjml X.qimlwhere X.qjml is the name of the QJML file and X.qiml is the name of the QIML file being created. The Quick API will support the use of either QJML or QIML files. But when given a QJML file, the Quick runtime must first convert it to QIML.
QJML and QIML are used by Quick, but are non-standard. This is because Quick needs to have binding information as well as a schema. So if you're using Quick, you have been developing a QJML binding schema. But when working with others, you need a DTD. So here's the command line to convert a QJML file into a DTD:
java com.jxml.quick.util.qjml2dtd.QJML2DTD X.qjml X.dtdwhere X.qjml is the name of the QJML file and X.dtd is the name of the DTD file being created. And just to be complete, here's the command line to convert a QIML file into a DTD:
java com.jxml.quick.util.qiml2dtd.QIML2DTD X.qiml X.dtd
QIML2XML is a utility for generating a QIML file from the Quick runtime's internal structures. Here's the command line:
java com.jxml.quick.util.qiml2xml.QIML2XML X.qimlwhere X.qiml is the name of the QIML file being created.
After you Download Quick, we suggest the following:
As you become familiar with Quick, we encourage your participation in its development:
Your participation in the development of Quick is welcome!
<JXML> <Download> <QDML> <QJML> <QARE>
Java and JavaBeans are trademarks of Sun Microsystems, Inc.