为什么对 XML 文件的 Linq 查询只检查许多参数的第一个参数?
Why does a Linq query on XML file checks only the first parameter of many?
我的源文件是一个 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.
此查询应该 return 所有具有 ModuleName=GEN1 和 Parameter 的实例 --> [Attribute] "名称" --> [值] "插槽"
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;
不幸的是,它 return 只是我的示例 XML 的倒数第二个实例。巧合的是,在这种情况下缺少一些参数,因此参数“slot”是第一个并被我的查询找到。如果是第二个或第三个参数,则查询找不到。
我真的不知道如何更改我的查询以获取所有 4 个实例。感谢您的帮助。
你在哪里:
where node.Element("Parameter")
这似乎只针对与名称 "Parameter"
.
匹配的第一个元素
我相信有一种称为 .Elements()
的替代方法,您必须使用它,因为 Instance
节点中有多个 Parameter
元素。
我相信它将 return 一个 IEnumerable,因此您将不得不更改逻辑以检查属性 Name
等于 Slot
的所有 Parameter
节点.
Update误解了问题,要return实际Instances,这样做:
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;
- 第一行returns一个枚举。
- 第二行过滤这个
枚举,因为只有一个属性具有该名称。
- 第三行必须包含一个“映射”,因为要检查的参数不止一个。 lambda 表达式遍历所有参数和 .Any() returns 布尔值到 WHERE 表达式。
谢谢大家,感谢你们的努力。
我的源文件是一个 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.
此查询应该 return 所有具有 ModuleName=GEN1 和 Parameter 的实例 --> [Attribute] "名称" --> [值] "插槽"
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;
不幸的是,它 return 只是我的示例 XML 的倒数第二个实例。巧合的是,在这种情况下缺少一些参数,因此参数“slot”是第一个并被我的查询找到。如果是第二个或第三个参数,则查询找不到。
我真的不知道如何更改我的查询以获取所有 4 个实例。感谢您的帮助。
你在哪里:
where node.Element("Parameter")
这似乎只针对与名称 "Parameter"
.
我相信有一种称为 .Elements()
的替代方法,您必须使用它,因为 Instance
节点中有多个 Parameter
元素。
我相信它将 return 一个 IEnumerable,因此您将不得不更改逻辑以检查属性 Name
等于 Slot
的所有 Parameter
节点.
Update误解了问题,要return实际Instances,这样做:
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;
- 第一行returns一个枚举。
- 第二行过滤这个 枚举,因为只有一个属性具有该名称。
- 第三行必须包含一个“映射”,因为要检查的参数不止一个。 lambda 表达式遍历所有参数和 .Any() returns 布尔值到 WHERE 表达式。
谢谢大家,感谢你们的努力。