Базовый синтаксис LINQ

2

Предположим, что у вас есть такой XML:

 <data>
  <messages>
   <message name="Person" id="P">
    <field name="FirstName" required="Y" />
    <field name="LastName" required="Y" />
    <field name="Sex" required="N" />
   </message>
   <message name="Car" id="C">
    <field name="Make" required="Y" />
    <field name="Model" required="Y" />
    <field name="Year" required="N" />
   </message>
  </messages>
 </data>

Используя Linq, как бы вы получили список всех необходимых имен полей для Person?

Я только начал играть с LINQ/XML сегодня, это примерно так, как я получил.

    var q = from c in loaded.Descendants("field")
            where (string)c.Attribute("required") == "Y" &&
            // how to check the parent node (message) has an attribute (id="P")           
            select (string)c.Attribute("name");

    foreach (string name in q)
        Console.WriteLine(name);
  • 0
    У вас нет такого XML, это не допустимый XML-документ. Можете ли вы опубликовать фактический XML, который у вас есть, или хотя бы рабочий пример?
Теги:
linq

4 ответа

1
Лучший ответ

Этот ответ совершенно неверен, учитывая, что вопроситель изменил свой xml. Должен ли я удалить это.

var q = from c in loaded.Descendants("field")
            where (string)c.Attribute("required") == "Y" &&
                    c.Parent.Attribute("id").Value == "P"
            select (string)c.Attribute("name");

Добавление Xml, который я использовал, потому что есть некоторая путаница в правильном решении.

XDocument loaded = XDocument.Parse(@"
<message name=""Person"" id=""P"">
    <field name=""FirstName"" required=""Y"" /> 
    <field name=""LastName"" required=""Y"" />
    <field name=""Sex"" required=""N"" />
    <message name=""Car"" id=""C"">
        <field name=""Make"" required=""Y"" />
        <field name=""Model"" required=""Y"" />
        <field name=""Year"" required=""N"" />
    </message>
</message>");
  • 0
    Чувак, я был так близок с c.Parent, но просто не видел атрибута ... Спасибо!
2

Я добавил корневой элемент и закрывающий тег для сообщений, чтобы сделать XML действительным:

XDocument loaded = XDocument.Parse(@"
  <messages>
    <message name=""Person"" id=""P"">
      <field name=""FirstName"" required=""Y"" />
      <field name=""LastName"" required=""Y"" />
      <field name=""Sex"" required=""N"" />
    </message>
    <message name=""Car"" id=""C"">
      <field name=""Make"" required=""Y"" />
      <field name=""Model"" required=""Y"" />
      <field name=""Year"" required=""N"" />
    </message>
  </messages>");

Вместо того, чтобы искать все поля, а затем проверять родительский элемент для каждого из них, найдите один из родителей, с которым вы перепробованы, чтобы у вас было меньше полей для проверки:

IEnumerable<string> fields =
  loaded.Root.Elements()
  .Where(m => m.Attribute("id").Value == "P")
  .Single()
  .Elements("field")
  .Where(f => f.Attribute("required").Value == "Y")
  .Select(f => f.Attribute("name").Value);

Edit:
Добавлен спецификатор "field" для дочерних элементов, если элемент сообщения содержит любые другие типы элементов.

Изменить 2:
Я собрал рабочий пример с подмножеством фактических данных:

XDocument loaded = XDocument.Parse(@"
  <fix major=""4"" minor=""4"">
    <header>
    </header>
    <trailer>
    </trailer>
    <messages>
      <message name=""ResendRequest"" msgtype=""2"" msgcat=""admin"">
        <field name=""BeginSeqNo"" required=""Y"" />
        <field name=""EndSeqNo"" required=""Y"" />
      </message>
      <message name=""Reject"" msgtype=""3"" msgcat=""admin"">
        <field name=""RefSeqNum"" required=""Y"" />
        <field name=""RefTagID"" required=""N"" />
        <field name=""RefMsgType"" required=""N"" />
        <field name=""SessionRejectReason"" required=""N"" />
        <field name=""Text"" required=""N"" />
        <field name=""EncodedTextLen"" required=""N"" />
        <field name=""EncodedText"" required=""N"" />
      </message>
    </messages>
  </fix>");

IEnumerable<string> fields =
  loaded.Root.Element("messages").Elements("message")
  .Where(m => m.Attribute("name").Value == "Reject")
  .Single()
  .Elements("field")
  .Where(f => f.Attribute("required").Value == "Y")
  .Select(f=>f.Attribute("name").Value);
  • 0
    Второй парень, чтобы понять это неправильно. OQ сказал: // как проверить, что родительский узел (сообщение) имеет атрибут (id = "P"), у его персоны есть автомобиль. Это не человек, а автомобиль, его человек имеет автомобиль
  • 0
    @jfar: О чем ты вообще говоришь? Почему вы думаете, что внутри узла сообщения есть узел сообщения?
Показать ещё 8 комментариев
2

вы можете удалить отдельный цикл foreach и уродливый листинг, сделав также следующее:

(from c in myXML.Descendants("field")
         where c.Attribute("required").Value == "Y" && 
         c.Parent.Attribute("id").Value == "P" 
         select c.Attribute("name").Value).ToList().ForEach(s => Console.WriteLine(s.ToString()));

Edit:

как проблема с обнуленными нулевыми или необязательными атрибутами, вот пример того, как добавить метод расширения для обработки нулевых атрибутов, вы можете передать его по умолчанию, если он не существует (это второй параметр в метод расширения).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;

namespace MyTestApp
{

class Program
{
    static void Main(string[] args)
    {
        XDocument myXML = XDocument.Load(@"C:\file.xml"); 

        (from c in myXML.Descendants("field")
         where c.Attribute("required")
               .GetAttributeValueOrDefault("N") == "Y" && 
                c.Parent.Attribute("id").Value == "P"      
         select 
         c.Attribute("name").Value).ToList().ForEach(s => Console.WriteLine(s.ToString()));

        Console.ReadLine();
    }
}

public static class XLinqHelper
{
    // extension method that handles an xattribute and returns the provided default if the Xattrib is null
    public static string GetAttributeValueOrDefault(this XAttribute s, string defaultValue)
    {
        string retVal;
        if (s == null)
            retVal = defaultValue;
        else
            retVal = s.Value;
        return retVal;


    }
}

}

  • 0
    странно, я получаю исключение NullReferenceException, когда я использую. Значение это как для вашего, так и для примеров Guffas.
  • 0
    Как вы загружаете XML
Показать ещё 10 комментариев
1

Вы используете метод Ancestors() или Parent, как определено System.Xml.Linq.XNode и System.Xml.Linq.XObject

Ещё вопросы

Сообщество Overcoder
Наверх
Меню