XML Linq 查询中间的 If-Statement

If-Statement in the middle of XML Linq Query

提问人:Ryan Daley 提问时间:7/11/2022 最后编辑:FildorRyan Daley 更新时间:7/11/2022 访问量:68

问:

我知道关于 if 语句与 Linq 组合的类似线程已经存在,但在大多数情况下,他们建议在查询之前设置条件。就我而言,条件是查询中的 XML 元素。因此,我需要遍历所有父元素,并根据 Parent 包含的内容选择不同的子元素。

让我们看一下我的 xml 文件的示例。有两种不同类型的属性:Uda 和 Template。我需要获取两种类型的属性的名称(“TemplateName”或“UdaName”)。属性的结构彼此略有不同,因此我需要对每个属性进行略有不同的 Linq 查询。

<PropertySet referenceId="column_common">
  <Name>Pset_ColumnCommon</Name>
  <Description>Common Properties to column elements</Description>
  <Properties>   
    <Property xsi:type="PropertySingleValueType" optional="true">
      <PropertyValue xsi:type="StringValueType" stringType="IfcIdentifier">
        <GetValue xsi:type="TemplateVariableType">
          <TemplateName>PART_POS</TemplateName>
        </GetValue>
      </PropertyValue>
    </Property>
    <Property xsi:type="PropertySingleValueType" optional="true">
      <PropertyValue xsi:type="BooleanValueType">
        <ValueConversion xsi:type="BooleanTypeFromIntegerVariable">
          <GetValue xsi:type="UdaVariableType">
            <UdaName>LOAD_BEARING</UdaName>
          </GetValue>
          <KeyValuePair>
            <Key>0</Key>
            <Value>false</Value>
          </KeyValuePair>
        </ValueConversion>
        <Default>true</Default>
      </PropertyValue>
    </Property>
  </Properties>
</PropertySet>    

如果它们都是 Template 属性,我可以简单地使用此 Linq 查询来获取 Names。

var propertyNames = from psetdefs in xElement.Elements(ns + "PropertySetDefinitions")
                    from pset in psetdefs.Elements(ns + "PropertySet")
                    where (string)pset.Attribute("referenceId").Value == PsetBinding
                    from props in pset.Elements(ns + "Properties")
                    from prop in props.Elements(ns + "Property")
                    from propValue in prop.Elements(ns + "PropertyValue")
                    from getValue in propValue.Elements(ns + "GetValue")
                    from templateName in getValue.Elements(ns + "TemplateName")
                    select templateName.Value;

我希望能够在 Linq 查询的中间放置一个 if 语句。这是我试图实现的逻辑,但显然它不起作用:

var propertyNames = from psetdefs in xElement.Elements(ns + "PropertySetDefinitions")
                    from pset in psetdefs.Elements(ns + "PropertySet")
                    where (string)pset.Attribute("referenceId").Value == PsetBinding
                    from props in pset.Elements(ns + "Properties")
                    from prop in props.Elements(ns + "Property")
                    from propValue in prop.Elements(ns + "PropertyValue")
                                    

if (propValue.Contains(ns + "ValueConverstion"))
{
    from valCon in propValue.Elements(ns + "ValueConversion")
    from getValue in valCon.Elements(ns + "GetValue")
    from templateName in getValue.Elements(ns + "TemplateName")
    select templateName.Value;
}
else
{
    from getValue in propValue.Elements(ns + "GetValue")
    from templateName in getValue.Elements(ns + "TemplateName")
    select templateName.Value;
}   

您可以看到它在树中有一个额外的元素,如果它是 UdaProperty。因此,查询变得不同。我该如何处理?

C# .NET LINQ-to-XML

评论

0赞 Fildor 7/11/2022
正确格式化代码片段将不胜感激。
0赞 Fildor 7/11/2022
您是否考虑过改用 XPath

答:

0赞 Orace 7/11/2022 #1

最简单的方法是使用以下方法:DefaultIfEmpty

var propertyNames = from psetdefs in xElement.Elements(ns + "PropertySetDefinitions")
                    from pset in psetdefs.Elements(ns + "PropertySet")
                    where pset.Attribute("referenceId")?.Value == PsetBinding
                    from props in pset.Elements(ns + "Properties")
                    from prop in props.Elements(ns + "Property")
                    from propValue in prop.Elements(ns + "PropertyValue")
                    from valCon in propValue.Elements(ns + "ValueConverstion").DefaultIfEmpty(propValue)
                    from getValue in valCon.Elements(ns + "GetValue")
                    from templateName in getValue.Elements(ns + "TemplateName")
                    select templateName.Value;

另一种选择是使用三元运算符:

from valCon in (propValue.Contains("ValueConverstion") ? propValue.Elements(ns + "ValueConverstion") : new[] {propValue})

最后,XPath 更容易匹配您提供的示例文件。//GetValue/UdaName|//GetValue/TemplateName

评论

0赞 Orace 7/11/2022
它也不起作用,最终标签在第一种情况下和第二种情况下。TemplateNameUdaName
0赞 Ryan Daley 7/11/2022
伟大!这解决了我的问题!您的解决方案适用于这种特殊情况。但是,在 Linq 中是否有可以实现 if 语句逻辑的地方?我可以看到它在某些情况下很有用。
0赞 Ryan Daley 7/11/2022
我通过获取“GetValue”的所有子元素来使其工作。在这种情况下,这是有效的。
0赞 Orace 7/11/2022
不能放入 linq 查询,但可以调用可以放入查询的方法。也有错别字。 而不是ifValueConverstionValueConversion
0赞 madreflection 7/11/2022
请记住,LINQ 是关于使用数据集的,因此子句是条件运算符,它应用于整个数据集。因此,您必须分组思考,以及如何按顺序处理每个元素。where