Avatar of greddin
greddin
Flag for United States of America asked on

Help with traversing xml with Microsoft.XMLDOM (non xslt)

I would like to know how to traverse an xml file using the Microsoft.XMLDOM and ASP only and non-xslt.  I have ncluded a sample of my xml file below for you to see.  I also have my code that I have so far.

When the page loads I'd like to expand the current selected section. The current selected section is determined by a query string "id" variable.

 For example, here's a sample output for what the "Products" page menu would be. If the query string id=4. (Products).

Products
    TVs
    Stereos
    DVRs
    CD Players
Services
About Us

If the user clicks on the "Services" page then the menu's sample output would be (id = 12).

Products
Services
    Installation
    Repair
About Us

And if the user clicked on About Us the sample output would be (id = 15):

Products
Services
About Us
    Employment
    Contact Us

(Clicking Employment the output would be (id=16):

Products
Services
About Us
    Employment
        Upload Resume
        Job Openings
    Contact Us

I'm just trying to show that I would always be giving an id to the code so that it knows which section to be "selected".

======== XML File =======================
<?xml version="1.0" encoding="utf-8"?>
<site href="index.htm" id="2" label="Home" level="0">
  <section href="Products/index.htm" id="3" label="Products" level="1">
    <section href="TVs/index.html" id="4" label="TVs" level="2"/>
    <section href="Stereos/index.html" id="5" label="Stereos" level="2"/>
    <section href="DVRs/index.html" id="6" label="DVRs" level="2"/>
    <section href="CDPlayers/index.html" id="10" label="CD Players" level="2"/>
  </section>
  <section href="Services/index.htm" id="12" label="Services" level="1">
    <section href="Installation/index.htm" id="13" label="Installation" level="2"/>
    <section href="Repair/index.htm" id="14" label="Repair" level="2"/>
  </section>
  <section href="AboutUs/index.htm" id="15" label="About Us" level="1">
    <section href="Employment/index.htm" id="16" label="Employment" level="2">
      <section href="Resume/index.htm" id="17" label="Upload Resume" level="3"/>
      <section href="Jobs/index.htm" id="18" label="Job Openings" level="3"/>
    </section>
    <section href="ContactUs/index.htm" id="19" label="Contact Us" level="2"/>
  </section>
</site>

The problem with this code below is that is displays too much. It displays even the root node.
======= my code so far ===============================
<%
Dim xmlDoc
Set xmlDoc = Server.CreateObject("Microsoft.XMLDOM")

sub loadXML()
    xmlDoc.async = false
    xmlDoc.load(xmlFile)

    xmlDoc.load("sitenavigation.xml")

    If xmlDoc.parseError.errorCode <> 0 Then
          Response.Write("There was an error loading the xml file!<br>")
    Else
        Response.Write("xml file loaded.<br>")
        set doc = xmlDoc.documentElement
        traverse(doc)
    End If
end sub

sub traverse(tree)
    if tree.hasChildNodes then
        Response.Write("<ul><li>")
        Response.Write("<b>" & tree.tagName & " : </b>")
        nodes = tree.childNodes.length
        For i = 0 To tree.childNodes.length - 1
            traverse(tree.childNodes(i))
        Next
        Response.Write("</li></ul>")
    else
        Response.Write(tree.text)
    end if
   
end sub

call loadXML()

%>

Thank you,
-Greg
ASPXML

Avatar of undefined
Last Comment
jkmyoung

8/22/2022 - Mon
greddin

ASKER
I tried modifying the code below to use Xpath but I'm getting this error:

Error Type:
Microsoft VBScript runtime (0x800A01B6)
Object doesn't support this property or method: 'tree.hasChildNodes'
/xml3.asp, line 23


<%
Dim xmlDoc
Set xmlDoc = Server.CreateObject("Microsoft.XMLDOM")

sub loadXML()
    xmlDoc.async = false
    xmlDoc.load("sitenavigation.xml")

    If xmlDoc.parseError.errorCode <> 0 Then
          Response.Write("There was an error loading the xml file!<br>")
    Else
        Response.Write("xml file loaded.<br>")
        'set doc = xmlDoc.documentElement
        Set xmlNode = xmlDoc.selectNodes("//section[@id='3']/section")
        'traverse(doc)
        traverse(xmlNode)
        TotalNodes = cint(xmlNode.length)
        Response.Write "TotalNodes = " & TotalNodes & "<br><br>"
    End If
end sub

sub traverse(tree)
    if tree.hasChildNodes then
        Response.Write("<ul><li>")
        Response.Write("<b>" & tree.tagName & " : </b>")
        nodes = tree.childNodes.length
        For i = 0 To tree.childNodes.length - 1
            traverse(tree.childNodes(i))
        Next
        Response.Write("</li></ul>")
    else
        Response.Write(tree.text)
    end if
   
end sub

call loadXML()

%>
jkmyoung

The reason you're getting that error is because xmlDoc.selectNodes returns a XMLNodeList, not an XMLNode.

I see a couple ways of doing this:
1. You could stick with your original main code, but changing the traverse function to ignore the root node.
sub traverse(tree)
    if tree.name != "site"  then
        Response.Write("<ul><li>")
        Response.Write("<b>" & tree.tagName & " : </b>")
   end if

2. Use your new code, and change the subfunction to accept a nodelist with id param

        Set xmlNodes = xmlDoc.selectNodes("//site/section")
        traverse(xmlNodes)

sub traverse(tree, id)
For i = 0 to tree.Count -1
  Set xmlNode = tree.item[i]
  Set xpath = "//section[@id = "+id+"]"
  if (xmlNode.parentNode.Name = "site" || xmlNode.selectNodes(xpath)) // check if valid
        Response.Write("<ul><li>")
        Response.Write("<b>" & tree.tagName & " : </b>")
        nodes = tree.childNodes.length
        For i = 0 To tree.childNodes.length - 1
            traverse(tree.childNodes(i))
        Next
        Response.Write("</li></ul>")
    else
        Response.Write(tree.text)
    end if  
end sub

Hope you can work out what you need from this.
greddin

ASKER
Ok, based on the second option you gave me, I have modifed the code to this:

<%
Dim xmlDoc
Set xmlDoc = Server.CreateObject("Microsoft.XMLDOM")

sub loadXML()
    xmlDoc.async = false
    xmlDoc.load("C:\stellent\idcm1\weblayout\websites\CNIC_HQ_Site\sitenavigation.xml")

    nodeId = Request.QueryString("nodeId")

    If xmlDoc.parseError.errorCode <> 0 Then
          Response.Write("There was an error loading the xml file!<br>")
    Else
        Response.Write("xml file loaded.<br>")
        'set doc = xmlDoc.documentElement
        'Set xmlNode = xmlDoc.selectNodes("//section[@id='65']/section")
        Set xmlNodes = xmlDoc.selectNodes("//site/section")
        traverse(xmlNodes, nodeId)
     
        'traverse(doc)
        'traverse(xmlNode)
        TotalNodes = cint(xmlNode.length)
        Response.Write "TotalNodes = " & TotalNodes & "<br><br>"
    End If
end sub

sub traverse(tree, id)
    For i = 0 to tree.Count -1
        Set xmlNode = tree.item[i]
        Set xpath = "//section[@id = "+id+"]"
          if (xmlNode.parentNode.Name = "site" || xmlNode.selectNodes(xpath))
                Response.Write("<ul><li>")
                Response.Write("<b>" & tree.tagName & " : </b>")
                nodes = tree.childNodes.length
                For i = 0 To tree.childNodes.length - 1
                    traverse(tree.childNodes(i))
                Next
                Response.Write("</li></ul>")
            else
                Response.Write(tree.text)
            end if  
    Next
end sub

call loadXML()
%>

But I'm getting this error:

Error Type:
Microsoft VBScript compilation (0x800A0414)
Cannot use parentheses when calling a Sub
/xml5.asp, line 18, column 26
traverse(xmlNodes, nodeId)
-------------------------^

Any ideas?
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
jkmyoung

Ah that's exclusively a VBScript error, didn't realize you weren't using VB.NET.
http://blogs.msdn.com/ericlippert/archive/2003/09/15/52996.aspx

Since there is no return value, call it like this:
        traverse xmlNodes, nodeId

Also nodeCount will not work the same way using this method.

I also realized           if (xmlNode.parentNode.Name = "site" || xmlNode.selectNodes(xpath))
should actually be          if (xmlNode.parentNode.Name = "site" || xmlNode.selectNodes(xpath) != null)
as this is not xslt.
greddin

ASKER
Ok calling the traverse without the parenthesis seemed to get past that error.
Now I have this error:

Error Type:
Microsoft VBScript compilation (0x800A0401)
Expected end of statement
/xml5.asp, line 29, column 23
Set xmlNode = tree.item[i]
----------------------^

Thanks for your help.
jkmyoung

Set xmlNode = tree.item(i);

does that work?
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
greddin

ASKER
Yes, it's getting there. I'm just having some syntax errors converting the Javascript to Vbscript.

I'm getting this on the for loop. Can you help me convert this?

Error Type:
Microsoft VBScript compilation (0x800A0410)
Invalid 'for' loop control variable
/xml5.asp, line 35, column 6
For i = 0 To tree.childNodes.length - 1
-----^


Here's my current file:

<%
Dim xmlDoc
Set xmlDoc = Server.CreateObject("Microsoft.XMLDOM")

sub loadXML()
    xmlDoc.async = false
    xmlDoc.load("C:\stellent\idcm1\weblayout\websites\CNIC_HQ_Site\sitenavigation.xml")

    nodeId = Request.QueryString("nodeId")

    If xmlDoc.parseError.errorCode <> 0 Then
          Response.Write("There was an error loading the xml file!<br>")
    Else
        Response.Write("xml file loaded.<br>")
        'set doc = xmlDoc.documentElement
        'Set xmlNode = xmlDoc.selectNodes("//section[@id='65']/section")
        Set xmlNodes = xmlDoc.selectNodes("//site/section")
        traverse xmlNodes, nodeId
     
        'traverse(doc)
        'traverse(xmlNode)
        TotalNodes = cint(xmlNode.length)
        Response.Write "TotalNodes = " & TotalNodes & "<br><br>"
    End If
end sub

sub traverse(tree, id)
    For i = 0 to tree.Count -1
        Set xmlNode = tree.item(i)
        Set xpath = "//section[@id = "+id+"]"
          if (xmlNode.parentNode.Name = "site") or (xmlNode.selectNodes(xpath) <> null) then
                Response.Write("<ul><li>")
                Response.Write("<b>" & tree.tagName & " : </b>")
                nodes = tree.childNodes.length
                For i = 0 To tree.childNodes.length - 1
                    traverse(tree.childNodes(i))
                Next
                Response.Write("</li></ul>")
            else
                Response.Write(tree.text)
            end if  
    Next
end sub


call loadXML()
%>
jkmyoung

You already have an i in a previous loop

For j = 0 To tree.childNodes.length - 1
    traverse(tree.childNodes(j))
Next
greddin

ASKER
Ah yes. I see that now. Now... I'm getting this error:
(File is below) Thanks for your help!

Error Type:
Microsoft VBScript runtime (0x800A01B6)
Object doesn't support this property or method: 'tree.Count'
/xml5.asp, line 28




Dim xmlDoc
Set xmlDoc = Server.CreateObject("Microsoft.XMLDOM")

sub loadXML()
    xmlDoc.async = false
    xmlDoc.load("C:\stellent\idcm1\weblayout\websites\CNIC_HQ_Site\sitenavigation.xml")

    nodeId = Request.QueryString("nodeId")

    If xmlDoc.parseError.errorCode <> 0 Then
          Response.Write("There was an error loading the xml file!<br>")
    Else
        Response.Write("xml file loaded.<br>")
        'set doc = xmlDoc.documentElement
        'Set xmlNode = xmlDoc.selectNodes("//section[@id='65']/section")
        Set xmlNodes = xmlDoc.selectNodes("//site/section")
        traverse xmlNodes, nodeId
     
        'traverse(doc)
        'traverse(xmlNode)
        TotalNodes = cint(xmlNode.length)
        Response.Write "TotalNodes = " & TotalNodes & "<br><br>"
    End If
end sub

sub traverse(tree, id)
    For i = 0 to tree.Count -1
        Set xmlNode = tree.item(i)
        Set xpath = "//section[@id = "+id+"]"
          if (xmlNode.parentNode.Name = "site") or (xmlNode.selectNodes(xpath) <> null) then
                Response.Write("<ul><li>")
                Response.Write("<b>" & tree.tagName & " : </b>")
                nodes = tree.childNodes.length
                For x = 0 To tree.childNodes.length - 1
                    traverse(tree.childNodes(x))
                Next
                Response.Write("</li></ul>")
            else
                Response.Write(tree.text)
            end if  
    Next
end sub


call loadXML()
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
jkmyoung

in VBScript it is
    For i = 0 to tree.length-1
http://www.devguru.com/technologies/xmldom/QuickRef/xmldom_properties.html
greddin

ASKER
Ok. Current error is:

Microsoft VBScript runtime (0x800A01B6)
Object doesn't support this property or method: 'xmlNode.parentNode.Name'
/xml5.asp, line 33


<%
Dim xmlDoc
Set xmlDoc = Server.CreateObject("Microsoft.XMLDOM")

sub loadXML()
    xmlDoc.async = false
    xmlDoc.load("C:\stellent\idcm1\weblayout\websites\CNIC_HQ_Site\sitenavigation.xml")

    nodeId = Request.QueryString("nodeId")

    If xmlDoc.parseError.errorCode <> 0 Then
          Response.Write("There was an error loading the xml file!<br>")
    Else
        Response.Write("xml file loaded.<br>")
        'set doc = xmlDoc.documentElement
        'Set xmlNode = xmlDoc.selectNodes("//section[@id='65']/section")
        Set xmlNodes = xmlDoc.selectNodes("//site/section")
        traverse xmlNodes, nodeId
     
        'traverse(doc)
        'traverse(xmlNode)
        TotalNodes = cint(xmlNode.length)
        Response.Write "TotalNodes = " & TotalNodes & "<br><br>"
    End If
end sub

sub traverse(tree, id)
    'For i = 0 to tree.Count -1
    For i = 0 to tree.length-1
        Set xmlNode = tree.item(i)
        xpath = "//section[@id='" & id & "']"
          if (xmlNode.parentNode.Name = "site") or (xmlNode.selectNodes(xpath) <> null) then
                Response.Write("<ul><li>")
                Response.Write("<b>" & tree.tagName & " : </b>")
                nodes = tree.childNodes.length
                For x = 0 To tree.childNodes.length-1
                    traverse(tree.childNodes(x))
                Next
                Response.Write("</li></ul>")
            else
                Response.Write(tree.text)
            end if  
    Next
end sub


call loadXML()
ASKER CERTIFIED SOLUTION
jkmyoung

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.