【问题标题】:Avoid recursion on this function XML related避免在此函数上递归 XML 相关
【发布时间】:2015-02-17 19:29:49
【问题描述】:

此函数检索 XML 文档的 XPath:

''' <summary>
''' Gets all the XPath expressions of an <see cref="Xml.XmlDocument"/> document.
''' </summary>
''' <param name="Document">Indicates the <see cref="Xml.XmlDocument"/> object.</param>
''' <returns>List(Of System.String).</returns>
Public Function GetXmlXPaths(ByVal Document As Xml.XmlDocument) As List(Of String)

    Dim XPathList As New List(Of String)

    Dim XPath As String = String.Empty

    For Each Child As Xml.XmlNode In Document.ChildNodes

        If Child.NodeType = Xml.XmlNodeType.Element Then
            GetXmlXPaths(Child, XPathList, XPath)
        End If

    Next ' child

    Return XPathList

End Function

''' <summary>
''' Gets all the XPath expressions of an <see cref="Xml.XmlNode"/>.
''' </summary>
''' <param name="Node">Indicates the <see cref="Xml.XmlNode"/>.</param>
''' <param name="XPathList">Indicates a ByReffered XPath list as a <see cref="List(Of String)"/>.</param>
''' <param name="XPath">Indicates the current XPath.</param>
Private Sub GetXmlXPaths(ByVal Node As Xml.XmlNode,
                         ByRef XPathList As List(Of String),
                         Optional ByVal XPath As String = Nothing)

    XPath &= "/" & Node.Name

    If Not XPathList.Contains(XPath) Then
        XPathList.Add(XPath)
    End If

    For Each Child As Xml.XmlNode In Node.ChildNodes

        If Child.NodeType = Xml.XmlNodeType.Element Then
            GetXmlXPaths(Child, XPathList, XPath)
        End If

    Next ' child

End Sub

这是一个用法示例:

Private Sub Test() 

    Dim xml As New Xml.XmlDocument
    xml.LoadXml((<?xml version="1.0" encoding="Windows-1252"?>
                 <!--XML Songs Database-->
                 <Songs>
                     <Song><Name>My Song 1.mp3</Name></Song>
                     <Song><Name>My Song 2.ogg</Name></Song>
                     <Song><Name>My Song 3.wav</Name></Song>
                 </Songs>).ToString)

    Dim xPathList As List(Of String) = GetXmlXPaths(xml)

    ListBox1.Items.AddRange(xPathList.ToArray)


End Sub

我想在实现迭代器的同时改进函数以避免递归:

Public Iterator Function GetXmlXPaths(ByVal document As Xml.XmlDocument) _
As IEnumerable(Of String)

    Yield ...

End Function

我该怎么做?

【问题讨论】:

  • 您想删除递归的任何具体原因?
  • 有两个原因,第一个只是为了美观(在外面调用方法很丑),第二个更重要的是,迭代器的实现将改善非常大的 XML 的执行时间文档,因为它记住了集合上的索引。感谢您的评论。
  • 您必须从 xml 树的文档遍历中构建一个迭代器。如果没有当前根路径的一些隐藏簿记,我看不出你是如何管理它的,它本质上表示与递归堆栈相同的信息。因此,我不会期望太多的性能提升。如果在收集 xpath 时不依赖文档 order,则可以首先处理每组同级元素的节点并在第二遍中递归。这应该避免需要将索引记住到集合中。
  • 为什么你认为去掉递归会改进函数?

标签: .net xml vb.net function recursion


【解决方案1】:

您可以尝试使用 XmlReader 的读取功能。这将一一读取所有节点。然后它只是将先前的节点存储在列表中。我不知道这对更大的 xml 效果如何。

    Dim xml As New Xml.XmlDocument
    xml.LoadXml((<?xml version="1.0" encoding="Windows-1252"?>
                 <!--XML Songs Database-->
                 <Songs>
                     <Song><Name>My Song 1.mp3</Name></Song>
                     <Song><Name>My Song 2.ogg</Name></Song>
                     <Song><Name>My Song 3.wav</Name></Song>
                 </Songs>).ToString)

    Dim xPathList As New List(Of String)

    Dim reader As XmlReader = xml.CreateNavigator.ReadSubtree
    Dim curNodes As New List(Of String)
    Dim curPath As String

    While reader.Read()
        If reader.NodeType = XmlNodeType.Element Then
            If curNodes.Count <= reader.Depth Then
                curNodes.Add(reader.Name)
            Else
                curNodes(reader.Depth) = reader.Name
            End If

            curPath = String.Join("/", curNodes.ToArray(), 0, reader.Depth + 1)

            If Not xPathList.Contains(curPath) Then
                xPathList.Add(curPath)
            End If
        End If
    End While

    For Each s As String In xPathList
        Console.WriteLine(s)
    Next

【讨论】:

  • 我说了我所说的,但我真的不太担心这个解决方案的性能,我更喜欢美学(对不起我的英语)。感谢您的帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-22
  • 2021-07-31
  • 1970-01-01
  • 2010-10-15
  • 2017-01-31
  • 2013-06-28
  • 1970-01-01
相关资源
最近更新 更多