2010-06-24 72 views
3

我有一個示例XML文件看起來像這樣:選擇使用LINQ

<Books> 
    <Category Genre="Fiction" BookName="book_name" BookPrice="book_price_in_$" /> 
    <Category Genre="Fiction" BookName="book_name" BookPrice="book_price_in_$" /> 
    <Category Genre="NonFiction" BookName="book_name" BookPrice="book_price_in_$" /> 
    <Category Genre="Children" BookName="book_name" BookPrice="book_price_in_$" /> 
</Books> 

我需要收集所有書名和書的價格,並傳遞給其他方法。現在,我得到的所有的書的名字和書籍的價格seperately成兩個不同的List<string>使用以下命令:

List<string>BookNameList = root.Elements("Category").Select(x => (string)x.Attribute("BookName")).ToList(); 
List<string>BookPriceList = root.Elements("Category").Select(x => (string)x.Attribute("BookPrice")).ToList(); 

我創建一個文本文件,並將其發送回調用函數(stroing這些結果在一個文本文件一個要求,文本文件有兩個字段bookname和bookprice)。

要寫入文本文件是使用下面的代碼:

for(int i = 0; i < BookNameList.Count; i++) 
{ 
    //write BookNameList[i] to file 
    // Write BookPriceList[i] to file 
} 

我有點不感覺良好,這種方法。假設由於任何原因,這兩個列表的大小不一樣。現在我不考慮這一點,我覺得使用foreach更有效率(我可能錯了)。是否可以從LINQ中將這兩個條目讀入數據結構(具有兩個屬性名稱和價格)?那麼我可以用foreach輕鬆地遍歷該數據結構的列表。

我正在使用C#進行編程。

感謝,

[編輯]:感謝大家的超快速反應,我選擇我所看見的第一個答案。

+0

如果您使用.NET 4,則可以將它們全部放入Tuple中。 – R0MANARMY 2010-06-24 17:29:26

+0

耶,應該是bookPrice,(複製粘貼錯誤),我正在使用.Net 3.5 – dsilva 2010-06-24 17:30:41

回答

10

選擇:

var books = root.Elements("Category").Select(x => new { 
    Name = (string)x.Attribute("BookName"), 
    Price = (string)x.Attribute("BookPrice") 
}).ToList(); 

循環:

foreach (var book in books) 
{ 
    // do something with 
    // book.Name 
    // book.Price 
} 
+1

**我需要收集所有書名和書價,並傳遞給其他方法**如果我正在閱讀,您的解決方案需要將匿名對象傳遞到創建它們的範圍之外(技術上可行,但這是一種邪惡的事情)。 – R0MANARMY 2010-06-24 17:32:40

+0

在這種情況下,您應該定義一個數據結構並使用它。您是否有能力編輯其他功能,或者是否已經成功了?該功能的簽名是什麼? – GWB 2010-06-24 17:35:26

+0

感謝您的解決方案,這就是我一直在尋找的,真棒!!!!!!!!!!!!!!!!! – dsilva 2010-06-24 17:37:56

1

您可以用單一的查詢和foreach循環做到這一點。

var namesAndPrices = from category in root.Elements("Category") 
        select new 
        { 
         Name = category.Attribute("BookName").Value, 
         Price = category.Attribute("BookPrice").Value 
        }; 

foreach (var nameAndPrice in namesAndPrices) 
{ 
    // TODO: Output to disk 
} 
1

要建立在傑夫的解決方案,如果你需要這個集合傳遞到另一個函數作爲參數,你可以濫用KeyValuePair數據結構一點點,做線沿線的東西:

var namesAndPrices = from category in root.Elements("Category") 
        select new KeyValuePair<string, string>(
         Name = category.Attribute("BookName").Value, 
         Price = category.Attribute("BookPrice").Value 
        ); 

// looping that happens in another function 
// Key = Name 
// Value = Price 
foreach (var nameAndPrice in namesAndPrices) 
{ 
    // TODO: Output to disk 
} 
+0

KeyValuePair的屬性不是Key和Value,而不是Name和Price? – GalacticCowboy 2010-06-24 17:50:22

+0

@GalacticCowboy:是的,他們會的,我只是想指出Key將持有名稱,Value則持有該價格。 – R0MANARMY 2010-06-24 18:54:31

2

我認爲你可以通過一些非常簡單的方法使它更整潔。

下面是一個稍微簡化的例子。

首先定義類型的書:

public class Book 
{ 
    public Book(string name, string price) 
    { 
     Name = name; 
     Price = price; 
    } 

    public string Name { get; set; } 
    public string Price { get; set; } // could be decimal if we want a proper type. 
} 

然後投射您的XML數據轉換成書籍的序列,像這樣:

var books = from category in root.Elements("Category") 
      select new Book((string) x.Attribute("BookName"), (string) x.Attribute("BookPrice")); 

如果你想更好的效率,我會使用的XmlReader指點和在每個遇到的類別上寫入文件,但與您的方法相比,它非常複雜。這取決於你的要求,我不認爲你必須擔心它太多,除非速度是必不可少的或數據集是巨大的。

流式傳輸的方式將是這個樣子:

using (var outputFile = OpenOutput()) 
using (XmlReader xml = OpenInput()) 
{ 
    try 
    { 
     while (xml.ReadToFollowing("Category")) 
     { 
      if (xml.IsStartElement()) 
      { 
       string name = xml.GetAttribute("BookName"); 
       string price = xml.GetAttribute("BookPrice"); 

       outputFile.WriteLine(string.Format("{0} {1}", name, price)); 
      } 
     } 
    } 
    catch (XmlException xe) 
    { 
     // Parse error encountered. Would be possible to recover by checking 
     // ReadState and continue, this would obviously require some 
     // restructuring of the code. 
     // Catching parse errors is recommended because they could contain 
     // sensitive information about the host environment that we don't 
     // want to bubble up. 
     throw new XmlException("Uh-oh"); 
    }  
} 

請記住,如果您的節點有XML命名空間,你必須通過一個NameTable註冊這些用XmlReader,否則將無法識別的節點。

+1

+1用於推薦創建實際類型,但您的示例不會按原樣運行,因爲Book沒有定義(字符串,字符串)構造函數。 – GWB 2010-06-24 17:42:00

+1

select new Book(){Name = x.Attribute(「BookName」)。Value,Price = x.Attribute(「BookPrice」)。Value}; //或類似的東西...... – GalacticCowboy 2010-06-24 17:48:43

+0

@GWB:它非常類似於你的笑聲。是的,我省略了密度的構造函數,但是這是事實,當我稍後調用它時,它不會顯得有點奇怪。添加了一個構造函數。 @GalacticCowboys:那也可以。 – Skurmedel 2010-06-24 18:02:07