【问题标题】:C# - Directory Structure from XMLC# - 来自 XML 的目录结构
【发布时间】:2018-04-27 09:33:15
【问题描述】:

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

如何遍历 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);
        }
    }   
}

【问题讨论】:

  • 是的,XDocument 让事情变得简单多了。您可以使用doc.Descendants("dir") 遍历所有目录元素。您说您尝试使用 XmlDocument - 您能否展示该代码并解释它对您不起作用的原因?
  • @DaisyShipton 我已经用代码编辑了我的帖子,我只是尝试用名为“dir”的元素数量创建一个循环并获取它的路径,然后使用Directory.Exists 检查它,但是这段代码不要'不返回完整路径只返回元素的名称
  • 根据文件的大小,您可以使用 XmlSerializer() 将其反序列化到内存中。使用 Xsd 创建支持对象,或者使用“编辑”菜单中的“选择性粘贴”,然后您就有可以迭代的简单 C# 对象。
  • @Tima:好的,所以您要查找的只是基于嵌套构建完整路径的代码?
  • 不需要在您的问题中编辑解决方案。您对答案的接受应该足以传达这一点。

标签: c# xml subdirectory


【解决方案1】:

这里有两个选项:

  • 使用递归,这样您就可以跟踪“到目前为止的路径”
  • 只看所有元素,但使用它们的祖先来构建路径

第一个可能最容易理解,是的,使用 LINQ to 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);
        }
    }   
}

【讨论】:

  • 我正在尝试您的第一种方法,但由于我使用的是 Windows 窗体应用程序,所以我被这行 string fullPath = path == null ? dir : $"{path}/{dir}"; 卡住了,如果这与主题无关,请见谅。
  • @Tima:应该没问题,假设您使用的是 C# 6 或更高版本的编译器。如果您使用的是早期版本的 C#,则可以使用 string fullPath = path == null ? dir : path + "/" + dir;
  • 谢谢,这两种方法都会产生这样的路径:Site Documents/External/Mechanical/01. Submittals/1. Sent
猜你喜欢
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-26
  • 2013-01-27
  • 1970-01-01
  • 1970-01-01
  • 2016-03-07
相关资源
最近更新 更多