2010-06-24 6 views
3

Je dispose d'un fichier xml exemple qui ressemble à ceci:sélection 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> 

Je dois recueillir tous les noms de livres et le prix du livre et de passer à une autre méthode. En ce moment, je reçois tous les noms de livres et le prix du livre séparement en deux différents List<string> en utilisant la commande suivante:

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

créer un fichier texte et envoyer ce retour à la fonction appelante (stroing ces résultats dans un fichier texte est une exigence, le fichier texte a deux champs bookname et bookprice).

Pour écrire dans le fichier texte est utilisez le code suivant:

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

Je ne me sens bien en quelque sorte de cette approche. Supposons que, pour une raison quelconque, les deux listes ne soient pas de la même taille. En ce moment je ne prends pas cela en compte et je me sens en utilisant foreach est beaucoup plus efficace (je me trompe peut-être). Est-il possible de lire les deux entrées dans une structure de données (ayant deux attributs nom et prix) à partir de LINQ? alors je peux facilement parcourir la liste de cette structure de données avec foreach.

J'utilise C# pour la programmation.

Merci,

[Modifier]: Merci à tous pour les réponses super rapide, je choisis la première réponse que je voyais.

+0

Si vous utilisez .NET 4, vous pouvez simplement les mettre dans un Tuple. – R0MANARMY

+0

Yah, cela aurait dû être bookPrice, (copier coller erreur) et j'utilise .Net 3.5 – dsilva

Répondre

10

Sélection:

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

Looping:

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

** Je dois collecter tous les noms de livres et les prix des livres et passer à une autre méthode. ** Si je lis bien , votre solution nécessiterait de passer des objets anonymes en dehors de la portée dans laquelle ils ont été créés (techniquement possible, mais une sorte de mauvaise chose à faire). – R0MANARMY

+0

Dans ce cas, vous devez définir une structure de données et l'utiliser. Avez-vous la possibilité d'éditer l'autre fonction ou est-elle gravée dans la pierre? Quelle est la signature de cette fonction? – GWB

+0

merci pour la solution, c'était ce que je cherchais, U r génial !!!!!!!!!!!!!!!!! – dsilva

1

Vous pouvez le faire avec une seule requête et une boucle 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

Pour tirer parti de la solution de Jeff, si vous avez besoin de passer cette collection dans une autre fonction comme un argument que vous pouvez abuser de la structure de données KeyValuePair un peu et faire quelque chose le long des lignes de:

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

Les propriétés d'un KeyValuePair ne seraient-elles pas Clé et Valeur, pas Nom et Prix? – GalacticCowboy

+0

@GalacticCowboy: Oui, ils le seraient, je voulais juste faire remarquer que Key tiendrait le nom, et que Value contiendrait le prix. – R0MANARMY

2

Je pense que vous pourriez le rendre plus ordonné par des moyens très simples.

Un exemple un peu simplifié suit.

d'abord définir le type Livre:

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. 
} 

projet Ensuite, vos données XML dans une séquence de livres, comme ceci:

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

Si vous voulez une meilleure efficacité, je vous conseille l'utilisation d'un XmlReader et écrire dans le fichier sur chaque catégorie rencontrée, mais il est très impliqué par rapport à votre approche. Cela dépend vraiment de vos besoins, je ne pense pas que vous ayez à vous en soucier trop à moins que la vitesse soit essentielle ou que l'ensemble de données soit énorme.

L'approche en flux continu ressemblerait à quelque chose comme ceci:

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

Gardez à l'esprit que si vos noeuds ont espaces de noms XML, vous devez vous inscrire ceux qui ont le XmlReader par un NameTable ou il ne reconnaîtra pas les nœuds.

+1

+1 pour recommander la création d'un type réel, mais votre exemple ne fonctionnera pas tel quel car Book ne possède pas de constructeur (chaîne, chaîne) défini. – GWB

+1

select new Livre() {Name = x.Attribute ("BookName"). Value, Price = x.Attribute ("BookPrice"). Value}; // ou quelque chose comme ça ... – GalacticCowboy

+0

@GWB: Il est venu terriblement semblable au vôtre lol. Oui, j'ai omis le constructeur pour la densité, mais c'est vrai, ce ne serait pas si ça a l'air un peu bizarre quand je l'appelle plus tard. Ajout d'un constructeur @GalacticCowboys: Cela fonctionnerait aussi bien. – Skurmedel

Questions connexes