【问题标题】:Parsing poor structured file with XMLReader使用 XMLReader 解析糟糕的结构化文件
【发布时间】:2020-05-08 19:55:02
【问题描述】:

我有以下文件

<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”

【问题讨论】:

  • 您好,欢迎来到 SO。请向我们展示一个尝试的例子。请创建完整的样本数据集。如果您也创建一个示例小提琴会容易得多。
  • 第一个文件夹的示例 - reader.ReadToFollowing("Folder");reader.ReadToFollowing("Item");if (reader.ReadToDescendant("Item")) { do {..some ..logic...} while (reader.ReadToNextSibling("Item"));它工作正常 - 我需要文件夹节点之间的迭代
  • 考虑使用 XPath 查询和/或 LINQ to XML (XElement) 以声明方式描述结果。使用低级 XML 阅读器和逻辑来跳过节点涉及更多,并且只有在性能测试表明有必要时才真正值得这样做。例如,只需使用//Folder 即可获取所有名为“文件夹”的元素。
  • 但我只需要一个特定的文件夹,而不是全部
  • 一个特定的文件夹也可以用 XPath 检索——例如,名称为xxx 的文件夹是//Folder[@name="xxx"],无论它出现在文档中的什么位置。 XPath 是处理 XML 时工具箱中的一个有用工具,无论您最终是否使用它。

标签: c#


【解决方案1】:

您只需要一个类来存储 XML 的 Folder 节点的数据。 喜欢这个:

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 根节点,请按照here 的说明使用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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-06
    • 2020-08-19
    • 2021-10-02
    • 2023-04-01
    • 2015-08-26
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    相关资源
    最近更新 更多