Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

XMP Parsing Help 1

Status
Not open for further replies.

UnderTheRadar

IS-IT--Management
Jun 15, 2005
15
0
0
US
Hi, I'm a little new to VBScript and I'm having some trouble traversing an xml file. I've done some C++ xml stuff a while back but I had a different parser. I'm not sure if this should be in the VBScript or XML forum, but here goes. Here's a piece of the xml file.


Code:
<facility id="TEST"_FACID> 
  <unit>TEST_UNIT</unit>
  <location>TEST_LOCATION</location>
  <street>TEST_STREET</street>
  <city>TEST_CITY</city>
  <state>TEST_STATE</state>
  <zip>TEST_ZIP</zip>
    <gateway ip="192.168.1.1">
      <navls>NAV_LOCALSERVER</navls>
      <usdls>USD_LOCALSERVER</usdls>
        <usdss count="0">
          <name>USD_STAGINGSHARE1</name>
          </usdss>
        <usdss count="0">
          <name>USD_STAGINGSHARE2</name>
          </usdss>
        <drive letter="S">
          <server>FILE_SERVER</server>
          <share>SHARE1$</share>
        </drive>
        <drive letter="T">
          <server>FILE_SERVER</server>
          <share>SHARE2$</share>
        </drive>
        <printer name="B/W PRINTER">
          <server>PRINT_SERVER</server>
        </printer>
        <printer name="COLOR PRINTER">
          <server>PRINT_SERVER</server>
        </printer>
    </gateway>
 </facility>


If you're familiar with login scripts, you can probably see what I'm trying to do here. Basically, I have a WSH file that hosts a vbscript that's running through the GPO's for users during logon. It retrieves the gateway ip address of the workstation and tries to find it in this xml file. If it finds it, I need to be able to retrieve basically all of the values for that particular gateway, drive mappings to local file shares, software distribution points, printers, virus updates, etc.

It's a very large WAN (55,000+ nodes) and everything is centrally managed (no local BDC's) so I need this to be an efficient process, hence the move to XML/VBScript with an administrative GUI, vs. the old DOS batch and CSV files we've been using.

So far, I'm able to retrieve the gateway and find it in the xml file with an xpath statement, but I'm having trouble traversing to previous and/or next relative nodes and retrieving those values. And I'm not so sure xpath is the way to go?

Here's that code:

Code:
Dim strFacid, strUnit, strLocation, strStreet, strCity, strState, strUsd, strNav

Set xml = CreateObject("MSXML2.DOMDocument")
xml.async = False
xml.setProperty "SelectionLanguage", "XPath"
xml.load("\\server\netlogon\gateways.xml")

Set xpath = xml.selectNodes("//@ip")
xpath.context = xml

buf = ""
bContinue = True
Do While (bContinue)
  Set node = Nothing
  Set node = xpath.NextNode()
  If Not (node Is Nothing) Then 
    If node.Text = strDefaultIPGateway Then
      bContinue = False
      bGWFound = True
      buf = buf & node.Text
      objIntExplorer.Document.WriteLn ("<font size=""2"";
        color=""#33CC33""><b>Gateway IP Address " & buf & ";
        Located in Facility ID Table.</b></font><br><br>"	
      Exit Do
    End If
  Else
    bContinue = False
    Dim err_NoGateway
      objIntExplorer.Document.WriteLn ("<font size=""2"";
      color=""red""><b>Unable to locate Default Gateway IP Address ";
      & strDefaultIPGateway & " in Facilitiy ID;
      Table.</b></font><br><br>")
  End If
Loop


Thanks for any help on this. I truly appreciate it.

Cheers,
UTR
 
Try For Each...

See if this is like what you are looking for...
Code:
Dim strFacid, strUnit, strLocation, strStreet, strCity, strState, strUsd, strNav

Set xml = CreateObject("MSXML2.DOMDocument")
xml.async = False
xml.setProperty "SelectionLanguage", "XPath"
xml.load("\\server\netlogon\gateways.xml")

Dim buf, color
[b]For Each Node In xml.selectNodes("//gateway")
  buf = Node.Attributes.getNamedItem("ip").Text[/b]
  If buf = strDefaultIPGateway Then
    bGWFound = True
    OutData = "Gateway IP Address " & buf & " Located in Facility ID Table."
    color = "#33CC33"
  Else
    OutData = "Unable to locate Default Gateway IP Address " & strDefaultIPGateway & " in Facilitiy ID Table."
    color = "Red"
  End If
  objIntExplorer.Document.WriteLn ("<b style='font-size:x-small;color:" & color & "'>" & OutData & "</b><br><br>")
Next

...This is assuming that your XML has mor than 1 <facility> element... and you are searching for the strDefaultIPGateway string in the //gateway/@id attribute of the XML...

If not, please give a detailed example of what your goal is...

I changed several other things as well, compare to your code, and feel free to ask questions...

Hope This Helps...
-Josh

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Thank you very much for taking the time to help me out.

Yes, there are roughly 900 <facility> elements, and sometimes multiple gateways under each of those. Each <facility> element represents a branch office and some of the larger offices with multiple subnets obviously have more than one gateway router.

By comparing the assigned default gateway IP address of their workstation to the addresses in the table, I should be able to determine the local network resources to which they'll need access.

I do have a few questions about your code. I see what you did with the "OutData". Much cleaner. Thank you.

I managed to get this working as it was before with a few changes...

Code:
Dim buf, color, [b]OutData[/b]
For Each Node In xml.selectNodes("//gateway")
  buf = Node.Attributes.getNamedItem("ip").Text
  If buf = strDefaultIPGateway Then
    bGWFound = True
    OutData = "Gateway IP Address " & buf & " Located in Facility ID Table."
    color = "#33CC33"
    [b]Exit For[/b]
  Else
    OutData = "Unable to locate Default Gateway IP Address " & strDefaultIPGateway & " in Facilitiy ID Table."
    color = "Red"
  End If
Next
[b]objIntExplorer.Document.WriteLn ("<b style='font-size:x-small;color:" & color & "'>" & OutData & "</b><br><br>")[/b]

After the gateway ip address was located, it would keep searching and not find it again and throw up the "not found" message. Did I do the right thing to fix that?

Now, I'll just need to figure out where to go from here, now that I've gained focus on the matching <gateway id=""> node, I'll need to go back to the parent node of him and get the values of the other children, siblings, uncles, cousins, amigos, etc. But I think I can figure that part out now. You've gotten me much closer. Thanks again!
 
Now, if you are just trying to match 1 single ip adress to 1 found in the list, there is an even simpler way... ;-)
Code:
Function FoundIP(IP, xml)
  Dim Node
  Set Node = xml.selectSingleNode("//gateway[b][@ip = '" & IP & "'][/b]")
  FoundIP = Not (Node Is Nothing)
End Function

Then Call like this...
Code:
Dim xml
Set xml = CreateObject("MSXML2.DOMDocument")
xml.async = False
xml.setProperty "SelectionLanguage", "XPath"
xml.load("\\server\netlogon\gateways.xml")

[COLOR=green]'... set/get strDefaultIPGateway somewhere within or above here ...[/color]

Dim color, OutData
If [b]FoundIP(xml, strDefaultIPGateway)[/b] Then
  OutData = "Gateway IP Address " & strDefaultIPGateway & " Located in Facility ID Table."
  color = "#33CC33"
Else
  OutData = "Unable to locate Default Gateway IP Address " & strDefaultIPGateway & " in Facilitiy ID Table."
  color = "Red"
End If
objIntExplorer.Document.WriteLn ("<b style='font-size:x-small;color:" & color & "'>" & OutData & "</b><br><br>")

That's the advantage of using XPath, you can add as many conditions ([]) as you like...
"//node[@ip = '123.456.789'][subnode = 'test']"
Including positions...
first node found = "//node[1]"
third node found = "//node[3]"
*With SelectSingleNode, the 1st is returned by default...

Make Sure you enclose string values with 'quotes'...

Here is some more info if you are interested:

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Oops... Didn't finish reading ;-)
Now, I'll just need to figure out where to go from here, now that I've gained focus on the matching <gateway id=""> node, I'll need to go back to the parent node of him and get the values of the other children, siblings, uncles, cousins, amigos, etc. But I think I can figure that part out now. You've gotten me much closer. Thanks again!

Do this instead, You can move it out to a function if you want... It really Doesn't matter...

Code:
Dim color, OutData, Node, xml
Set xml = CreateObject("MSXML2.DOMDocument")
xml.async = False
xml.setProperty "SelectionLanguage", "XPath"
xml.load("\\server\netlogon\gateways.xml")
[b]Set Node = xml.selectSingleNode("//gateway[@ip = '" & IP & "']/..")[/b]
If Not Node Is Nothing Then
  OutData = "Gateway IP Address " & strDefaultIPGateway & " Located in Facility ID Table."
  [b]OutData = OutData & "<br/><xmp>" & Node.xml & "</xmp>"[/b] 'Show the XML selected...
  color = "#33CC33"
Else
  OutData = "Unable to locate Default Gateway IP Address " & strDefaultIPGateway & " in Facilitiy ID Table."
  color = "Red"
End If
objIntExplorer.Document.WriteLn ("<b style='font-size:x-small;color:" & color & "'>" & OutData & "</b><br><br>")

BTW... this would be a GREAT time to look into Using XSL...

I might give an example tomorrow... (it's 1am now)

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Hi Josh,

Thanks again. Looks like I was going down a different path. I did manage to locate a specific facitility id based on the gateway, which I was very happy with.

Here's the whole function now:

FindGateway()
Code:
Function FindGateway()
Dim strFacid, strUnit, strLocation, strStreet, strCity, strState, strUsd, strNav

Set xml = CreateObject("MSXML2.DOMDocument")
xml.async = False
'xml.setProperty "SelectionLanguage", "XPath"
xml.load("\\ecswk301\netlogon\gateways.xml")

Dim buf, Node
For Each Node In xml.selectNodes("//gateway")
  buf = Node.Attributes.getNamedItem("ip").Text
  If buf = strDefaultIPGateway Then
    bGWFound = True
    OutData = "Gateway IP Address " & buf & " Located in Facility ID Table."
    color = "#33CC33"
    Exit For
  Else
    OutData = "Unable to locate Default Gateway IP Address " & strDefaultIPGateway & " in Facilitiy ID Table."
    color = "Red"
  End If
Next

SendStatus()

If (bGWFound) Then
  Set strNav = Node.FirstChild
  buf = strNav.Text
  objIntExplorer.Document.getElementById("navserver").innerHTML = "NAV Server:&nbsp;&nbsp;&nbsp;&nbsp;" & buf

  Set strUsd = Node.NextNode
  buf = strUsd.Text
  objIntExplorer.Document.getElementById("usdserver").innerHTML = "USD Server:&nbsp;&nbsp;&nbsp;&nbsp;" & buf

End If
End Function

SendStatus()
Code:
Function SendStatus()
  objIntExplorer.Document.getElementById("status").innerHTML = "<b style='font-size:x-small;color:" & color & "'>" & OutData
End Function

Unfortunately, the Set strUsd = Node.NextNode isn't giving me the value. I thought it was last night, but it's not this morning. I think it was because I was using the first group in the xml file, but now I'm using one in the middle.

Funny you mentioned XSL. I went to a book store after work yesterday and tried to find one but my client is in the boonies and the store only had two that looked pretty outdated. Any good recommendations?

I'm not sure how it's going to work though, as this XML file will play about three different roles. One of the reasons I decided to use VbScript/XML was so that there would be a way to administer all of the gateways and resources through a web interface, so I was going to use XSL there but not in the login window.
 
>>Unfortunately, the Set strUsd = Node.NextNode isn't giving me the value.

Perhaps:
strUsd = Node.NextNode.Text

>>Any good recommendations?

Forget the books, I have 4 XML books and have barely even opened them...

My favorite reference is: You can learn about XML, XSL, XPATH, DOM, etc...
It has Try-It-Yourself demos that you can play around with and see how it all works...

Google is my Second favorite reference (If I can't find something here first)

>>I'm not sure how it's going to work though, as this XML file will play about three different roles. One of the reasons I decided to use VbScript/XML was so that there would be a way to administer all of the gateways and resources through a web interface, so I was going to use XSL there but not in the login window.

You can use XSL in VBScript through DOM...
Check this out:
OutputText = xmlDom.transformNode(xslDom)

Basically...
Code:
Set xmlDom = CreateObject("MSXML.DomDocument")
Set xslDom = CreateObject("MSXML.DomDocument")
xmlDom.async = false
xslDom.async = false
xmlDom.load "my xml file.xml"
xslDom.load "my xsl file.xsl"
[b]document.write xmlDom.transformNode(xslDom)[/b]

The best part is that you can Modify the XSL via the DOM Document, before sending the XML through it... (Same applies to the XML)

I will try to provide a few samples when I get home later...

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Oh yes, very familiar with w3schools and google is my friend. I did all kinds of searches on this, but couldn't find anything specific to what I was trying to do. Most of the XML DOM walking examples/tutorials I could find were dealing with very simple XML files and using Javascript.

I'll look more into the XSL tutorials on w3schools this weekend. This is probably a silly question but how will I compare values then? Is it better to bring the data onto the document with XSL and then compare those DHTML values, or do the comparisons like this programatically as I'm dumping them into the document?

Come to think of it though, there's a good chance that there won't even be a login "splash screen" if you will. I'm just doing that for the demo. It'll be useful when I'm developing the back-end piece though.

Anyway...

The strUsd = Node.NextNode.Text isn't working either. My next line was buf = strUsd.Text, so I think we were doing the same thing.

Once I find the correct <gateway ip=""> node, I do the Set strNav = Node.FirstChild and get the <navls> node. That part works fine. Shouldn't a Node.NextNode be the next child node of <gateway ip="">? I'm confused. A light bulb came on for a second last night but then it fizzled.

 
XPATH is part of XSL...

So you can use the operators in the link I provided before...
(
So this in vbs...
Code:
[b]IP = 123.456.789[/b]
Set [b]Node[/b] = xml.selectSingleNode([b]"//gateway[@ip = '" & IP & "']/.."[/b])

Would be this in xsl (more or less)...
Code:
<xsl:variable name="[b]IP[/b]" select=[b]"123.456.789"[/b] />
<xsl:variable name="[b]Node[/b]" select=[b]"//gateway[@ip = '$IP']/.."[/b] />

Then you can access the text of the sub nodes, such as:
Code:
...
<xsl:value-of select="$Node/unit" />
<xsl:value-of select="$Node/location" />
<xsl:value-of select="$Node/street" />
<xsl:value-of select="$Node/city" />
<xsl:value-of select="$Node/state" />
<xsl:for-each select="$Node/gateway" />
  <xsl:value-of select="@ip />
  <xsl:value-of select="navls" />
  <xsl:value-of select="usdls" />
  <xsl:for-each select="usdss" />
    <xsl:value-of select="name" />
  </xsl:for-each>
  <xsl:for-each select="drive">
    <xsl:value-of select="@letter" />
    <xsl:value-of select="server" />
    <xsl:value-of select="share" />
  </xsl:for-each>
  <xsl:for-each select="printer">
    <xsl:value-of select="@name" />
    <xsl:value-of select="server" />
  </xsl:for-each>
</xsl:for-each>
...

The above code will access every node in the selected facility node...

You can remove the stuff you don't need, and add HTML tags where needed...
*Note that EVERYTHING needs a closing tag...
<br> will not work... it must be: <br/>

Then... You need to add the <html> tags around the XSL, then the <xsl:template> tags, then the root, <xsl:stylesheet> tags...
Such as:
Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
<xsl:template match="/">
 <html>

...Content XSL Code with html formatting tags...

 </html>
</xsl:template>
</xsl:stylesheet>

Save the Document... (such as "myxsl.xsl")

then do something like:
Code:
'*** Load Documents..
Set xmlDom = CreateObject("MSXML.DomDocument")
Set xslDom = CreateObject("MSXML.DomDocument")
xmlDom.async = false
xslDom.async = false
[b]xmlDom.load "facilities.xml"
xslDom.load "myxsl.xsl"[/b]
'*** Set the IP address to search for in the XSL variable tag...
[b]xslDom.selectSingleNode("//xsl:variable[@name = 'IP']").Attributes.getNamedItem("select").Text = strDefaultIPGateway[/b]
'*** Transform to HTML
document.write xmlDom.transformNode(xslDom)

Let me know if you have any questions about these examples...

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Thanks again. Wow, you're putting a lot of time into this and I really do appreciate it.

Isn't XSL used primarily for displaying information in a web page? Or could it also be used for this purpose? Since I'll be using the data to send to Event Logs, map network drives, connect printers, import to SQL, etc., I hadn't really considered XSL because I was under the impression that is was used for converting an XML file to a viewable web page.

Or am I missing something?
 
It's purpose is to filter and trasform data, usually from one XML file into another, xhtml just happens to be a form of an XML file

Check out my web page...
If you have IE, you can see what I am doing with Script and XSL...

If not, click the link at the bottom, to see the same data rendered through just XSL...

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Just had a breakthrough! It's doing everything I need it to do now and I "get it". You've been a HUGE help.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top