为什么对XML文件的Linq查询只检查许多文件的第一个参数?

问题描述

我的源文件一个XML文件,看起来像这样,但是有点大:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Controller Name="PLC1_0">
    <LibSolution>CMG</LibSolution>
    <LibName>1756-LxxES</LibName>       
    <LibVersion></LibVersion>
    <Parameter Name="ChassisName">Local</Parameter>
    <Parameter Name="Slot">0</Parameter>
    <Parameter Name="Size">4</Parameter>
    <Parameter Name="SoftwareRevision">31</Parameter>
    <Parameter Name="ProcessorType">1756-L83ES</Parameter>
    <Parameter Name="ConfigureMotion">1</Parameter>
    <Parameter Name="MotionGroupName">MotionGroup1</Parameter>
    <!--====================================================================================================================-->
    <!-- IO CONfigURATION -->
    <!--====================================================================================================================-->
    <IOInstances>
        <Instance ModuleName="GEN1" UnitName="CAB1" SubUnitName="KF0907_2">             
            <LibSolution>CMG</LibSolution>          
            <LibName>1734-IB4/C</LibName>       
            <LibVersion></LibVersion>
            <ParentModule>CLO1_CAB1_KF0901_1</ParentModule>
            <Parameter Name="IP">80</Parameter>
            <Parameter Name="Slot">6</Parameter>
            <Parameter Name="ProgNameIO">CLX1_IO</Parameter>
        </Instance>
        
        <Instance ModuleName="GEN1" UnitName="CAB1" SubUnitName="KF0907_4">             
            <LibSolution>CMG</LibSolution>          
            <LibName>1734-IB4/C</LibName>       
            <LibVersion></LibVersion>
            <ParentModule>CLO1_CAB1_KF0901_1</ParentModule>
            <Parameter Name="IP">80</Parameter>
            <Parameter Name="Slot">7</Parameter>
            <Parameter Name="ProgNameIO">CLX1_IO</Parameter>
        </Instance>
        
        <Instance ModuleName="GEN1" UnitName="CAB1" SubUnitName="KF0907_5">             
            <LibSolution>CMG</LibSolution>          
            <LibName>1734-4IOL/A</LibName>      
            <LibVersion></LibVersion>
            <ParentModule>CLO1_CAB1_KF0901_1</ParentModule>
            <Parameter Name="Slot">8</Parameter>
        </Instance>
        
        <Instance ModuleName="GEN1" UnitName="CAB1" SubUnitName="KF0910_1">             
            <LibSolution>CMG</LibSolution>          
            <LibName>1734-OB4/C</LibName>       
            <LibVersion></LibVersion>
            <ParentModule>CLO1_CAB1_KF0901_1</ParentModule>
            <Parameter Name="IP">80</Parameter>
            <Parameter Name="Slot">9</Parameter>
            <Parameter Name="ProgNameIO">CLX1_IO</Parameter>
        </Instance>         
    </IOInstances>          
</Controller>   
</root>

我的查询将目标指定为,例如具有特殊名称的参数。问题在于,LinQ看起来不像普通的sql

查询应返回所有具有ModuleName = GEN1 Parameter -> [Attribute]“ Name ”“的实例– > [值]“ 广告位

IEnumerable<XElement> finalObject = from node in xDocConfig.Descendants("IOInstances").Elements("Instance")
                                      where node.Attribute("ModuleName").Value.Equals("GEN1")
                                      where node.Element("Parameter").Attribute("Name").Value.Equals("Slot")
                                      select node;

不幸的是,它仅返回示例XML的倒数第二个实例。巧合的是,在这种情况下,缺少一些参数,因此参数“ slot”是第一个,并由我的查询找到。如果它是第二个或第三个参数,则查询找不到。

我真的不知道如何更改查询获取所有4个实例。感谢您的帮助。

解决方法

您在哪里:

where node.Element("Parameter")

似乎只针对与名称"Parameter"相匹配的第一个元素。

我相信,由于.Elements()节点中有多个Parameter元素,因此您必须使用另一种称为Instance的方法。

我相信它将返回IEnumerable,因此您将必须更改逻辑以检查属性Parameter等于Name的所有Slot节点。

https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xcontainer.elements?view=netcore-3.1#System_Xml_Linq_XContainer_Elements_System_Xml_Linq_XName _

,

更新误解了问题,要返回实际的实例,请执行以下操作:

IEnumerable<XElement> finalObject = xDocConfig.Descendants("IOInstances")
    .SelectMany(x => x.Elements("Instance").Where(i => i.Attribute("ModuleName").Value.Equals("GEN1")
    &&
    i.Elements("Parameter").Any(p => p.Attribute("Name").Value.Equals("Slot"))
    ));

基本上,您需要SelectMany来展平嵌套的集合,并需要Any()来查找其中包含元素的集合。

,

请尝试以下操作。

c#

void Main()
{
    const string fileName = @"e:\temp\prototype.xml";
    
    XDocument xdoc = XDocument.Load(fileName);

    IEnumerable<XElement> finalObject = xdoc.Descendants("IOInstances")
        .SelectMany(x => x.Elements("Instance")
            .Where(i => i.Attribute("ModuleName").Value.Equals("GEN1")
            &&
            i.Elements("Parameter").Any(p => p.Attribute("Name").Value.Equals("Slot"))
            )
        );

    finalObject.Dump();
}
,

@Juharr,您的提示将我引向了一个解决方案,这是最有用且非常简单的方法。

IEnumerable<XElement> finalObject = from node in xDocConfig.Descendants("IOInstances").Elements("Instance") 
                                    where node.Attribute("ModuleName").Value.Equals("GEN1") 
                                    where node.Elements("Parameter").Any(x => x.Attribute("Name").Value.Equals("Slot")) 
                                    select node;
  • 第一行返回一个枚举。
  • 第二行对此进行过滤 枚举,因为只有一个具有该名称的属性。
  • 第三行必须包含一个“映射”,因为要检查的参数不止一个。 lambda表达式迭代所有参数,.Any()将bool值返回到WHERE表达式。

对大家表示感谢,感谢您的努力。