2009-11-06 74 views
2

比方說你有一個像這樣的XML:基本LINQ語法

<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,你將如何獲得個人的所有必填字段名稱的列表?

我剛剛開始使用LINQ/XML,今天這是關於Ive得到的。

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,或者至少有一個可行的例子嗎? – Guffa

回答

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

您可以通過刪除單獨的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())); 

編輯:

與空或可選屬性的問題隨之而來,這裏是一個如何添加擴展方法來處理空屬性的示例,如果不存在(即擴展方法中的第二個參數),可以將其傳遞爲缺省值以供使用。

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 – Matt

+0

你有頂部無效的XML,因爲你沒有消息元素的結束標籤。解析器會無視這個問題,所以我假設你有有效的XML – Matt

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); 

編輯:
在消息元素包含任何其他類型的元素的情況下爲子元素添加說明符「字段」。

編輯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」)他的人有一輛車。它不是人和車,它的人有車 – jfar

+0

@jfar:你到底在說什麼?爲什麼你認爲消息節點內部有一個消息節點? – Guffa

+0

對,消息中有消息,而不是兩個單獨的消息。 – jfar