ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Schemaless Java-XML Data Binding with VTD-XML
Pages: 1, 2

The following code has two methods: The bind() accepts the XML file name as the input, performs the data binding by plugging in the above XPath expressions, and returns an array list containing object references. The main() method invokes the binding routine and prints out the content of the objects.



class XMLBinder {
    ArrayList bind(String fileName) throws Exception {
        ArrayList al = new ArrayList();
        VTDGen vg = new VTDGen();
        AutoPilot ap0 = new AutoPilot();
        AutoPilot ap1 = new AutoPilot();
        AutoPilot ap2 = new AutoPilot();
        AutoPilot ap3 = new AutoPilot();
        AutoPilot ap4 = new AutoPilot();
        ap0.selectXPath("/CATALOG/CD[YEAR > 1982 and YEAR <1990]");
        ap1.selectXPath("TITLE");
        ap2.selectXPath("ARTIST");
        ap3.selectXPath("PRICE");
        ap4.selectXPath("YEAR");
        if (vg.parseFile(fileName,false)) {
            VTDNav vn = vg.getNav();
            ap0.bind(vn);
            ap1.bind(vn);
            ap2.bind(vn);
            ap3.bind(vn);
            ap4.bind(vn);
            while(ap0.evalXPath()!=-1){
                CDRecord cdr = new CDRecord();
                cdr.title = ap1.evalXPathToString();
                cdr.artist = ap2.evalXPathToString();
                cdr.price = ap3.evalXPathToNumber();
                cdr.year = (int)ap4.evalXPathToNumber(); // evalXPathToNumber evaluates to a double
                al.add(cdr);
            }
            ap0.resetXPath();
        }
        return al;
    }


    public static void main(String[] args) throws Exception {
        XMLBinder xb = new XMLBinder();
        ArrayList al = xb.bind("d:/javaworld/update/example2/cd.xml");
        Iterator it = al.iterator();
        while(it.hasNext()) {
            CDRecord cdr = (CDRecord) it.next();
            System.out.println("===================");
            System.out.println("TITLE:  ==> "+cdr.title);
            System.out.println("ARTIST: ==> "+cdr.artist);
            System.out.println("PRICE:  ==> "+cdr.price);
            System.out.println("YEAR:   ==> "+cdr.year);
        }
    }
}

Read and Write

This part of the project deals with the same XML document, but the application logic lowers the PRICE of each CD by 1. To that end, two changes are necessary: the CD record class file now has a new field (named priceIndex) containing the VTD index for text node of PRICE.

public class CDRecord2 {
    String title;
    String artist;
    double price;
    int priceIndex;
    int year;
}

The new bind() now accepts a VTDNav object as the input, but returns the same array list. The main method invokes bind(...), iterates over the objects, and uses XMLModifer to create cd_updated.xml.

import com.ximpleware.*;
import java.util.*;
import java.io.*; 

class XMLBinder2 { 
    ArrayList bind(VTDNav vn) throws Exception {
        ArrayList al = new ArrayList();
        AutoPilot ap0 = new AutoPilot();
        AutoPilot ap1 = new AutoPilot();
        AutoPilot ap2 = new AutoPilot();
        AutoPilot ap3 = new AutoPilot();
        AutoPilot ap4 = new AutoPilot();
        ap0.selectXPath("/CATALOG/CD[YEAR > 1982 and YEAR < 1990]"); /*/CATALOG/CD[YEAR > 1982 and YEAR < 1990]/TITLE */
        ap1.selectXPath("TITLE"); /* /CATALOG/CD[YEAR > 1982 and YEAR < 1990]/ARTIST */
        ap2.selectXPath("ARTIST"); /* /CATALOG/CD[YEAR > 1982 and YEAR < 1990]/PRICE */
        ap3.selectXPath("PRICE"); /* /CATALOG/CD[YEAR > 1982 and YEAR < 1990]/YEAR */
        ap4.selectXPath("YEAR"); 
        ap0.bind(vn);
        ap1.bind(vn);
        ap2.bind(vn);
        ap3.bind(vn);
        ap4.bind(vn);
        while (ap0.evalXPath() != -1) {
            CDRecord2 cdr = new CDRecord2()
            cdr.title = ap1.evalXPathToString()
            cdr.artist = ap2.evalXPathToString()
            vn.push()
            ap3.evalXPath()
            cdr.priceIndex = vn.getText()
            cdr.price = vn.parseDouble(cdr.priceIndex)
            ap3.resetXPath()
            vn.pop()
            cdr.year = (int) ap4.evalXPathToNumber()
            al.add(cdr);
        }
        ap0.resetXPath();
        return al;
    } 

    public static void main(String[] args) throws Exception {
        XMLBinder2 xb = new XMLBinder2();
        VTDGen vg = new VTDGen();
        XMLModifier xm = new XMLModifier(); 

        if (vg.parseFile("cd.xml",false)) {
            VTDNav vn = vg.getNav();
            ArrayList al2 = xb.bind(vn);
            Iterator it2 = al2.iterator();
            xm.bind(vn);
            while(it2.hasNext()) {
                CDRecord2 cdr = (CDRecord2) it2.next();  // reduce prices by 1
                xm.updateToken(cdr.priceIndex, ""+(cdr.price - 1));
            }
            xm.output(new FileOutputStream("cd_update.xml"));
        }<br/> 
    }

The updated XML, containing new prices, looks like the following:

<CATALOG>
    <CD>
        <TITLE>Empire Burlesque</TITLE>
        <ARTIST>Bob Dylan</ARTIST>
        <COUNTRY>USA</COUNTRY>
        <COMPANY>Columbia</COMPANY>
        <PRICE>9.9</PRICE>
        <YEAR>1985</YEAR>
    </CD>
    <CD>
        <TITLE>Still Got the Blues</TITLE>
        <ARTIST>GaryMore</ARTIST>
        <COUNTRY>UK</COUNTRY>
        <COMPANY>Virgin Records</COMPANY>
        <PRICE>10.20</PRICE>
        <YEAR>1990</YEAR>
    </CD>
    <CD>
        <TITLE>Hide Your Heart</TITLE>
        <ARTIST>Bonnie Tyler</ARTIST>
        <COUNTRY>UK</COUNTRY>
        <COMPANY>CBS Records</COMPANY>
        <PRICE>8.9</PRICE>
        <YEAR>1988</YEAR>
    </CD>
    <CD>
        <TITLE>Greatest Hits</TITLE>
        <ARTIST>Dolly Parton</ARTIST>
        <COUNTRY>USA</COUNTRY>
        <COMPANY>RCA</COMPANY>
        <PRICE>9.90</PRICE>
        <YEAR>1982</YEAR>
      </CD>
</CATALOG>

Read, Write and Indexing

With the introduction of the native XML indexing feature since VTD-XML 2.0, you don't even have to parse XML. If cd.xml is pre-indexed, just load it up and let the binding routine go to work!  The main() can be quickly rewritten as following to entirely bypass parsing.

public static void main(String[] args) throws Exception {
    XMLBinder2 xb = new XMLBinder2();
    VTDGen vg = new VTDGen();
    XMLModifier xm = new XMLModifier(); 
    //cd.vxl is the index for cd.xml 
    VTDNav vn = vg.loadIndex("cd.vxl");
    ArrayList al2 = xb.bind2(vn);
    Iterator it2 = al2.iterator();
    xm.bind(vn);
    while(it2.hasNext()) {
        CDRecord2 cdr = (CDRecord2) it2.next();
        // reduce prices by 1
        xm.updateToken(cdr.priceIndex, ""+(cdr.price - 1));
        xm.output(new FileOutputStream("cd_update.xml"));
    }
}

Benefits

As you have seen, By using Xpath "/CATALOG/CD[ YEAR < 1990 and YEAR>1982]," the examples above only deal with the most relevant records. This is important because your applications may process XML files containing hundreds, if not thousands, of data items, most of which are not needed to drive the application logic. In addition, thanks to Xpath, you can only void extracting un-used fields. Furthermore, if some of new data fields are added, the example code will still work unmodified.

Adopting this new XML binding instantly turbocharges your XML applications. Whether it is parsing, indexing, incremental update, non-blocking XPath, or avoiding needless object creation, VTD-XML not only does many things well, it is the only tool that meets performance requirements for your next SOA project.

With VTD-XML, you also wave goodbye to all the schema related drawbacks. Your XML/SOA applications become far less likely to break and much more resilient to changes.

In other words, it is official: the performance issue of XML is no more. Welcome to the age of SOA!

Conclusion

I hope this article has helped you understand the process and benefits of the new XML data binding. XML schema is a means to an end, not an end in itself.  As you probably have seen, when XML processing is made simple enough, XML schemas are mostly a bad thing for data binding.  Why create all those objects that you never use? Finding a good solution once again requires that we change the problem first. Your SOA success starts with the first step, at the foundation. By combining XPath with VTD-XML, you can now break free of XML schema, and achieve unrivaled efficiency and agility.

Jimmy Zhang is a co-founder of XimpleWare, a provider of high performance XML processing solutions.


Return to ONJava.