Trees

FlatTree can read and write numerous flat file structures including:

Every row in a flat file is represented by a flattree.tree.Node while each column is represented by a flattree.tree.Leaf.

See flattree.tree for an overview of all available classes to define a tree structure.

CSV

We have already seen an example with delimited columns in the overview. Now let's pretend we want to 'enhance' the structure to:

  • use a comma as column separator
  • escape commas contained in the second column
  • allow the third column to span several lines
Version,Release date,Codename
JDK 1.0,January 23\, 1996,"OAK"
JDK 1.1,February 19\, 1997,""
J2SE 1.2,December 8\, 1998,"Playground
funny name - isn't it?"
J2SE 1.3,May 8\, 2000,"Kestrel"
J2SE 1.4,February 6\, 2002,"Merlin"
J2SE 5.0,September 30\, 2004,"Tiger"
Java SE 6,December 11\, 2006,"Mustang"
Java SE 7,,"Dolphin"

The adapted structure utilizes a flattree.tree.EscapedDelimitedLeaf and a flattree.tree.QuotedDelimitedLeaf. Note that we configure the latter to always require quotes:

Node root = new DelimitedNode("Header")
            .add(
              new DelimitedNode("Row")
              .add(
                new DelimitedLeaf("Version", ',')
              ).add(
                new EscapedDelimitedLeaf("Release date", ',', '\\')
              ).add(
                new QuotedDelimitedLeaf("Codename", ',', '"', Leaf.REQUIRED)
              )
            );
        

FlatTree handles delimiters, escapes and quotes transparently for the client code.

FLR

In Fixed Length Records (FLR) columns are bound by their length:

Version         Release date        Codename
JDK 1.0             January 23, 1996OAK
JDK 1.1            February 19, 1997
J2SE 1.2            December 8, 1998Playground
J2SE 1.3                 May 8, 2000Kestrel
J2SE 1.4            February 6, 2002Merlin
J2SE 5.0          September 30, 2004Tiger
Java SE 6          December 11, 2006Mustang
Java SE 7                           Dolphin

The configuration required to read and write this structure with FlatTree is as follows. Note that the second column is configured to pad shorter values with leading space:

Node root = new DelimitedNode("Header")
            .add(
              new DelimitedNode("Row")
              .add(
                new PaddedFixedLengthLeaf("Version", 16)
              ).add(
                new PaddedFixedLengthLeaf("Release date", 20, PaddedFixedLengthLeaf.LEADING)
              ).add(
                new PaddedFixedLengthLeaf("Version", 12)
              )
            );
        

Once again FlatTree handles lengths and padding transparently for the client code. If required, each row can have a different delimiter.

Mixed structures

FlatTree supports mixed delimited and fixed-length leaves. Fixed-length nodes can contain delimited leaves and vice versa. In the next example the first column is fixed-length while the remaining columns are delimited:

Version   Release date|Codename|
JDK 1.0   January 23, 1996|OAK|
JDK 1.1   February 19, 1997||
J2SE 1.2  December 8, 1998|Playground|
J2SE 1.3  May 8, 2000|Kestrel|
J2SE 1.4  February 6, 2002|Merlin|
J2SE 5.0  September 30, 2004|Tiger|
Java SE 6 December 11, 2006|Mustang|
Java SE 7 |Dolphin|

This time we're using a pipe as leaf delimiter:

Node root = new DelimitedNode("Header")
            .add(
              new DelimitedNode("Row")
              .add(
                new PaddedFixedLengthLeaf("Version", 10)
              ).add(
                new DelimitedLeaf("Release date", '|', Leaf.REQUIRED)
              ).add(
                new DelimitedLeaf("Version", '|', Leaf.REQUIRED)
              )
            );
        

Hierarchical structures

Flat files may contain a hierarchical structure. In the following example there are two different types of lines, differentiable by their L and F prefix:

LFlatTree;http://flattree.sourceforge.net;
Fdelimited columns;supports escaping,quoting,multiple lines
Ffixed columns
Fmixed columns
Freading;hierarchical API
Fwriting;hierarchical API
FSAX adapter
FStax adapter
FXStream adapter
LX-Files
Fparses anything;supports CVS,FLR,INI,HTML,XML,XSL,XLS,DOC,...

Let us add some semantic information: This flat file lists Java parsing libraries including their key features.
Now it's easy to unveil the hierarchical structure - features (F lines) are child records of libraries (L lines).

This structure can be described with FlatTree as follows:

Node root = new SyntheticNode("Root")
            .add(
              new DelimitedNode("Library")
              .add(
                new ConstantLeaf("L")
              ).add(
                new DelimitedLeaf("Name", ';')
              ).add(
                new DelimitedLeaf("URL", ';')
              ).add(
                new DelimitedNode("Feature")
                .add(
                  new ConstantLeaf("F")
                ).add(
                  new DelimitedLeaf("Name", ';')
                ).add(
                  new DelimitedLeaf("Details", ';')
                )
              )
            );
        

Note how we use a flattree.tree.SyntheticNode since the flat file does not contain any suitable data for a root node.

The following code traverses the complete tree (skipping uninteresting parts with skip()):

        assertEquals(TreeReader.START, reader.read());
        assertEquals("root", reader.getName());

        while (reader.read() == TreeReader.START) {
            if ("Library".equals(reader.getName())) {
                final String libraryName = reader.getValues().get("Name");
                final String libraryUrl = reader.getValues().get("URL");
                System.out.println(String.format("%s - %s", libraryName, libraryUrl));

                while (reader.read() == TreeReader.START) {
                    if ("Feature".equals(reader.getName())) {

                        final String featureName = reader.getValues().get(
                                "Name");
                        final String featureDetails = reader.getValues().get(
                                "Details");
                        System.out.println(String.format("  %s - %s", featureName, featureDetails));
                    }

                    reader.skip();
                }
            } else {
                reader.skip();
            }
        }