2012-01-09 52 views
4

好吧,我有以下XML树使用Linq To 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中很容易做到,但我无法用头来包裹它。

回答

8

您可以通过查找有没有后代元素找到叶:

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); 
+0

慎用元素的索引,检查这个问题:http://stackoverflow.com/questions/451950/get-the-xpath-to-an-xelement – Alpha 2012-01-09 21:48:01

+0

我是在寻找一种方法来如此之深在LinqToXml中这样做,我完全忽略了使用父母构建路径的简单性...... doh!如果有人知道在LinqToXml中执行该操作的方法,我会稍微留下问题。非常感谢。 – 2012-01-09 21:49:21

2

将XML解析为XDocument后,我认为您已经可以执行该操作,请使用下面的方法。请注意0​​的实现是相当令人讨厌的。请参阅this answer以获得更好的实施。

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)); 
} 
+0

我没有看到需要像其他答案一样使用扩展名。对我来说,这个答案看起来更加优雅,可读性和可维护性。 – daniloquio 2015-08-10 15:07:36