What is a hierarchical data set?


<AspireDataSet>
    <!-- A set of key value pairs at the root level -->
    <key1>val1</key1>   
    <key2>val2</key2>

    <!-- A set of named loops -->
    <loop name="loop">
    </loop>
    <loop name="loop2">
    </loop>
</AspireDataSet>

Inner loop further expanded


<loop name="loopname">
    <row>
        <!-- a set of key value pairs -->
        <key1>val1</key1>
        <key2>val2</key2>

        <!-- a set of named loops -->
        <loop name="loopname1">
        </loop>

        <!-- a set of named loops -->
        <loop name="loopname2">
        </loop>
    </row>
    <row>
    </row>
</loop>

How is this data structure navigated


import com.ai.htmlgen.*;
import com.ai.common.TransformException;
import Java.io.*;
import com.ai.data.*;

   // above code removed for clarity 

    public static void staticTransform(ihds data, PrintWriter out) 
           throws TransformException
    {
        try
        {
            writeALoop("MainData",data,out,"");
        }
        catch(DataException x)
        {
            throw new TransformException(
            "Error: DebugTextTransform: Data Exception",x);
        }
    }
    
    /**********************************************************
     * A recursive function to write out a loop worth of ihds
     **********************************************************
     */
     
    private static void writeALoop(
      String loopname, ihds data, PrintWriter out, String is)
            throws DataException
    {
        println(out,is, ">> Writing data for loop:" + loopname);

        // write metadata
        IMetaData m = data.getMetaData();
        IIterator columns = m.getIterator();

        StringBuffer colBuffer = new StringBuffer();
        for(columns.moveToFirst();!columns.isAtTheEnd();columns.moveToNext())
        {
            String columnName = (String)columns.getCurrentElement();
            colBuffer.append(columnName).append("|");
        }
        println(out,is,colBuffer.toString());

        //write individual rows
        for(data.moveToFirst();!data.isAtTheEnd();data.moveToNext())
        {
            StringBuffer rowBuffer = new StringBuffer();
            for(columns.moveToFirst();!columns.isAtTheEnd();columns.moveToNext())
            {
                String columnName = (String)columns.getCurrentElement();
                rowBuffer.append(data.getValue(columnName));
                rowBuffer.append("|");
            }
            println(out,is,rowBuffer.toString());

            // recursive call to print children
            IIterator children = data.getChildNames();
            for(children.moveToFirst();!children.isAtTheEnd();children.moveToNext())
            {
                // for each child
                String childName = (String)children.getCurrentElement();
                ihds child = data.getChild(childName);
                writeALoop(childName,child,out,is + "\t");
            }
        }

        println(out,is,">> Writing data for loop:" + loopname + " is complete");
    }
    
    private static void println(PrintWriter out, String indentationString, 
                               String line)
    {
        out.print(indentationString);
        out.print(line);
        out.print("\n");
    }

    // code removed for clarity

How is this hds obtained declaratively


###################################
# ihdsTest data definition: section1
###################################
request.ihdsTest.className=com.ai.htmlgen.DBHashTableFormHandler1
request.ihdsTest.loopNames=loop1,loop2

#section1 - main key value pairs
request.ihdsTest.mainDataRequest.classname=com.ai.db.DBRequestExecutor2
request.ihdsTest.mainDataRequest.db=my-database
request.ihdsTest.mainDataRequest.stmt=some-select

#section2 - loop1
request.ihdsTest.loop1.class_request.className=com.ai.htmlgen.GenericTableHandler6
request.ihdsTest.loop1.loopNames=loop11
request.ihdsTest.loop1.query_request.className=com.ai.data.RowFileReader
request.ihdsTest.loop1.query_request.filename=aspire:\\samples
            \\pop-table-tags\\properties\\pop-table.data

         
#section3 - loop2
request.ihdsTest.loop2.class_request.className=com.ai.htmlgen.GenericTableHandler6
request.ihdsTest.loop2.loopNames=loop11
request.ihdsTest.loop2.query_request.className=com.ai.data.RowFileReader
request.ihdsTest.loop2.query_request.filename=aspire:\\samples
            \\pop-table-tags\\properties\\pop-table.data

#section3 - subloop to loop1
request.loop11.class_request.classname=com.ai.htmlgen.GenericTableHandler6
request.loop11.query_request.classname=com.ai.data.RowFileReader
request.loop11.query_request.filename=aspire:\\samples\\pop-table-tags
           \\properties\\pop-table.data

The APIs - ihds


package com.ai.htmlgen;
import com.ai.data.*;

/**
 * Represents a Hierarchical Data Set.
 * An hds is a collection of rows.
 * You can step through the rows using ILoopForwardIterator
 * You can find out about the columns via IMetaData.
 * An hds is also a collection loops originated using the current row.
 */
public interface ihds extends ILoopForwardIterator
{
    /**
     * Returns the parent if available
     * Returns null if there is no parent
     */
    public ihds getParent() throws DataException;

    /**
     * For the current row return a set of 
     * child loop names. ILoopForwardIteraor determines
     * what the current row is.
     * 
     * @see ILoopForwardIterator
     */
    public IIterator getChildNames() throws DataException;

    /**
     * Given a child name return the child Java object 
     * represented by ihds again
     */
    public ihds getChild(String childName) throws DataException;

    /**
     * returns a column that is similar to SUM, AVG etc of a 
     * set of rows that are children to this row.
     */
    public String getAggregateValue(String keyname) throws DataException;

    /**
     * Returns the column names of this loop or table.
     * @see IMetaData
     */
    public IMetaData getMetaData() throws DataException;

    /**
     * Releases any resources that may be held by this loop of data 
     * or table.
     */
    public void close() throws DataException;
}

The APIs - ILoopForwardIterator


package com.ai.htmlgen;
import com.ai.data.*;

public interface ILoopForwardIterator
{
   /**
    * getValue from the current row matching the key
    */
   public String getValue(final String key);

   public void moveToFirst() throws DataException;

   public void moveToNext() throws DataException;

   public boolean isAtTheEnd() throws DataException;
}

The APIs - metadata


package com.ai.data;
public interface IMetaData 
{
   public IIterator getIterator();

   public int       getColumnCount();

   public int       getIndex(final String attributeName)
      throws FieldNameNotFoundException;
}

References

1. Using Hierarchical Data Sets with Aspire and Tomcat, at OnJava.com

2. Use Aspire and Tomcat to retrieve XML declaratively from any relational database

3. Code Examples for relational data sets

3. OnJava article on relational data sets

3. Overview of data access using Aspire