动态 LINQ to XML [关闭]

Posted

技术标签:

【中文标题】动态 LINQ to XML [关闭]【英文标题】:Dynamic LINQ to XML [closed] 【发布时间】:2020-01-09 15:38:51 【问题描述】:

我正在尝试将Dynamic LINQ Expressions 与LINQ to XML 一起使用,但动态参数有问题。

这是来自 Dynamic LINQ Wiki 的示例查询:

var query = db.Customers
    .Where("City == @0 and Orders.Count >= @1", "London", 10)
    .OrderBy("CompanyName")
    .Select("new(CompanyName as Name, Phone)");

以我为例,我正在尝试查询以下结构:

<DataCenter>
   <Server IP="1.2.3.4">
       <OS>Windows</OS>
   </Server>
   <Server IP="5.6.7.8">
       <OS>Linux</OS>
   </Server>
</DataCenter>

我正在尝试像这样读取和解析它:

XElement XmlSource = XElement.Load(filePath)
var query = XmlSource.Elements().AsQueryable().Select("???????");

我应该把什么作为字符串参数?例如,如果我尝试检索所有服务器的 IP 和操作系统。当我尝试使用 XElement 的 Element( )Attribute( ) 方法时,我收到错误消息“XElement 没有这样的属性或方法”。

虽然firstAtteibutefirstNode 似乎可用。像这样的工作:

var query = XmlSource.Elements()
         .AsQueryable()
         .Select("new (FirstAttribute.Value as IP, FirstNode.toString() as OS)");

【问题讨论】:

感谢您的反对票和近距离投票。你真好。 你想访问什么?这里不需要AsQueryable @DanielA.White 据我所知,建立在 IQueryable 之上的动态 LINQ 表达式。我正在尝试对用户提供的任意字段运行查询。我添加了来自 Dynamic LINQ Wiki 的示例。 @DanielA.White 下面由 NetMage 给出的答案正是我要问的。抱歉不清楚。 【参考方案1】:

假设您使用的是System.Linq.Dynamic.Core,您可以将XNameXElement 添加到可访问类型,这样它们就可以工作了:

public class MyCustomTypeProvider : DefaultDynamicLinqCustomTypeProvider 
    public override HashSet<Type> GetCustomTypes() => new[]  typeof(XName), typeof(XElement) .ToHashSet();

由于动态 LINQ 不使用隐式转换进行方法查找,并且不理解显式转换,我展示了两种不同的方法来处理通常通过隐式转换完成的 stringXName 的转换:

ParsingConfig.Default.CustomTypeProvider = new MyCustomTypeProvider();

var OSName = (XName)"OS";
var query = XmlSource.Elements().AsQueryable()
                .Select("new (Attribute(XName.Get(\"IP\")).Value as IP, Element(@0).Value as OS)", OSName);

如果元素OS 可能丢失,则必须测试null。不幸的是,我无法让 np 谓词起作用:

var query = XmlSource.Elements().AsQueryable()
                .Select("new (Attribute(XName.Get(\"IP\")).Value as IP, (Element(@0) != null ? Element(@0).Value : null) as OS)", OSName);

【讨论】:

你是个天才!这就像一个魅力。不过我有两个问题:一:为什么我们将名称以不同的方式传递给属性和元素?或者我们将 String 转换为 XName 并没有什么区别?第二 - 如果该属性不存在,我将得到 NullReferenceException。添加安全措施检查 null 的最佳位置是什么?谢谢! @YuriyGalanter 我以不同的方式传递它们只是为了展示解决动态 LINQ 中缺乏隐式或显式转换支持的可能方法。使用您喜欢的任何一个。 @YuriyGalanter 我扩展了缺少元素的答案。 希望您能帮助我解决另一个问题。我可以成功运行动态 LINQ 查询,但是当我尝试使用此方法 (hanselman.com/blog/…) 将结果导出到 CSV 时,它作为“对象”类型的 IEnumerable 传递给女巫 GetProperties() 什么都不返回。有没有办法枚举动态 LINQ 返回的 Item 的属性? NM,我明白了,谢谢!【参考方案2】:
    string xml =
            "<DataCenter><Server IP=\"1.2.3.4\"><OS>Windows</OS></Server><Server IP=\"5.6.7.8\"><OS>Linux</OS></Server></DataCenter>";

    XDocument doc = XDocument.Parse(xml);
    var servers = doc.Elements("DataCenter").Elements("Server");

    var results = from s in doc.Elements("DataCenter").Elements("Server") where (string)s.Attribute("IP") == "1.2.3.4" select s;

编辑:

既然它是 XML,我们想要元素/属性中的值,为什么不直接获取它们的 Value 属性。那么就没有理由去处理可访问类型了。

XDocument doc2 = XDocument.Parse(xml);
var results = from s in doc2.Descendants("Server") select new  OsName = s.Element("OS").Value, IpAddress = s.Attribute("IP").Value ;

【讨论】:

我正在使用动态 LINQ,我事先不知道条件或请求的字段将是什么。如果您看一下我帖子底部的示例-参数是可以构造的字符串 我已经编辑了我的帖子。既然它是 XML,我们想要元素/属性中的值,为什么不直接获取值。【参考方案3】:

要检索属性和后代元素您可以尝试以下代码:

string StringXML = @"<DataCenter>
                       <Server IP='1.2.3.4'>
                           <OS>Windows</OS>
                       </Server>
                       <Server IP='5.6.7.8'>
                           <OS>Linux</OS>
                       </Server>
                    </DataCenter>";


XDocument Doc = XDocument.Parse(StringXML);

var nodess = from Servers in Doc.Descendants("Server")
                select newIP = Servers.Attribute("IP").Value , OS=Servers.Element("OS").Value ;

foreach(var node in nodess)

    Console.WriteLine("ServerIP:"+node.IP + " ServerOS:" +node.OS);

【讨论】:

谢谢,但select需要动态,我不知道会提前请求哪些元素/属性

以上是关于动态 LINQ to XML [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Linq to sql 动态查询

Linq to Entities 中的动态 where 子句 (OR)

Linq to Sql 与动态数据库

使用 Linq to Entities (EF6) 动态选择列名

LINQ to SQL 可以查询 XML 字段 DB-serverside 吗?

Linq To Entities中的动态排序