在XML中返回不同的路径

时间:2015-05-20 00:46:02

标签: xml vb.net xpath

我有一个XML文件,我想从中检索所有唯一路径。在以下示例中:

<?xml version="1.0" encoding="utf-8"?>
<views>
    <invoice>
        <newRa elem="0">
            <createD>20150514</createD>
            <modD>1234</modD>
            <sample>text</sample>
        </newRa>
        <total>1.99</total>
    </invoice>
</views>

我想要检索:

views/invoice/newRa/createD
views/invoice/newRa/modD
views/invoice/newRa/sample

and so on......

我对xPath有一些经验,但我不知道如何在VB中设置一个sub来为我做这个。请注意,我正在使用.NET 2.0,因此LINQ是不可能的。

编辑1:

Dim xOne As New XmlDocument
xOne.Load("d/input/oneTest.xml")

For Each rNode As XmlNode In xOne.SelectSingleNode("/")
    If rNode.HasChildNodes Then
        subHasChild(rNode)
    End If
Next



Private Sub subHasChild(ByVal cNode As XmlNode)
    Dim sNode = cNode.Name

    If cNode.HasChildNodes Then
        sNode = sNode + "/" + cNode.FirstChild.Name
        cNode = cNode.FirstChild
        subHasChild(cNode)
    End If

    Dim sw As New StreamWriter("d:\input\paths.txt")
    sw.WriteLine(sNode)
    sw.Flush() : sw.Close() : sw.Dispose()
End Sub

3 个答案:

答案 0 :(得分:2)

试试这个:

    Dim xd = <?xml version="1.0" encoding="utf-8"?>
<views>
    <invoice>
        <newRa elem="0">
            <createD>20150514</createD>
            <modD>1234</modD>
            <sample>text</sample>
        </newRa>
        <total>1.99</total>
    </invoice>
</views>

    Dim getPaths As Func(Of XElement, IEnumerable(Of String)) = Nothing
    getPaths = Function(xe) _
        If(xe.Elements().Any(), _
            xe.Elements() _
                .SelectMany( _
                    Function(x) getPaths(x), _
                    Function(x, p) xe.Name.ToString() + "/" + p) _
                .Distinct(), _
            { xe.Name.ToString() })

    Dim paths = getPaths(xd.Root)

它给了我:

views/invoice/newRa/createD 
views/invoice/newRa/modD 
views/invoice/newRa/sample 
views/invoice/total 

它正确地摆脱了重复的路径。

答案 1 :(得分:1)

感谢所有回复的人。在研究了各种方法之后,我最终使用字典来获得所有独特的路径。对于任何可能遇到过类似情况的人来说,这就是我所使用的:

Dim xdDoc As New SmlDocument
Dim sw As New StreamWriter("Output File Path")
Dim diElements As New Dictionary(Of String, Integer)

xdDoc.Load("File Path")

For Each rootNode As XmlNode In xdDoc.SelectNodes("//*")
            Dim sNode As String = rootNode.Name

            While Not rootNode.ParentNode Is Nothing _
            AndAlso Not rootNode.ParentNode.Name Is "invoice" _
            AndAlso Not rootNode.ParentNode.Name Is "#document"
                rootNode = rootNode.ParentNode
                sNode = rootNode.Name + "/" + sNode
            End While

            If Not diElements.ContainsKey(sNode) Then
                diElements.Add(sNode, 1)
            Else
                diElements(sNode) += 1
            End If
        Next
    End While

    Dim pair As KeyValuePair(Of String, Integer)
    For Each pair In diElements
        sw.WriteLine("{0} --- {1}", pair.Value, pair.Key)
    Next

    sw.Flush() : sw.Close() : sw.Dispose()

答案 2 :(得分:0)

这比我想象的要糟糕得多。我不是一个真正优秀的程序员,但我通常可以弄清楚如何完成它,但我的代码通常仅用于小型实用程序,因此它只需要工作。

注意:现在已更新为仅输出唯一路径

Private PathArray As New ArrayList

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    Dim xDoc As New XmlDocument
    Dim Output As String = ""

    xDoc.Load("C:\inetpub\wwwroot\SqlMonitor\MonitorConfig.xml")
    NodeRecurser(xDoc.SelectSingleNode("/"))

    For Each item In PathArray
        Output += item & vbCrLf
    Next

    MsgBox(Output)

    Me.Close()

End Sub

Sub NodeRecurser(xNode As XmlNode)

    If xNode.HasChildNodes Then

        For Each cNode As XmlNode In xNode.ChildNodes

            NodeRecurser(cNode)

        Next

    Else : GetPath(xNode)

    End If

End Sub

Sub GetPath(n As XmlNode)

    Dim xPath As String = ""

    Do

        If n.ParentNode.Name <> "#document" Then

            xPath = n.ParentNode.Name & "/" & xPath
            n = n.ParentNode

        Else : Exit Do

        End If

    Loop

    If xPath.Length > 1 And Not PathArray.Contains(xPath) Then PathArray.Add(xPath)

End Sub