HierarchicalMap Tutorial - Intermediate Level

HierarchicalMap is an interface. So anyone can implement it. This tutorial is based on BasicHierarchicalmap, a reference implementation of HierarchicalMap.

Following subjects are covered in this tutorial:

    Basic Level
  1. Getting Started
  2. Creating Structure
  3. Recovering the Data
  4. Interacting with Collections
  5. Restructuring the Map

  6. Intermediate Level
  7. Working with Stream
  8. Working with XML
  9. Handling Large XML
  10. Accessing Data Base
  11. Accessing Preferences

  12. Advanced Level
  13. Template Filling
  14. .NET Interoperability
  15. Runtime schema validation
  16. Writing Application

  17. Planned for Future
  18. IDE's plugin for coding-time schema validation and code completion

(Javascript must be enabled to allow syntax highlighting for source code snippets in this tutorial)

Intermediate Level

8. Handling Large XML

Reading whole XML can be time consuming and may require large amount of memory. In this chapter we will present another approach for XML handling.

First execute the following code:

try {
    HierarchicalMap map = new BasicHierarchicalMap();
    map.add("Author","author's name");
    map.add("Summary","summary");
    map.add("Section");
    
    FileOutputStream fout
            = new FileOutputStream("/temp/large.xml");
    XMLMapOutputStream xout = new XMLMapOutputStream(fout);
    
    //writing first portion
    xout.writeMap("Document", map);

    xout.close();
} catch(Exception e) {
    e.printStackTrace();
}

At this point, the XML written so far is:

Here, we introduce three concepts:

  • Cursor position: position where the next XML component will be written.
  • Reference position: XML can have nested elements. Reference position will indicate the parent element. Subsequent writing will create a child element relative to this parent.
  • Insertion point: Represents the point where the next map will be appended. This is the intersection between cursor position and reference position.
  • Now, let's append the following piece of HierarchicalMap:

    To do so, replace the code between first writing and closing methods by the following snippet of code:

    //writing first portion
    xout.writeMap("Document", map);
    
    //complement the code from here
    HierarchicalMap chapter = new BasicHierarchicalMap();
    chapter.put("Title", "title 1");
    chapter.put("Content", "content 1");
    
    //write first chapter
    xout.writeMap("Chapter", chapter);
    
    xout.close();

    The structure of resulting XML will be the following:

    Then, append the next snippet of code before closing the XMLMapOutputStream. Note that the content of second chapter has changed.

    chapter.put("Title", "title 2");
    chapter.put("Content", "content 2");
    
    //write second chapter
    xout.writeMap("Chapter", chapter);
    
    xout.close();

    The final structure of resulting XML will be the following:

    Strictly saying, this is not a valid XML structure because it contains three root nodes. You probablely receive an error message if you try to open the resulting document using XML aware editor. However, this is still a valid HierarchicalMap.

    Changing Reference Position

    Adding HierarchicalMap at fixed reference is too limitted to write more complex XML. Now we will show you, how to append HierarchicalMap at arbitrary position. To do so, we must use MapWriter. First, prepare the following code and execute it.

    try {
        HierarchicalMap map = new BasicHierarchicalMap();
        map.add("Author","author's name");
        map.add("Summary","summary");
        map.add("Section");
        
        FileOutputStream fout
                = new FileOutputStream("/temp/large4.xml");
        XMLMapOutputStream xout = new XMLMapOutputStream(fout);
        MapWriter mw = new MapWriter(xout);
        
        //writing first portion
        mw.writeMap("Document", map);
        
        //complement the code from here
    
        //get a new MapWriter with reference set at last 
        //position i.e. right after "Document/Section"
        MapWriter mw2 = mw.newLatestWriter();
        
        //prepare first chapter
        HierarchicalMap chapter = new BasicHierarchicalMap();
        chapter.put("Title", "title 1");
        chapter.put("Content", "content 1");
        
        //write first chapter
        mw2.writeMap("Chapter", chapter);
    
        //prepare second chapter
        chapter.put("Title", "title 2");
        chapter.put("Content", "content 2");
    
        //write second chapter
        mw2.writeMap("Chapter", chapter);
    
        xout.close();
    } catch(Exception e) {
        e.printStackTrace();
    }

    The resulting XML will be the following:

    First, the instantiation of MapWriter is pretty simple. Just instantiate it passing either MapOutputStream or XMLMapOutputStream. Then write down the map as usual using writeMap() method. Now, we have two more concepts:

  • Current position: this is usually the same as reference position. When writeMap() is called specifying the start node, the current position will be the start node's position.
  • Latest position: position where last element has been written.
  • The relationship of these positions for "mw", the first MapWriter created in the sample, after calling "mw.writeMap("Document", map);" are shown below:

    Therefore, the following snippet of code extracted from previous example, will create a MapWriter "mw2" with reference set to the node "Section".

    //get a new MapWriter with reference set at last 
    //position i.e. right after "Document/Section"
    MapWriter mw2 = mw.newLatestWriter();
        
    //prepare first chapter
    HierarchicalMap chapter = new BasicHierarchicalMap();
    chapter.put("Title", "title 1");
    chapter.put("Content", "content 1");
        
    //write first chapter
    mw2.writeMap("Chapter", chapter);

    The line "mw2.writeMap("Chapter", chapter);" will append the chapter under latest position of "mw". The relationship of positions for "mw2" are shown below:

    Reading Large XML

    For same reason, there is a MapReader to allow partial reading of XML. Try the following code and note how is similar to MapWriter.

    try {
    	FileInputStream i = 
    	    new FileInputStream("/temp/large4.xml");
    	XMLMapInputStream in = new XMLMapInputStream(i);
    	MapReader mr = new MapReader(in);
    	HierarchicalMap hmap = 
    	    mr.readMapUntil("Document/Section/Chapter");
    	System.out.println(hmap);	
    	System.out.println();	
    	//get the reader with reference set to the 
    	//last reading element
    	MapReader mr2 = (MapReader)mr.newLatestReader();
    	
    	HierarchicalMap chapter = mr2.readMap("Chapter");
    	System.out.println(chapter);
    	System.out.println();	
    	
    	chapter = mr2.readMap("Chapter");
    	System.out.println(chapter);
    	System.out.println();
    	
    	in.close();		
    } catch(Exception e) {
    	e.printStackTrace();
    }

    The result will be as below (Line brakes are inserted to fit into the screen. Actual result will produce only three lines):

    <Document><Author>author's name</Author>
    <Summary>summary</Summary><Section></Section></Document>
    
    <Title>title 1</Title><Content>content 1</Content>
    
    <Title>title 2</Title><Content>content 2</Content>
    

    Continue to Intermediate Level - Accessing Data Base