Используя Linq To XML, метод, чтобы получить путь ко всем листьям? - PullRequest
5 голосов
/ 10 января 2012

Хорошо, у меня есть следующее дерево XML

<root>
    <A>
        <A1>
            <A1A>1000</A1A>
            <A1B>2000</A1B>
            <A1C>3000</A1C>
        </A1>
        <A2>
            <A2A>4000</A2A>
            <A2B>5000</A2B>
        </A2>
    </A>
    <B>
        <B1>
            <B1A>6000</B1A>
        </B1>
    </B>
</root>

Из метода, получающего XDocument, я хочу создать словарь, в котором ключ - это путь (на самом деле XPath), а значение исходит из значения в соответствующем листе.

root/A/A1/A1A    1000
root/A/A1/A1B    2000
root/A/A1/A1C    3000
root/A/A2/A2A    4000
root/A/A2/A2B    5000
root/B/B1/B1A    6000

Кажется, что это легко сделать в Linq to XML, но я не могу обойти это.

Ответы [ 2 ]

9 голосов
/ 10 января 2012

Вы можете найти листья, ища элементы, которые не имеют потомков:

var doc = XDocument.Load(fileName);
var leaves = 
    from e in doc.Descendants()
    where !e.Elements().Any()
    select e;

Я не знаю, есть ли встроенный способ получить путь к элементу, но вы можетелегко создать метод расширения для его построения:

static class Extensions
{
    public static string Path(this XElement element)
    {
        XElement tmp = element;
        string path = string.Empty;
        while (tmp != null)
        {
            path = "/" + tmp.Name + path;
            tmp = tmp.Parent;
        }
        return path;
    }
}

Затем вы можете построить словарь так:

var dict = leaves.ToDictionary(e => e.Path(), e => e.Value);
3 голосов
/ 10 января 2012

После анализа XML в XDocument, который, как я полагаю, вы уже смогли сделать, используйте методы ниже. Обратите внимание, что реализация GetPath() довольно наивна. См. этот ответ для лучшей реализации.

public Dictionary<string, string> GetLeaves(XDocument doc)
{
    var dict = doc
        .Descendants()
        .Where(e => !e.HasElements)
        .ToDictionary(e => GetPath(e), e.Value);

    return dict;
}

private string GetPath(XElement element)
{
    var nodes = new List<string>();
    var node = element;
    while (node != null)
    {
        nodes.Add(node.Name.ToString());
        node = node.Parent;
    }

    return string.Join("/", Enumerable.Reverse(nodes));
}
...