如何使用通用文本值提取所有子节点

时间:2013-10-11 17:49:07

标签: xml vbscript

给出以下XML

<Tests>
    <AutomatedTests>
        <TestName>Test1</TestName>
        <FunctionalLibraries>
            <FunctionalLibrary>CommonLib</FunctionalLibrary>
            <FunctionalLibrary>AppTestLib</FunctionalLibrary>
            <FunctionalLibrary>Test1Lib</FunctionalLibrary>
        </FunctionalLibraries>
    </AutomatedTests>
    <AutomatedTests>
        <TestName>Test2</TestName>
        <FunctionalLibraries>
            <FunctionalLibrary>CommonLib</FunctionalLibrary>
            <FunctionalLibrary>AppTestLib</FunctionalLibrary>
            <FunctionalLibrary>Test2Lib</FunctionalLibrary>
        </FunctionalLibraries>
    </AutomatedTests>
    <AutomatedTests>
        <TestName>Test3</TestName>
        <FunctionalLibraries>
            <FunctionalLibrary>CommonLib</FunctionalLibrary>
            <FunctionalLibrary>Test3Lib</FunctionalLibrary>
        </FunctionalLibraries>
    </AutomatedTests>
</Tests>

使用VBScript,如何找到所有/ Tests / AutomatedTests节点共有的所有/ Tests / AutomatedTests / FunctionalLibraries节点。
根据上面的xml,结果应该是......

<CommonTestLibraries>
    <FunctionalLibrary>CommonLib</FunctionalLibrary>
</CommonTestLibraries>

由于

这就是我所拥有的,我希望有一个更简单的方法,因为我必须在同一个文件上多次这样做。

set tempDict = CreateObject("Scripting.Dictionary")
set commonDict = CreateObject("Scripting.Dictionary")

Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.Load(fileName)
set testNodes = xmlDoc.SelectNodes("/Tests/AutomatedTests")
isFirst = true

for each testNode in testNodes
    set functionalLibraryNodes = testNode.SelectNodes("FunctionLibraries/FunctionLibrary")
    For Each functionalLibraryNode in functionalLibraryNodes
       If not tempDict.Exists(functionalLibraryNode.Text) Then
            tempDict.Add functionalLibraryNode.Text, functionalLibraryNode.Text
       End If
    Next
    If NOT isFirst Then
        for each item in commonDict
            if tempDict.Exists(item) = false Then
                commonDict.Remove item
            End If
        Next
    Else
        Set commonDict = tempDict
        isFirst = false
    End If

    Set tempDict = nothing
    Set tempDict = CreateObject("Scripting.Dictionary")
Next

2 个答案:

答案 0 :(得分:1)

我可能会这样做:

filename = "C:\path\to\your.xml"

Set xmlDoc = CreateObject("Msxml2.DOMDocument.6.0")
xmlDoc.async = False
xmlDoc.load filename

If xmlDoc.parseError <> 0 Then
  WScript.Echo xmlDoc.parseError.reason
  WScript.Quit xmlDoc.parseError
End If

'determine the total number of tests
numTests = xmlDoc.selectNodes("/Tests/AutomatedTests").length

'count the libraries from all tests
Set commonDict = CreateObject("Scripting.Dictionary")
For Each node In xmlDoc.selectNodes("//FunctionalLibrary")
  commonDict(node.text) = commonDict(node.text) + 1
Next

'libraries common to all tests must have occurred {numTests} number of times
For Each lib In commonDict.Keys
  If commonDict(lib) = numTests Then WScript.Echo commonDict(lib)
Next

但可能有更有效的方式。

注意:该行

commonDict(node.text) = commonDict(node.text) + 1

利用表达式dict(key)自动将不存在的键添加到字典并使用空值初始化它这一事实。然后在添加中将该空值转换为0。具有相同语义的显式代码如下所示:

If Not commonDict.Exists(node.text) Then
  commonDict(node.text) = 0
Else
  commonDict(node.text) = commonDict(node.text) + 1
End If

注意: XPath表达式//FunctionalLibrary将从XML树中的任何位置选择FunctionalLibrary个节点。如果您有的任何此类节点/Tests/AutomatedTests/FunctionalLibraries的直接子节点(您提供的示例数据表明您没有),则应该使XPath表达式显式:

funclib = "/Tests/AutomatedTests/FunctionalLibraries/FunctionalLibrary"
For Each node In xmlDoc.selectNodes(funclib)
  commonDict(node.text) = commonDict(node.text) + 1
Next

答案 1 :(得分:0)

由于'常见'lib在n次测试中出现n次,因此字典方法可以简单得多:

  Dim oFS    : Set oFS  = CreateObject("Scripting.FileSystemObject")
  Dim sFSpec : sFSpec   = oFS.GetAbsolutePathName("..\data\02.xml")
  Dim oXML   : Set oXML = CreateObject("Msxml2.DOMDocument.6.0")
  oXML.load sFSpec
  If 0 = oXML.parseError Then
     Dim sXPath : sXPath     = "/Tests/AutomatedTests/FunctionalLibraries/FunctionalLibrary"
     Dim ndlFnd : Set ndlFnd = oXML.selectNodes(sXPath)
     If 0 = ndlFnd.length Then
        WScript.Echo sXPath, "not found"
     Else
        Dim dicLibs  : Set dicLibs  = CreateObject("Scripting.Dictionary")
        Dim nTests   : nTests       = ndlFnd(0).parentNode.parentNode.parentNode.childNodes.length
        WScript.Echo nTests, "tests"
        Dim ndFnd, sLib
        For Each ndFnd In ndlFnd
            sLib  = ndFnd.text
            dicLibs(sLib) = dicLibs(sLib) + 1
        Next
        For Each sLib In dicLibs.Keys()
            If dicLibs(sLib) = nTests Then
               WScript.Echo sLib, dicLibs(sLib)
            End If
        Next
     End If
  Else
     WScript.Echo oXML.parseError.reason
  End If