【问题标题】:If person with specific name exists in People XML list如果人员 XML 列表中存在具有特定姓名的人员
【发布时间】:2020-04-14 11:38:31
【问题描述】:

如何知道这个结果:

<People>
<Person name="John" />
<Person name="Andrew" />
</People>

我需要查看人员列表中是否存在具有特定姓名的人员。

例子:

if (Element("People").ForAny(person => person.name == "John")) // Returns True
if (Element("People").ForAny(person => person.name == "Amanda")) // Returns False

我正在使用 Xml Linq 库。

感谢您的帮助!

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    您需要进行关注点分离:将您的问题分成可以独立使用的较小问题。这样可以更轻松地重用您的代码来解决其他问题,更轻松地测试您的代码,在不破坏代码的情况下进行更改。

    您的问题包含两个子问题:

    • 如何将 XML 数据转换为 Person 序列
    • 如何从 Persons 序列中提取具有特定名称的 Persons
    • 如何检测 Person 序列是否为空?

    我不经常将 XML 转换为 IEnumerable,但this answer helped me.

    class Person
    {
        public string Name {get; set;}
        ... // other properties
    }
    

    如果在你的 XML 中一个 Person 真的只有一个 Name,你不必为它定义一个特殊的类。但话又说回来:你确定一个人只不过是一个名字吗?那不应该是名字的集合吗?

    好的,所以我们有一个 Person 类(或一个字符串),我们需要一个函数来将 XML 转换为 Person 序列:

    把它写成一个扩展方法,这样我们就可以让它看起来像 LINQ。见extension methods demystified。签名中的单词this 使其成为扩展方法。它允许您像使用字符串类本身的方法一样使用该方法

    public static IEnumerable<Person> ToPersons(this String xml)
    {
        return XElement.Parse(xml)
            .Elements("Person")
            .Select(xmlElement => new Person
            {
                Name = xmlElement.Element("Name").Value,
    
                // if needed, fill other properties, for instance:
                Id = Int32.Parse(xmlElement.Element("Id").Value),
            });
    }
    

    用法:

    string xmlTxt = ...
    IEnumerable<Person> persons = xmlTxt.ToPersons();
    

    如果您没有带有 xml 的字符串,而是一个 XmlReader,请考虑:

    public static IEnumerable<Person> ToPersons(this XmlReader xmlReader)
    {
        while(xmlReader.Read())
        {
            // TODO: read one Person from xmlReader
            Person person = new Person() {...} // you know better how to do this than I
            yield return person
        }
    

    现在我们已经将 xml 转换与 Person 处理分开了,剩下的就很简单了:

    要求:
    给定一个 Person 的名称,以及一些表示 Person 序列的 XmlText,告诉我具有此名称的 Person 是否在此序列中

    string personName = ...
    string xmlText = ...      // or Use the XmlReader
    
    bool personAvailable = xmlText.ToPersons()
        .Where(person => person.Name == personName)
        .Any();
    

    用词:将 xmlText 转换为 Persons 序列。从这个序列中,只保留那些Name 等于personName 的人。如果剩余序列中还有任何元素,则返回 true。

    如果您使用特殊字符,或者想忽略大小写。考虑:

    IEqualityComparer<strong> personNameComparer = StringComparer.CurrentCultureIgnoreCase;
    bool personAvailable = xmlText.ToPersons()
        .Where(person => personNameComparer.Equals(person.Name, personName))
        .Any();
    

    好消息是,因为您分离了您的关注点,您还可以将ToPersons 用于其他功能:

    要求:给我所有 1960 年之前出生的纽约市居民

    var oldPersons = xmlText.ToPersons
        .Where(person => person.Location == "New York City" && person.Birthday.Year < 1960);
    

    或者,如果您从 Json 文件、CSV 文件或数据库中获取您的 Persons,您仍然可以获取所有 1960 年之前出生的纽约市居民,而只需编写一个新的 ToPersons 方法。

    【讨论】:

      【解决方案2】:

      您可以简单地从根目录导航 element People
      在其所有decendantsPerson 中,是否有anyattribute name 等于您正在寻找的值:

      string input = @"<People>
      <Person name=""John"" />
      <Person name=""Andrew"" />
      </People>";
      
      XDocument doc = XDocument.Parse(input);
      
      var isJohnHere = doc.Element("People")
                          .Descendants("Person")
                          .Any(x=> x.Attribute("name").Value == "John");
      

      获得List&lt;string&gt;names 的方法是:

      var names = doc.Element("People")
                      .Descendants("Person")
                      .Select(x=> x.Attribute("name").Value);
      
      

      甚至更短的“所有Persons,无论在哪里”:

      var isJohnHere2 = doc.Descendants("Person")
                           .Any(x=> x.Attribute("name").Value == "John");
      

      Live demo

      【讨论】:

      • 如果我在 中有 怎么办?
      • @JohnDoe,没错!你从 doc 开始,你有一个名为 rootElement 的元素。然后你也这样做:doc.Element("rootElement").Element("People")
      • 或者,如果您之间有一些层次结构,但您不想一一导航。您可以直接使用 Descendants:“在文档中,我希望所有名为 'People' 的后代。” => doc.Descendants("People") 。但那是一个节点列表,逻辑只针对一个节点?也许你只想要.First()
      • 下次不要忘记minimal reproducible example,包含正确的数据输入。这样,您将使用正确的输入获得答案,而不必适应。数据可能是伪造的,但仍然具有正确的数据结构。
      猜你喜欢
      • 1970-01-01
      • 2017-05-05
      • 2011-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      相关资源
      最近更新 更多