<HTML> <HEAD> <TITLE>XML to DOM Converter: Listing 3</TITLE> <APPLET CODE=com.ms.xml.dso.XMLDSO.class WIDTH=100% HEIGHT=30 ID=xmldso MAYSCRIPT=true> <PARAM NAME="url" VALUE="someXMLDocument.xml"> </APPLET> </HEAD> <BODY> <SCRIPT> _root = xmldso.getDocument().root results = window.document; // Simple stack ADT function stack() { this.depth = 0; this.data = new Array(); this.push = push; this.pop = pop; this.popTop = popTop; this.length = length; this.exists = exists; return this; } // Add an item function push( item ) { this.data[ this.depth ++ ] = item; } // Remove last item function pop() { if ( this.depth ) { this.depth --; return this.data[ this.depth ]; } return null; } // Remove item at head of stack function popTop() { if ( this.depth ) { // Pop the top item _j = this.data[ 0 ]; this.depth --; // Shuffle the stack up a place for ( _i = 0; _i < this.depth; _i ++ ) { this.data[ _i ] = this.data[ _i + 1 ] } return _j; } return null; } // Return the size of the stack function length() { return this.depth; } // Does the stack hold the specified item? function exists( obj ) { for ( _i = 0; _i < this.depth; _i ++ ) { if ( this.data[ _i ] == obj ) { return true; } } return false; } function xmltodom() { // Cache the XML root, since retrieving it more than once via // getDocument() causes an error var root = _root // Holds XML node objects var x = new stack(); // Holds incremental document description tags var y = new stack(); // Holds unique paths of descent to XML leaf nodes var d = new stack(); x.push( root ); y.push( "document." + root.tagname + "." ); while ( x.length() != 0 ) { // Pop top items, so that DOM tree is same way up as XML // tree; it would be easier simply to push them in reverse // order, but xmldso.class seems to have problems navigating // a node's child-list backwards rather than forwards var xmlTag = x.popTop(); var docTag = y.popTop(); // If the XML node is a leaf, assign its DOM equivalent its // textual value; otherwise create a new DOM object var docString = docTag.substring( 0, docTag.length - 1 ) + " = "; if ( xmlTag.children.length != 0 ) { docString += "new " + xmlTag.tagname + "();<br>"; } else { docString += "'" + xmlTag.text + "';<br>"; } results.writeln( docString ); // Check that our XML tag is of type "ELEMENT" if ( xmlTag.type == 0 ) { if ( xmlTag.children.length == 0 ) { // Generate the complete path to the element var iter = xmlTag; var t = new stack(); while ( iter.parent != null ) { t.push( iter.tagname ); iter = iter.parent; } // Reverse the path var path = ""; while ( t.length() ) { path += t.pop() + "."; } // Check whether this object path has already // been generated if ( !d.exists( path ) ) { d.push( path ); } } } // Stack children of this XML node if ( xmlTag.children ) { // Might seem logical to cache xmlTag.children, but if // you do XMLDSO won't work properly for ( i = 0; i < xmlTag.children.length; i ++ ) { x.push( xmlTag.children.item( i ) ); // How many instances of a given child node at // this level? var numInstances = 0; for ( j = 0; j < xmlTag.children.length; j ++ ) { if ( xmlTag.children.item( i ) .tagName == xmlTag.children.item( j ).tagName ) { numInstances ++; } } // Get instance index for current node var thisInstance = -1; for ( j = 0; j < i + 1; j ++ ) { if ( xmlTag.children.item( j ) .tagname == xmlTag.children.item( i ).tagname ) { thisInstance ++; } } if ( numInstances > 1 ) { y.push( docTag + xmlTag.children.item( i ) .tagname + "[ " + thisInstance + " ]." ); } else { y.push( docTag + xmlTag.children.item( i ) .tagname + "." ); } } } } // Now generate the ADT function prototypes for this XML document results.writeln( "<br>" ); // Store the tree depth we have parsed var objDepth = 0; while ( true ) { // Create an array of stacks to hold the collections // of sub-elements var newTerms = new Array(); newTerms[ newTerms.length ] = new stack(); // This will hold the immediate parent of each // "newTerms" stack var baseTerms = new Array(); for ( i = 0; i < d.length(); i ++ ) { var str = d.data[ i ]; var testDepth = 0; var lastDot = 0; for ( j = 0; j < str.length; j ++ ) { if ( testDepth == objDepth ) { break; } if ( str.charAt( j ) == "." ) { testDepth ++; if ( testDepth == objDepth - 1 ) { lastDot = j; } } } if ( j < str.length ) { var listNum = 0; var baseObject = str.substring( lastDot ? lastDot + 1 : 0, j - 1 ); // If this parent has already been assigned, // locate it; otherwise assign another one and // add it to the array var fFound = false; for ( k = 0; k < baseTerms.length; k ++ ) { if ( baseTerms[ k ] == baseObject ) { fFound = true; break; } } if ( !fFound ) { listNum = baseTerms.length; newTerms[ listNum ] = new stack(); baseTerms[ baseTerms.length ] = baseObject; } else { listNum = k; } str = str.substring( j, str.indexOf( ".", j + 1 ) ); // If the sub-element is unique, add it to the // appropriate sub-element collection if ( !newTerms[ listNum ].exists( str ) ) { newTerms[ listNum ].push( str ); } } } // Parse the two stacks, creating a Javascript object named // after each parent, and containing the collection // of sub-elements dependent upon that parent if ( objDepth != 0 ) { var fItems = false; for ( l = 0; l < baseTerms.length; l ++ ) { if ( baseTerms[ l ].length ) { results.writeln( "function " + baseTerms[ l ] + "()<br>" ); results.writeln( "{<br>" ); while ( newTerms[ l ].length() ) { fItems = true; results.writeln( " this." + newTerms[ l ].pop() + " = new Array();<br>" ); } results.writeln( " return this;<br>" ); results.writeln( "}<br><br>" ); } } // If there were no items, we have finished traversing if ( !fItems ) { break; } } objDepth ++; } } // Convert the loaded document xmltodom() </SCRIPT> </BODY> </HTML>

Script Junkie | An XML Document to JavaScript Object Converter (Web Techniques,
Related Reading
More Insights
INFO-LINK
![]() |
To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy. |