【问题标题】:Build XML tree from Text File in .NET在 .NET 中从文本文件构建 XML 树
【发布时间】:2014-04-17 16:42:00
【问题描述】:

我有一个显示树结构的文本文件。空格数表示给定成员的级别。例如下面,组可以有成员或子组,子组可以有成员等等:

MainGroup
 Member1
 Member2
 Group1
  Member11
  Member12
  Group12
   Member21
   Member22
 Member3

对不起大家, 我在这里的第一次也是第一个问题是弄清楚整个格式化的事情。

这是我迄今为止尝试过的:

  1. 我正在将文本文件读入数据表(这不是必需的,但我需要数据表来为我显示数据。)。
  2. 遍历每一行(有一列),我创建一个节点。我找到了空格的数量。如果为零,我将属性添加到此节点并将其添加到 doc。如果它有空格,我会循环并继续向该节点添加子节点。那就是事情对我不起作用的地方。

    Sub ExportToEXML
        Dim datarow As DataRow
        Dim fileName As String = ""
        Dim level As Integer = 0
        Dim counter As Integer = 0
        Dim doc As XmlDocument = New XmlDocument
        Dim docNode As XmlNode = doc.CreateXmlDeclaration("1.0", "UTF-8", Nothing)
        doc.AppendChild(docNode)
        Dim ComponentsNode As XmlNode = doc.CreateElement("Components")
        doc.AppendChild(ComponentsNode)
    
        Dim firstrow As DataRow
    
        For i As Integer = 0 To dt.Rows.Count - 1
            firstrow = dt.Rows.Item(i)
            fileName = firstrow(0)
            level = CountSpacesBeforeFirstChar(fileName)
    
            Dim partNode As XmlNode = doc.CreateElement("Component")
            Dim att As XmlAttribute = doc.CreateAttribute("Name")
            att.Value = fileName
            partNode.Attributes.Append(att)
            GetChildNodes(partNode, i, doc, 0, level, dt)
            ComponentsNode.AppendChild(partNode)                   
        Next
        doc.Save("D:\TestXML.xml")    
    End Sub
    
    Private Sub GetChildNodes(ByRef xNode As XmlNode, ByRef rowInd As Integer, ByRef xDoc As   XmlDocument, level As Integer, table As DataTable)
    
        Dim lev As Integer
        Dim fileName As String
        Dim dr As DataRow
        For i As Integer = rowInd + 1 To table.Rows.Count - 1
            dr = table.Rows.Item(i)
            fileName = dr(0)
            lev = CountSpacesBeforeFirstChar(fileName)
            If lev = 0 Then 'has no children
                Exit Sub
            End If    
    
            If lev > level Then
                Dim partNode As XmlNode = xDoc.CreateElement("Component")
                Dim att As XmlAttribute = xDoc.CreateAttribute("Name")
                att.Value = fileName
                partNode.Attributes.Append(att)
                xNode.AppendChild(partNode)
                GetChildNodes(xNode, i, xDoc, lev, table)
    
            End If
        Next        
    End Sub
    

【问题讨论】:

  • 你尝试了什么?你在哪里遇到问题?发布您的代码。
  • 您能解释一下“空格数表示给定成员的级别”是什么意思吗?是固定宽度的文本文件吗?

标签: c# xml vb.net tree


【解决方案1】:

好吧,您应该读取文件(如果文件不是太大,则将整个文件读入内存,否则不会),创建一个空 XML 文档,遍历行,并根据行的缩进创建新节点并添加它们到适当的 XML 元素(例如,跟踪每个级别的“最后一个”节点并将它们添加为子元素)。当然,您可以将 XML 创建延迟到稍后阶段,并根据文件内容构建对象层次结构,并在完成后简单地对其进行序列化。或者也许这整个事情可以用一个智能的正则表达式来完成。有很多可能的解决方案。

但坦率地说:SO 不是一个让您不费吹灰之力就能神奇地获得代码的地方。 (嗯,有时确实如此,但尽管如此:在您提出一个非常笼统的问题之前,向我们展示您为实际解决问题付出了一些的努力。)

【讨论】:

    【解决方案2】:

    这是一种相对简洁的方法:

    Sub ParseHierarchy(ByRef inputFilePath As String, ByRef outputFilePath As String)
        ' We'll treat depth as zero-based to match the number of spaces in the lines
        Dim depth As Integer = -1
        Dim settings As XmlWriterSettings = New XmlWriterSettings
        settings.Indent = True
    
        Using writer As XmlWriter = XmlWriter.Create("testxml.xml", settings)
            For Each line As String In File.ReadLines(inputFilePath)
                Dim nextDepth As Integer = GetLineDepth(line)
    
                If nextDepth - depth > 1 Then
                    Throw New ApplicationException( _
                        "Depth cannot increase by more than 1 at a time.")
                End If
    
                '' Close any elements at a deeper or the same depth as the next one
                CloseElements(writer, depth - nextDepth + 1)
                depth = nextDepth
    
                writer.WriteStartElement("Component")
                writer.WriteAttributeString("Name", line.Trim())
            Next
    
            '' Close any elements that are still open
            CloseElements(writer, depth + 1)
        End Using
    End Sub
    
    Private Sub CloseElements(ByRef writer As XmlWriter, ByVal count As Integer)
        For i = 1 To count
            writer.WriteEndElement()
        Next
    End Sub
    
    Private Function GetLineDepth(line As String) As Integer
        Return Regex.Match(line, "^\s*").Length
    End Function
    

    在您的示例文件上运行时,输出为:

    <Component Name="MainGroup">
      <Component Name="Member1" />
      <Component Name="Member2" />
      <Component Name="Group1">
        <Component Name="Member11" />
        <Component Name="Member12" />
        <Component Name="Group12">
          <Component Name="Member21" />
          <Component Name="Member22" />
        </Component>
      </Component>
      <Component Name="Member3" />
    </Component>
    

    【讨论】:

    • 这正是我想做的。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 2013-02-22
    • 2010-10-29
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多