C# - 来自 XML 的目录结构

C# - Directory Structure from XML

使用 C# 我有一个包含文件夹结构的 XML 文件,用户选择主项目文件夹然后系统开始根据 [= 的结构检查主项目文件夹中的子文件夹34=] 文件。文件夹结构是动态的,因为应用程序的管理员可以通过更改 XML 文件 add/remove/modify 结构中的文件夹。

我如何遍历 XML,我尝试使用 XmlDocument 获取完整的目录路径,但我阅读了有关使用 XDocument 以获得更好结果的信息,但我对 XML 的了解仍然很基础。

XML文件结构为:

<?xml version="1.0" encoding="utf-8" ?>

<dir name="Site Documents">
  <dir name="External">
    <dir name="Mechanical">
      <dir name="01. Submittals">
        <dir name="1. Sent">
        </dir>
        <dir name="2. Received" />
      </dir>
      <dir name="02. Drawings">
        <dir name="1. Sent">
        </dir>
        <dir name="2. Received" />
      </dir>
      <dir name="03. MIR">
        <dir name="1. Sent">
        </dir>
        <dir name="2. Received" />
      </dir>
      <dir name="04. IR">
        <dir name="1. Sent">
        </dir>
        <dir name="2. Received" />
      </dir>
    </dir>
    <dir name="Electrical">
      <dir name="01. Submittals">
        <dir name="1. Sent">
        </dir>
        <dir name="2. Received" />
      </dir>
      <dir name="02. Drawings">
        <dir name="1. Sent">
        </dir>
        <dir name="2. Received" />
      </dir>
      <dir name="03. MIR">
        <dir name="1. Sent">
        </dir>
        <dir name="2. Received" />
      </dir>
      <dir name="04. IR">
        <dir name="1. Sent">
        </dir>
        <dir name="2. Received" />
      </dir>
    </dir>
  </dir>
  <dir name="Internal">
    <dir name="01. PR">
      <dir name="1. MECH">
      </dir>
      <dir name="2. ELEC" />
    </dir>
    <dir name="02. PO">
    </dir>
    <dir name="03. SRF">
    </dir>
    <dir name="04. RMR" />
  </dir>
</dir>

编辑 -- 1

我试过用这个测试代码获取节点和子节点的路径

private void button2_Click(object sender, EventArgs e)
        {
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(@"C:\Users\John_Doe\_data\directory_hirarchy.xml");
            XmlNodeList xmlFolderName = xDoc.SelectNodes("//dir");
            MessageBox.Show(xmlFolderName.Count.ToString());
            string finalText = "";
            for (int ctr = 0; ctr < xmlFolderName.Count; ctr++)
            {
                string DocFolder = xmlFolderName[ctr].Attributes["name"].InnerText;
                finalText = finalText + DocFolder + "\r\n";
            }
            txtDisplay.Text = finalText; // Test text box for Output Result
        }

文本框的输出为:

Site Documents External Mechanical 01. Submittals 1. Sent 2. Received 02. Drawings 1. Sent 2. Received 03. MIR 1. Sent 2. Received 04. IR 1. Sent 2. Received Electrical 01. Submittals 1. Sent 2. Received 02. Drawings 1. Sent 2. Received 03. MIR 1. Sent 2. Received 04. IR 1. Sent 2. Received Internal 01. PR 1. MECH 2. ELEC 02. PO 03. SRF 04. RMR

由 Daisy Shipton 解决

using System;
using System.Linq;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        var doc = XDocument.Load("test.xml");
        var directories = doc.Descendants("dir");

        foreach (var dir in directories)
        {
            var parts = dir
                .AncestorsAndSelf() // All the ancestors of this element, and itself
                .Reverse()          // Reversed (so back into document order)
                .Select(e => e.Attribute("name").Value); // Select the name
            var path = string.Join("/", parts);
            Console.WriteLine(path);
        }
    }   
}

这里有两个选项:

  • 使用递归,这样你就可以跟踪"the path so far"
  • 只看所有元素,但使用它们的祖先来构建路径

第一个可能最容易理解,是的,使用 LINQ XML 让生活更简单。

using System;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        var doc = XDocument.Load("test.xml");
        PrintDirectories(doc, null);        
    }

    static void PrintDirectories(XContainer parent, string path)
    {
        foreach (XElement element in parent.Elements("dir"))
        {
            string dir = element.Attribute("name").Value;
            string fullPath = path == null ? dir : $"{path}/{dir}";
            Console.WriteLine(fullPath);
            PrintDirectories(element, fullPath);
        }
    }
}

非递归方法的大小大致相同,但如果您不熟悉 LINQ,可能更难理解:

using System;
using System.Linq;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        var doc = XDocument.Load("test.xml");
        var directories = doc.Descendants("dir");

        foreach (var dir in directories)
        {
            var parts = dir
                .AncestorsAndSelf() // All the ancestors of this element, and itself
                .Reverse()          // Reversed (so back into document order)
                .Select(e => e.Attribute("name").Value); // Select the name
            var path = string.Join("/", parts);
            Console.WriteLine(path);
        }
    }   
}