首页 > 解决方案 > 使用 XMLReader 解析糟糕的结构化文件

问题描述

我有以下文件

<container rev="1">
 <Folder name="root" access="all">
   <Folder name="aaa" access="user1">
     ...
   </Folder>
   <Folder name="bbb" access="user2">
     ...
   </Folder>
   <Folder name="ccc" access="user1">
     ...
   </Folder>
 ....
 </Folder>
</container>

很多文件夹封装在容器中。问题是遍历此文件夹检查文件夹名称属性的最佳方法是什么?我已经通过 Reader.skip() 和 readtofolowing() 完成了这项工作,但我不喜欢我的解决方案,因为这个文件夹块可以混合。例如需要文件夹“xxx”

标签: c#

解决方案


您只需要一个类来存储FolderXML 节点的数据。像这个:

public class Folder
{
    /// <summary>
    /// List of folders in the folder
    /// </summary>
    [XmlElement(ElementName = "Folder")]
    public List<Folder> Folders { get; set; }

    /// <summary>
    /// Name of the folder
    /// </summary>
    [XmlAttribute("name")]
    public string Name { get; set; }

    /// <summary>
    /// Access information of the folder
    /// </summary>
    [XmlAttribute("access")]
    public string Access { get; set; }

    public override string ToString()
    {
        var sb = new StringBuilder();
        ToString(sb, 0);
        return sb.ToString();
    }

    private void ToString(StringBuilder sb, int level)
    {
        const int indent = 2;
        sb.Append(new string(' ', level * indent));
        sb.AppendLine($"{Name} ({Access})");
        foreach (var folder in Folders)
            folder.ToString(sb, level + 1);
    }
}

另一个容器:

public class Container
{
    /// <summary>
    /// List of folders in the container
    /// </summary>
    [XmlElement(ElementName = "Folder")]
    public List<Folder> Folders { get; set; }

    /// <summary>
    /// Revision of the container
    /// </summary>
    [XmlAttribute("rev")]
    public string Revision { get; set; }

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine($"Container rev: {Revision}");
        foreach (var folder in Folders)
            sb.AppendLine(folder.ToString());
        return sb.ToString();
    }
}

使用XmlSerializer反序列化文件。要管理container根节点,请按照此处XmlRootAttribute的说明使用。

这里生成的程序:

class Program
{
    static void Main(string[] args)
    {
        var rootAttribute = new XmlRootAttribute { ElementName = "container", IsNullable = true };
        var serializer = new XmlSerializer(typeof(Container), rootAttribute);

        using (var reader = new StreamReader("./input.xml"))
        {
            var result = (Container)serializer.Deserialize(reader);
            Console.WriteLine(result);
        }
    }
}

有了这个内容input.xml

<container rev="1">
 <Folder name="root" access="all">
   <Folder name="aaa" access="user1">
     <Folder name="aab" access="user2" />
     <Folder name="aac" access="user2"/>
   </Folder>
   <Folder name="bbb" access="user2" />
   <Folder name="ccc" access="user1"/>
 </Folder>
</container>

输出是:

Container rev: 1
root (all)
  aaa (user1)
    aab (user2)
    aac (user2)
  bbb (user2)
  ccc (user1)

推荐阅读