简体   繁体   中英

LINQ: How to return all child elements?

For an application I am working on, I have to display data from an XML File. There's a few transformations being done, but eventually the end result will be displayed in a treeview. When a user then clicks on a node, I want to pop up the details in a listview.

When no node has been selected, I basically use LINQ to grab the details of the first item I encounter.

Here's a simplified version of my XML

<root>
   <parent label="parent1">
      <child label="child1">
         <element1>data</element1>
         <element2>data</element2>
         ...
      </child>
      <child label="child2">
         <element1>data</element1>
         <element2>data</element2>
         ...
      </child>
   </parent>
</root>

And here's the code used to grab it (After selecting the parent-node that the treeview has been set to by means of an XPAthSelectStatement):

protected void listsSource_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
    XElement rootElement = XElement.Load(MapPath(TreeSource.DataFile));
    rootElement = rootElement.XPathSelectElement("//parent[@label='parent1']");
    XElement parentElement;

    parentElement = rootElement;

    var query = (from itemElement in parentElement.Descendants("child")
                 select new
                 {
                     varElement1 = itemElement.Element("element1").Value,
                     varElement2 = itemElement.Element("element2").Value,
                     ...
                 }).Take(1);

    e.result = Query;
}

This works a treat, and I can read out the varElement1 and varElement2 values from there. However, when I try and implement a similar mechanism for when the user actually did select a node, I seem to run into a wall.

My approach was to use another XPatchSelectStatement to get to the actual node:

parentElement = rootElement.XPathSelectElement("//child[@label='" + tvwChildren.SelectedNode.Text + "']");

But I am kind of stumped on how to now get a proper LINQ query built up to read in all elements nested under the child node. I tried using parentElement.Elements() , but that was yielding an error. I also looked at using Nodes() , but with similar results.

I suppose I could use a foreach loop to access the nodes, but then I'm not sure how to get the results into a LINQ query so I can return the same e.Result = query back.

I'm fairly new to LINQ, as you might have guessed, so any hints would be very much appreciated.

I think data binding is much easier in this case.

XDocument doc = XDocument.Load(filePath);
if (doc.Root == null)
{
throw new ApplicationException("invalid data");
}
tvwChildren.Source=doc;

But if you want in this way hope following one helps(not the exact solution)

XElement root = XElement.Load("Employees.xml");
TreeNode rootNode = new TreeNode(root.Name.LocalName);
treeView1.Nodes.Add(rootNode);
    foreach(XElement employee in root.Elements())
           {
            TreeNode employeeNode = new TreeNode("Employee ID :" + employee.Attribute("employeeid").Value);
            rootNode.Nodes.Add(employeeNode);
                 if (employee.HasElements)
                 {
                    foreach(XElement employeechild in employee.Descendants())
                     {
                        TreeNode childNode = new TreeNode(employeechild.Value);
                        employeeNode.Nodes.Add(childNode);
                     }
                 }
            }

And you can try Resharper tool for create better linq statements. It shows possible ones and you can easily convert each for,foreach loops into linq statements.

Here's the query that will give you the child element (given that there is only one child element with the specified label):

var childElement = rootNode.Descendants("child")
                           .Single(e=>e.Attribute("label").Value == "child1");

If you have more than one child elements with label="child1" but those elements are under different parent elements you can use the same approach to get first the parent element and then the child element.

Having the above, you can use this query to get all element nodes under the child node:

var elements = childElement.Descendants().Select(e=>e.Value);

I'm not entirely sure I understand what you're trying to do, but it sounds like it could be this:

var data =
    from p in xml.Root.Elements("parent")
    where p.Attribute("label").Value == "parent1"
    from c in p.Elements("child")
    where c.Attribute("label").Value == "child2"
    from d in c.Elements()
    select d.Value;

Let me know if that helps.

Using this Xml library you can write your XPath like:

XElement child = rootElement.XPathElement(
    "//parent[@label={0}]/child[@label={1}]", "parent1", "child2");

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