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.
We have already seen an example with delimited columns in the overview. Now let's pretend we want to 'enhance' the structure to:
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.
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.
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) ) );
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(); } }