简体   繁体   English

在C#中使用LINQ从XML获取节点

[英]Get nodes from XML using LINQ in C#

My code is as follows: 我的代码如下:

XDocument xmlDoc = XDocument.Load("myXML.xml");

        var data = from items in xmlDoc.Root.Elements("category")
                   where items.Attribute("value").Value == "idxCategoryPlatformEngine"
                   select new
                   {
                       attribute = items.Element("attributes").Element("attribute").Element("name").Value,
                       trigger = items.Element("attributes").Element("attribute").Element("trigger").Value,
                       value = items.Element("attributes").Element("attribute").Element("value").Value,
                       minutes = items.Element("attributes").Element("attribute").Element("minutes").Value
                   };

The XML I have is as follows: 我拥有的XML如下:

<?xml version="1.0" encoding="utf-8"?>
<GMS>
    <category value="idxCategoryPlatformEngine">
        <attributes>
            <attribute>
                <name>CheckpointFileCorruptionAlarm.InAlarm</name>
                <trigger>EQ</trigger>
                 <value>TRUE</value>
                 <minutes>0</minutes>
            </attribute>
            <attribute>
                 <name>CPULoad</name>
                <trigger>GT</trigger>
                <value>60</value>
                <minutes>5</minutes>
            </attribute>
            <attribute>
                <name>Engine.Historian.InStoreForward</name>
                <trigger>EQ</trigger>
                <value>TRUE</value>
                <minutes>0</minutes>
            </attribute>
        </attributes>
    </category>
    <category value="idxCategoryApplicationEngine">
        <attributes>
            <attribute>
                <name>CheckpointFileCorruptionAlarm.InAlarm</name>
                <trigger>EQ</trigger>
                 <value>TRUE</value>
                 <minutes>0</minutes>
            </attribute>
            <attribute>
                 <name>CPULoad</name>
                <trigger>GT</trigger>
                <value>60</value>
                <minutes>5</minutes>
            </attribute>
            <attribute>
                <name>Engine.Historian.InStoreForward</name>
                <trigger>EQ</trigger>
                <value>TRUE</value>
                <minutes>0</minutes>
            </attribute>
        </attributes>
    </category>
</GMS>

Now when I run the code it does perform the query however it only returns the first attribute where I actually want all attributes. 现在,当我运行代码时,它会执行查询,但是它只返回我实际上需要所有属性的第一个属性。

I'd appreciate any help on this as it is driving me crazy, each change I make to try fix this only results in more issues! 我很乐意提供任何帮助,因为它使我发疯,我为尝试解决此问题所做的每项更改只会导致更多问题!

The problem is that by down selecting to the attribute element inside the select statement, you're only executing it once. 问题在于,通过向下选择select语句中的attribute元素,您只执行一次。 In other words, you're passing in a collection to select, and the select is running statements like items.Element("attributes").Element("attribute").Element("name").Value to get a single value and a single anonymous object. 换句话说,您传递的是一个要选择的集合,并且select正在运行诸如items.Element("attributes").Element("attribute").Element("name").Value类的语句以获取单个值和一个匿名对象。 It should look more like this (which works): 它看起来应该更像这样(有效):

var data2 = doc.Root.Elements("category")
    .Where(x => x.Attribute("value").Value == "idxCategoryPlatformEngine")
    .Elements("attributes")
    .Elements("attribute")
    .Select(x => new
    {
        attribute = x.Element("name").Value,
        trigger = x.Element("trigger").Value,
        value = x.Element("value").Value,
        minutes = x.Element("minutes").Value
    });

I'm more comfortable with the extension syntax for Linq, but this can easily be converted to the other syntax. 我对Linq的扩展语法比较满意,但是可以轻松将其转换为其他语法。

You should add one additional select into select new { } , now you are only returning values of the first attribute : 您应该在select new { }添加一个附加的select ,现在只返回第一个attribute值:

var data = from item in xmlDoc.Root.Elements("category")
           where item.Attribute("value").Value == "idxCategoryPlatformEngine"
           select new
               {
                   category = item.Attribute("value").Value,
                   attributes = from attr in item.Element("attributes")
                                select new {
                                   attribute = attr.Element("name").Value,
                                   trigger = attr.Element("trigger").Value,
                                   ...
                                }
               };

First you need to get at the Attributes element and then iterate all the Attribute elements under it. 首先,您需要获取Attributes元素,然后迭代其下的所有Attribute元素。

You can do it like this: 您可以这样做:

  XDocument xmlDoc = XDocument.Load("myXML.xml");

  var data = (from items in xmlDoc.Root.Elements("category")
              where items.Attribute("value").Value == "idxCategoryPlatformEngine"
              select new {attrs  = items.Element("attributes")})
              .SelectMany(a => a.attrs.Elements("attribute"))
              .Select(item => new {
                       attribute = item.Element("name").Value,
                       trigger = item.Element("trigger").Value,
                       value = item.Element("value").Value,
                       minutes = item.Element("minutes").Value
              });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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