Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 268
  • Last Modified:

xpath query for grouping

I'm trying to do this...

    Set nodList = mdoc.selectNodes( _
      "computers/computer[not(domainname=preceding-sibling:domainname)]/domainname")
    For Each nod In nodList
        MsgBox nod.nodeName & " " & nod.Text
    Next

just to get a list of domain names out of the tree, but its just not working.

mdoc is a domdocument with <computers><computer><computername>abc</computername><domainname>xyz</domainname>... etc

Any ideas? thanks
0
xassets
Asked:
xassets
  • 6
  • 4
1 Solution
 
avnerCommented:
Take alook at the Munchian grouping :

http://www.jenitennison.com/xslt/grouping/muenchian.html
0
 
sparkplugCommented:
Hi,

I think your problem is that you are missing a forward slash and double colon. e.g.

"/computers/computer[not(domainname=preceding-sibling::domainname)]/domainname"

>S'Plug<
0
 
sparkplugCommented:
Also missing a node - should actually be: "/computers/computer[not(domainname=preceding-sibling::computer/domainname)]/domainname"

>S'Plug<
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
xassetsAuthor Commented:
Thanks, but its still not working.

If I change it to

"computers/computer[not(domainname='xyz')]/domainname"

Then it does indeed return all domains except xyz (not distinct, obviously). It works with or without the front slash

The second colon gets rejected as a syntax error (expected token ')', found ':'). If I take it out, theres no syntax error but it selects no nodes.

Have tried many combinations including:

computers/computer[not(domainname=preceding-sibling:computers/computer/domainname)]/domainname

/computers/computer[not(domainname=preceding-sibling:domainname)]/domainname

computers/computer[not(.=preceding-sibling:computers/computer/domainname)]/domainname

... sadly, I am allergic to xsl, any ideas?

0
 
xassetsAuthor Commented:
Also, would there be an easy way of getting the distinct list to be case insensitive? e.g. so domains xyz and XYZ return only one value?

Thanks
0
 
xassetsAuthor Commented:
Also, would there be an easy way of getting the distinct list to be case insensitive? e.g. so domains xyz and XYZ return only one value?

Thanks
0
 
sparkplugCommented:
The preceding-sibling axis is only available in MSXML4. Once this is installed you should create your DOM object as follows:

Set mdoc = CreateObject("MSXML2.DOMDocument.4.0")

To do a case insensitive compare, you need to use ms:string-compare() which a microsoft extension to XPath.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/htm/xpath_functions_097y.asp

Here's the complete vbs code:

Set mdoc = CreateObject("MSXML2.DOMDocument.4.0")
mdoc.loadXML("<computers><computer><computername>abc</computername><domainname>xyz</domainname></computer><computer><computername>abc</computername><domainname>XYZ</domainname></computer></computers>")
mdoc.setProperty "SelectionNamespaces", "xmlns:ms='urn:schemas-microsoft-com:xslt'"
Set nodList = mdoc.selectNodes("/computers/computer[not(ms:string-compare(domainname, preceding-sibling::computer/domainname, 'en-GB', 'i') = 0)]/domainname")
For Each nod In nodList
   MsgBox nod.nodeName & " " & nod.Text
Next

>S'Plug<
0
 
xassetsAuthor Commented:
Thanks, have some points, but we are tied to msxml3 so if you have any ideas for doing this in msxml3 I'd be grateful. At present we're having to let vb do a bubblesort and distinct loop which is not ideal.

0
 
sparkplugCommented:
Actually, preceding-sibling does work in MSXML3. You need to explicitly specify the selection language. e.g mdoc.setProperty "SelectionLanguage", "XPath". Don't ask me why. Unfortunately the ms:string-compare() function does not work with MSXML3.

I guess your options are either to initially iterate through each node and apply LCase to the value or to use XSLT with some included script to do the case-insensitive compare and an output a new XML DOM containing the distinct list of nodes. The use of the latter option depends on your required output. I guess its not going to be a series of message boxes. I could give you an example of this however this will take time and require more points...

>S'Plug<
0
 
xassetsAuthor Commented:
After adding the mdoc.setProperty statement, this one finally worked and it even let me use 2 colons...

computers/computer[not(domainname=preceding::domainname)]/domainname

well done.
0
 
xassetsAuthor Commented:
In case anyone finds this in google etc, I managed to get the case insensitivity by using the xpath translate function e.g. :

"computers/computer[translate(domainname,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='" & LCase$(sDomain) & "']/computername"

0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 6
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now