将笨拙的xml文档结构转换为友好的文档结构

时间:2013-01-23 10:26:24

标签: c# algorithm linq xml-parsing linq-to-xml

好的,我有一个自动生成的xml文件,代表库中的某个文件夹结构:

<Folder>
    <Name>One</Name>
    <OutlineLevel>0</OutlineLevel>
</Folder>
<Folder>
    <Name>Two</Name>
    <OutlineLevel>1</OutlineLevel>
</Folder>
<Folder>
    <Name>Three</Name>
    <OutlineLevel>2</OutlineLevel>
</Folder>
<Folder>
    <Name>Four</Name>
    <OutlineLevel>3</OutlineLevel>
</Folder>
<Folder>
    <Name>Five</Name>
    <OutlineLevel>2</OutlineLevel>
</Folder>
<Folder>
    <Name>Six</Name>
    <OutlineLevel>3</OutlineLevel>
</Folder>
<Folder>
    <Name>Seven</Name>
    <OutlineLevel>3</OutlineLevel>
</Folder>
<Folder>
    <Name>Eight</Name>
    <OutlineLevel>1</OutlineLevel>
</Folder>

然而,我需要它在以下结构中看起来更人性化,更不尴尬:

<Folder Name="One">
    <Folder Name="Two">
        <Folder Name="Three">
            <Folder Name="Four"></Folder>
        </Folder>
        <Folder Name="Five">
            <Folder Name="Six"></Folder>
            <Folder Name="Seven"></Folder>
        </Folder>
    </Folder>
    <Folder Name="Eight"></Folder>
</Folder>

我已经看了很长时间了,而且我对如何将它包装成方法缺乏任何想法。任何建议都将受到高度赞赏。

到目前为止,我已成功将其放入我班级的对象中,如下所示:

class MyFolder
{
    private List<MyFolder> _folders;
    public List<MyFolder> Folders
    {
        get
        {   if (_folders == null)
            { _folders = new List<MyFolder>(); }
            return _folders;  }
        set { _folders = value; }
    }
    public string Name { get; set; }
}

不知道这是否导致我说实话,我现在有一个MyFolder,其MyFolders有其他MyFolders等,希望这是有道理的。

1 个答案:

答案 0 :(得分:1)

我做了一个控制台应用程序。它产生你需要的东西。我已将XML包装到FolderTree元素中,只是为了简化解析。

static void Main(string[] args)
{
    var xml = @"<FolderTree>
        <Folder>
            <Name>One</Name>
            <OutlineLevel>0</OutlineLevel>
        </Folder>
        <Folder>
            <Name>Two</Name>
            <OutlineLevel>1</OutlineLevel>
        </Folder>
        <Folder>
            <Name>Three</Name>
            <OutlineLevel>2</OutlineLevel>
        </Folder>
        <Folder>
            <Name>Four</Name>
            <OutlineLevel>3</OutlineLevel>
        </Folder>
        <Folder>
            <Name>Five</Name>
            <OutlineLevel>2</OutlineLevel>
        </Folder>
        <Folder>
            <Name>Six</Name>
            <OutlineLevel>3</OutlineLevel>
        </Folder>
        <Folder>
            <Name>Seven</Name>
            <OutlineLevel>3</OutlineLevel>
        </Folder>
        <Folder>
            <Name>Eight</Name>
            <OutlineLevel>1</OutlineLevel>
        </Folder>
        </FolderTree>
    ";

    var root = XElement.Parse(xml);
    var elements = root.Elements().ToList();
    var rootFolderString = GetItemsAtLevel(new Queue<XElement>(elements), 0).First().ToString();
}

private static void TransformElement(XElement folder)
{
    folder.Element("OutlineLevel").Remove();
    var nameElement = folder.Element("Name");
    nameElement.Remove();
    folder.Add(new XAttribute(nameElement.Name, nameElement.Value));
}

private static IEnumerable<XElement> GetItemsAtLevel(Queue<XElement> elements, int level)
{
    while (elements.Any())
    {
        var parent = elements.Dequeue();
        var children = new Queue<XElement>();
        while (elements.Any() && (int)elements.Peek().Element("OutlineLevel") > level)
        {
            children.Enqueue(elements.Dequeue());
        }

        if (children.Any())
        {
            var subtree = GetItemsAtLevel(children, level + 1);
            parent.Add(subtree);
        }

        TransformElement(parent);
        yield return parent;
    }
}