简体   繁体   中英

Linq to xml descendants

How can I get similar functionality to doc.Descendants() using linq against a collection of objects that contains sub collections of the same objects X levels deep?

The last nested collection contains the data in need to get at, all the other parent collections are merely groupings. I could transform the collection to an XDocument and call the descendants function but I would prefer to mimic that functionality against this object collection.

public class ProductLine
{
  public string Id {get;set;}
  public string ParentId  {get;set;}
  public string Name  {get;set;}
  public string Type  {get;set;}
  public string Level  {get;set;}
  public IEnumerable<ProductLine> Children  {get;set;}
}

I can have a list of ProductLine that contains child lists of ProductLine. The nested levels can vary depending on how the data was set up so I never know how many levels there are. The bottom most list will have a Type="Model" while every list prior will have a Type="Series" resulting in something like:

Series1
   Series2
      Series3
          Model1
          Model1
   Series2
      Model3
      Model4

With this Node class , the solution is quite easy.

Change the ProductLineClass a litte bit:

public class ProductLine
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
    // The level property is no longer needed because it is a property of the Node class
    public IEnumerable<ProductLine> Children { get; set; }
}

Create a tree:

var productlinesInAFlatList = GetListOfproductLines();

// Create alle the trees that can me made with the flad list based on Id and ParentId's
var rootNodes = Node<ProductLine>.CreateTree(productlinesInAFlatList, p => p.Id, p => p.ParentId);

// Assume there is only one tree in this flat ist
var rootNode = rootNodes.Single();

Get all info you need:

// Get the nodes that has no childnodes
var nodesWithoutChildNodes = rootNode.Descendants.Where(n => !n.Descendants.Any());

// If you just want the values of this childnodes
var values = nodesWithoutChildNodes.Values();

// When you need the levels of the values
var levels = nodesWithoutChildNodes.Select(n => n.Level);

You can use Linq's SelectMany function.

IEnumerable<ProductLine> products = <something>;
IEnumerable<ProductLine> modelProducts = products
    .SelectMany((x) => x.Children)

However, this will only flatten to one depth. You need to look a Recursive SelectMany for the full effect. See the following links for more advice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM