简体   繁体   中英

How to return sibling XElements in a LINQ to XML statement?

From the following XML input:

<root>
  <node name="one" value="1"/>
  <node name="two" value="2"/>
  <node name="three" value="3"/>
  <node name="four" value="4"/>
</root>";

I need to use LINQ to XML to produce the following:

<root>
  <name content="one"/>
  <value content="1"/>
  <name content="two"/>
  <value content="2"/>
  <name content="three"/>
  <value content="3"/>
  <name content="four"/>
  <value content="4"/>
</root>

This code produces the name elements, but not the value elements.

var input = @"
<root>
  <node name=""one"" value=""1""/>
  <node name=""two"" value=""2""/>
  <node name=""three"" value=""3""/>
  <node name=""four"" value=""4""/>
</root>";


var xml = XElement.Parse(input);
var query = new XElement("root",
    from p in xml.Elements("node")
    select new XElement("name",
        new XAttribute("content", p.Attribute("name").Value) /*,

        new XElement("value", new XAttribute("content", p.Attribute("value").Value)) */
        )
    );

If I include the value XElement (commented out above) inside the last parenthesis then it is a child of the name element, but outside the closing parenthesis it no longer has access to q (it is outside the query).

It feels like I need to concatenate two XElements together or somehow include them in another collection that doesn't produce any XML.

You could flatten the attributes using the Enumerable.SelectMany method . In query format this is equivalent to two from clauses :

var query = new XElement("root",
    from p in xml.Elements("node")
    from a in p.Attributes()
    select new XElement(a.Name,
        new XAttribute("content", a.Value)
        )
    );

To contrast, using the actual SelectMany method and writing it fluently would look like this:

var query = new XElement("root",
        xml.Elements("node")
           .SelectMany(n => n.Attributes())
           .Select(a => new XElement(a.Name,
                new XAttribute("content", a.Value))));

However, I tend to find the query syntax to be clearer in most of SelectMany usages and I tend to stick to one format or another, although it's perfectly fine to mix both.

Using your code as starting point. Wrap the pair in an item element and then replace it with its children.

        var xml = XElement.Parse(input);
        var result = new XElement("root",
            from p in xml.Elements("node")
            select new XElement("item", 
                        new XElement("name", new XAttribute("content", p.Attribute("name").Value)),
                        new XElement("value", new XAttribute("content", p.Attribute("value").Value))));

        result.Descendants("item").ToList().ForEach(n => n.ReplaceWith(n.Elements()));

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