Jalaj P. Jha Technical & Miscellaneous Ramblings

21Dec/060




Easy way to writing XML

The Microsoft XML component was OK for me, till I needed to write XML to be created, as previously I mostly needed it for parsing existing XML files. The biggest drawback I found was that it didnot format the generated XML with indents etc, and the result xml was a long string. As I was supposed to provide indentation also, I did it anyhow by calculating spaces required for each node... don't ask me how? It took me time, and if ever need to re-do the same, that would take even more...

At last my work finished, but what will happen when I am required to do similar thing again? I decided to give more time and rewrite the XML formation part as a DLL component, which I reproduce here. I have written the component referencing the "Microsoft XML 2.6" (msxml2.dll) and have not tested it over later versions. Since this component exposes limited properties and methods, it is relatively easier (mmm...more than that) to use for minimal requirement of writing XML files.

Dim objXMLText As DOMDocument
Dim objNodes As IXMLDOMElement
Private intCurTree As Integer
Private iChar As String
Dim varNodeTree(0 To 10)

Since, I have used Array for storing node references, the depth of nodes will be limited to the Upper bound in the Dim statement as shown above. For me 10 was more than sufficient. I feel to rewrite it using collections but I better change the upper bound there for now.

The Component exposes two Properties indentChar and XMLText

indentChar is a write-only property which allows you to specify the Characters/length you need to use for indent. By default, it assigns vbTab (tab Character)

XMLText property gives you the XML text at any moment of time. Though SaveXML method is recommended if you need to save it.

Private Sub Class_Initialize()

    iChar = vbTab

End Sub

Public Property Let indentChar(ByVal strIChar As String)

    iChar = strIChar

End Property

Public Property Get XMLText()

    XMLText = objXMLText.XML

End Property

To start writing the XML you need to call CreateXML method

Public Sub CreateXML()

    Set objXMLText = New DOMDocument

End Sub

The root element is created using CreateRootElement Method. It takes for parameter the tagname which you need to assign to root element.

Public Sub CreateRootElement(ByVal strRootName As String)

    Set varNodeTree(0) = objXMLText.createElement(strRootName)
    objXMLText.appendChild varNodeTree(0)
    intCurTree = 0

End Sub

All other node are created using CreateXMLElement method which takes a number, the node depth of parent node counting from root ( Zero for nodes whose parent is the Root Node ) apart from the tagname which is the second parameter.

Public Sub CreateXMLElement(ByVal intParent As Integer, ByVal strElementName As String)

    Dim ctr As Integer
    Dim striChars As String

    striChars = String((intParent + 1) * Len(iChar), iChar)
    varNodeTree(intParent).appendChild objXMLText.createTextNode(vbNewLine)
    varNodeTree(intParent).appendChild objXMLText.createTextNode(striChars)

    For ctr = intCurTree - 1 To intParent + 1 Step -1
        striChars = String(ctr * Len(iChar), iChar)
        varNodeTree(ctr).appendChild objXMLText.createTextNode(vbNewLine)
        varNodeTree(ctr).appendChild objXMLText.createTextNode(striChars)
    Next

    Set varNodeTree(intParent + 1) = objXMLText.createElement(strElementName)
    varNodeTree(intParent).appendChild varNodeTree(intParent + 1)

    intCurTree = intParent + 1

End Sub

Attributes and its value can be set using method SetXMLAttr which takes the index of node as described above, the attribute name and the value for the parameters.

Public Sub SetXMLAttr(ByVal intIndex As Integer, ByVal strAttrName As String, ByVal strAttrValue As String)

    varNodeTree(intIndex).setAttribute strAttrName, strAttrValue

End Sub

The text or comments between the opening and closing tag can be added using the AddText and AddComment methods passing index of node and the Text string as parameters

Public Sub AddText(ByVal intIndex As Integer, ByVal strText As String)

    varNodeTree(intIndex).appendChild objXMLText.createTextNode(strText)

End Sub

Public Sub AddComment(ByVal inIndex As Integer, ByVal strComment As String)

    varNodeTree(intIndex).appendChild objXMLText.createTextNode(vbCrLf)
    varNodeTree(intIndex).appendChild objXMLText.createComment(strComment)

End Sub

And the SaveXML method can be used to save the generated XML to a file passed as parameter.

Public Sub SaveXML(ByVal strFilePath As String)

    For ctr = intCurTree - 1 To 0 Step -1
        striChars = String(ctr * Len(iChar), iChar)
        varNodeTree(ctr).appendChild objXMLText.createTextNode(vbNewLine)
        varNodeTree(ctr).appendChild objXMLText.createTextNode(striChars)
    Next

    objXMLText.save (strFilePath)

End Sub

All this little description, it would be better if I place a little code enhance the understanding more.

A code as this one :

Dim XMLPage As New MyXMLWriter.XML
XMLPage.CreateXML
XMLPage.indentChar = "   "
XMLPage.CreateRootElement "html"
XMLPage.AddComment 0, "Comment in the HTML File"
XMLPage.CreateXMLElement 0, "head"
XMLPage.CreateXMLElement 1, "title"
XMLPage.AddText 2, "The page Title"
XMLPage.CreateXMLElement 0, "body"
XMLPage.CreateXMLElement 1, "table"
XMLPage.SetXMLAttr 2, "Border", 1
XMLPage.CreateXMLElement 2, "tr"
XMLPage.CreateXMLElement 3, "th"
XMLPage.AddText 4, "Heading 1"
XMLPage.CreateXMLElement 3, "th"
XMLPage.AddText 4, "Heading 2"
XMLPage.CreateXMLElement 2, "tr"
XMLPage.CreateXMLElement 3, "td"
XMLPage.AddText 4, "data 1"
XMLPage.CreateXMLElement 3, "td"
XMLPage.AddText 4, "data 2"
XMLPage.SaveXML "c:\\demo.html"

will generate a page as below :

<html>
<!--Comment in the HTML File-->
   <head>
      <title>The page Title</title>
   </head>
   <body>
      <table Border="1">
         <tr>
            <th>Heading 1</th>
            <th>Heading 2</th>
         </tr>
         <tr>
            <td>data 1</td>
            <td>data 2</td>
         </tr>
      </table>
   </body>
</html>
Comments (0) Trackbacks (1)

Leave a comment