【问题标题】:Returning distinct paths in XML返回 XML 中的不同路径
【发布时间】:2015-05-20 00:46:01
【问题描述】:

我有一个 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 中设置一个可以为我完成此任务的子程序。请注意,我正在使用 .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

【问题讨论】:

  • 我将对此发表评论,因为实际编写代码所需的时间比我现在想要的要长。你需要的是一个递归子程序。因此,您将一个变量设置为根 作为节点,并将其传递给循环遍历所有 的子例程的子例程。在该循环中,您为子节点设置一个变量,如果它有子节点,则将其直接传递回子例程。如果它没有孩子,那么您可以获取它的路径并将其存储在数组中或将其写入文件 - 无论您使用它做什么。
  • @Tony Hinkle,刚刚更新了我的代码块,我走对了吗?

标签: xml vb.net xpath


【解决方案1】:

试试这个:

    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 

它正确地消除了重复的路径。

【讨论】:

  • 由于我使用的是 .NET 2.0,LINQ 不可用。
  • @Gmac - 抱歉,您最初应该指定的。不过,这个答案可能对其他人有所帮助。
【解决方案2】:

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

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()

【讨论】:

    【解决方案3】:

    这比我想象的要丑得多。我不是一个真正的程序员,但我通常可以弄清楚如何完成它,但我的代码通常用于非常有限的小型实用程序,所以它只需要工作。

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

    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
    

    【讨论】:

    • @Gmac 如果这对您有用,请将其标记为答案,或者让我知道它发生了什么。我使用的是最新的 .NET,所以我不确定这是否适合您。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多