Printing a DOM tree in DOM2

The current DOM level 2 specification does not standardize any method to serialize or output the DOM tree to a file, URL or memory buffer though this is to be addressed in DOM level 3 and Xerces 2.x does support an initial implementation of this as documented here. However the code to print a DOM tree using DOM2 methods is not complicated and an example is shown here. This also shows the use of attributes and checking for the type of a node. A more rigorous program might also want to check for processing instructions.

Note the use of the isWhiteSpace() method. This is a KCML extension which checks to see if a text node value consists only of whitespace characters. Such nodes occur between tags if the original document had a tab or newline at that point. This is more useful than the DOM sanctioned IsIgnorableWhitespace() as it depends on the use of a DTD to define when whitespace is ignorable.

The example also shows the use of some constants which are defined in the object and thus displayed in the workbench function browser when the object is loaded.

DIM OBJECT x, OBJECT p, OBJECT doc, OBJECT elm, count, last=0
DIM _ELEMENT_NODE=1, _TEXT_NODE=3, _CDATA_SECTION_NODE=4, _COMMENT_NODE=8
OBJECT x = CREATE "dynamic", "dyndom"
OBJECT p = x.CreateParser()
p.DoSchema = TRUE
p.DoNamespaces = TRUE
p.parse("books.xml")
REM get the Document object
OBJECT doc = p.Document
REM get its root element
OBJECT elm = doc.DocumentElement
count = 'printnode(OBJECT elm, 0)
END
DEFSUB 'printnode(OBJECT n, level)
        LOCAL DIM OBJECT e, t, count, i, acount, OBJECT alist, OBJECT a, b, nc
        t = n.NodeType
        REM print this node
        SELECT CASE t
        CASE _ELEMENT_NODE
                REM tag
                count = 1
                PRINT TAB(level);"<";n.TagName$;
                REM add any attributes
                OBJECT alist = n.Attributes
                IF (OBJECT alist <> NULL)
                        acount = alist.length
                        i = 0
                        WHILE (i < acount) DO
                                OBJECT a = alist.Item(i)
                                PRINT " ";a.NodeName$;"='";a.NodeValue$;"'";
                                i++ 
                        WEND
                END IF
        CASE _TEXT_NODE
                REM text, use KCML ext fn to check for whitespace only nodes
                IF (NOT n.isWhitespace()) THEN PRINT TAB(level + 4);n.NodeValue$
        CASE _CDATA_SECTION_NODE
                PRINT TAB(level);"<![CDATA[";n.NodeValue$;"]]>"
        CASE _COMMENT_NODE
                REM comment
                PRINT TAB(level);"<!-- ";n.NodeValue$;" -->"
        CASE ELSE
                REM some other node
                PRINT "node";t;"value '";n.NodeValue$;"'"
        END SELECT
        REM and print its children
        OBJECT e = n.FirstChild
        nc = 0
        WHILE OBJECT e <> NULL DO
                IF (nc++ == 0 AND t == _ELEMENT_NODE) THEN PRINT ">"
                count += 'printnode(OBJECT e, level + 4)
                OBJECT e = e.NextSibling
        WEND
        IF (t == _ELEMENT_NODE)
                REM if no children we can use the short form of the tag
                IF (nc == 0)
                        PRINT "/>"
                ELSE
                        PRINT TAB(level);"</";n.TagName$;">"
                END IF
        END IF
        RETURN count
END SUB

For other XML DOM examples click here.