Easiest way to filter elements out of an XML document in .NET

佐手、 提交于 2020-01-02 09:54:03

问题


Let's say I have the following doc

<sets version="2.0">
  <setting>
    <id>set1</id>
    <value>80</value>
    <label>EVersion</label>
    <type>Val</type>
    <format>R</format>
    <bits>
      <addr>0</addr>
      <startBit>0</startBit>
      <bitWidth>8</bitWidth>
    </bitspec>
  </setting>
  <setting>
    <id>set3</id>
    <value>50</value>
    <label>GVersion</label>
    <type>Bin</type>
    <format>R</format>
    <bits>
      <addr>0</addr>
      <startBit>0</startBit>
      <bitWidth>8</bitWidth>
    </bitspec>
  </setting>
  </sets>

and I just want the ID and value elements -

<sets version="2.0">
  <setting>
    <id>set1</id>
    <value>80</value>
  </setting>
  <setting>
    <id>set3</id>
    <value>50</value>
  </setting>
  </sets>

How could I select just these using XDocument and LINQ?


回答1:


Use linq-to-xml, the following code:

var xml_str = @"<sets version=""2.0"">
  <setting>
    <id>set1</id>
    <value>80</value>
    <label>EVersion</label>
    <type>Val</type>
    <format>R</format>
    <bits>
      <addr>0</addr>
      <startBit>0</startBit>
      <bitWidth>8</bitWidth>
    </bits>
  </setting>
  <setting>
    <id>set3</id>
    <value>50</value>
    <label>GVersion</label>
    <type>Bin</type>
    <format>R</format>
    <bits>
      <addr>0</addr>
      <startBit>0</startBit>
      <bitWidth>8</bitWidth>
    </bits>
  </setting>
  </sets>";

var doc = XDocument.Parse(xml_str);

var settings = new XElement("sets",
    from setting in doc.Element("sets").Elements("setting")
    select new XElement("setting", setting.Element("id"), setting.Element("value")));

Console.WriteLine(settings);

prints:

<sets>
  <setting>
    <id>set1</id>
    <value>80</value>
  </setting>
  <setting>
    <id>set3</id>
    <value>50</value>
  </setting>
</sets>

If you don't need transformed XML, but just, say, dictionary of id -> value mapping, (storing value as int), you could do:

var doc = XDocument.Parse(xml_str);
var settings_dict = doc.Element("sets").Elements("setting").ToDictionary(s => s.Element("id").Value, s => Convert.ToInt32(s.Element("value").Value));



回答2:


var xdoc = XDocument.Load(@"c:\myxml.xml");

var settings = 
    xdoc.Element("sets").Elements("setting")
    .Select(s => new 
       { 
         Id = s.Element("id").Value, 
         Value = s.Element("value").Value 
       });

This would produce an IEnumerable of an anonymous type, with properties Id and Value (both strings).

You could create your own Setting type, and use that in the projection instead, also converting the 'value' string value to an integer if required.




回答3:


My first answer was very similar to the other answers, and wasn't as clear, so I removed it. However, I thought it would be a good exercise to write some linq that would generate the filtered XML when the desired elements were at any arbitrary depth. This is what I came up with:

Func<XElement, XElement> f = null; 
f = e => e.Name == "id" || e.Name == "value" ? e : //on a match, return the node
    new[] { new XElement(e.Name, e.Elements().Select(f)) } //else recurse
    .FirstOrDefault(y => y.Elements().Any()); //keeping subtrees with matches

XElement resultXmlElement = f(XDocument.Parse(yourXmlString).Root);


来源:https://stackoverflow.com/questions/9285708/easiest-way-to-filter-elements-out-of-an-xml-document-in-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!