Benutzer mit den meisten Antworten
LINQ from-Abfrage innerhalb einer from-Abfrage

Frage
-
Guten Tag Community,
ich bin neu im Bereich der generischen Programmierung :) Deswegen bitte ich um Nachsicht.
Ich habe in meiner Anwendung folgendes Problem:
Ich möchte eine Xml Datei einlesen. Die Datei habe ich und ich habe auch ein XDocument erstellt. XmlDocument nehme ich nicht, weil ich Silverlight nutze. Warum auch immer kommt dann bei mir ein Fehler. Die XML ist wie folgt aufgebaut:
<Labels> <Label Id="lblTitle" Target="MainPage"> <Language lang="de"> <![CDATA[P1]]> </Language> <Language lang="en"> <![CDATA[P2]]> </Language> </Label> <Label Id="lblHead" Target="Home"> <Language lang="de"> <![CDATA[S1]]> </Language> <Language lang="en"> <![CDATA[S2]]> </Language> </Label> </Labels>
Nun möchte ich eine Abfrage machen, die mir ein IEnumerable<T> erstellt, wobei ich eine eigene Klasse angelegt habe, die vier Properties enthält. Die Klasse sieht wie folgt aus:
public class PolFotLabel { public string TextGerman { get; set; } public string TextEnglish { get; set; } public string Id { get; set; } public string Target { get; set; } }
Die Abfrage, die ich bis jetzt mache, sieht wie folgt aus:
IEnumerable<PolFotLabel> values = from elem in doc.Descendants("Label") select new PolFotLabel { Id = elem.Attribute(XName.Get("Id")).Value, Target = elem.Attribute(XName.Get("Target")).Value };
Nun möchte ich am liebsten noch innerhalb dieser Abfrage die Elemente "TextEnglish" und "TextGerman" befüllen, aber ich habe keine Ahnung wie. Folgende Abfrage funktioniert zwar an sich
System.Collections.Generic.IEnumerable<string> sDE = from ele in doc.Descendants("Label").Descendants("Language") where ele.Attribute(XName.Get("lang")).Value == "de" select ele.Value;
aber wenn ich diese wie folgt einbauen will, funktioniert das nicht.
IEnumerable<PolFotLabel> values = from elem in doc.Descendants("Label") select new PolFotLabel { Id = elem.Attribute(XName.Get("Id")).Value, Target = elem.Attribute(XName.Get("Target")).Value, TextGerman = from ele in elem.Descendants("Language") where ele.Attribute(XName.Get("lang")).Value == "de" select ele.Value };
Dann erfolgt folgende Fehlermeldung.
Eine implizite Konvertierung vom Typ "System.Collections.Generic.IEnumerable<string>" in "string" ist nicht möglich.
Kann mir jemand helfen, wie ich das löse, dass ich innerhalb der from-Abfrage einfach eine weitere habe?
Sollte dies nicht gehen, wäre eine Alternative die funktionierende Abfrage zu nehmen, die mir "sDE" liefert, und dann in einer schleife die Eigenschaften "TextGerman", "TextEnglish" in einer Schleife zu setzen. Ungefähr so:
for (int i = 0; i < values.Count<PolFotLabel>(); i++) { values.ElementAt<PolFotLabel>(i).TextGerman = sDE.ElementAt<string>(i).ToString(); values.ElementAt<PolFotLabel>(i).TextEnglish = sEN.ElementAt<string>(i).ToString(); }
Hier erhalte ich zwar keinen Fehler, aber die Werte werden einfach nicht gesetzt...
Antworten
-
Hi,
ich hätte es wie folgt gemacht :
var file = XDocument.Load("file.xml"); var ele = from i in file.Element("Labels").Elements("Label") select new PolFotLabel() { Id = (string) i.Attribute("Id"), Target = (string) i.Attribute("Target"), TextEnglish = (string) i.Elements("Language").FirstOrDefault(p => (string)p.Attribute("lang") == "en"), TextGerman = (string)i.Elements("Language").FirstOrDefault(p => (string)p.Attribute("lang") == "de") };
Ich ahbe bewusst nicht die Value genommen , da ich damit auch NULL Werte erlaube.Grüße
Pawel
- Als Antwort vorgeschlagen Stefan Hoffmann Freitag, 15. Juli 2011 11:33
- Als Antwort markiert Gozar15 Freitag, 15. Juli 2011 12:29
-
Hallo,
das wäre dann:
IEnumerable<PolFotLabel> values = from label in GetDocument().Root.Descendants("Label") select new PolFotLabel { Id = (string)label.Attribute("Id"), Target = (string)label.Attribute("Target"), TextGerman = (from language in label.Elements("Language") where (string)language.Attribute("lang") == "de" select (string)language).SingleOrDefault(), TextEnglish = (from language in label.Elements("Language") where (string)language.Attribute("lang") == "en" select (string)language).SingleOrDefault() };
was dann etwas umfangreicher wird.
Und sollte auch zeigen, dass man sich mit beiden Syntaxarten vertraut machen sollte.Im Sinne späteren einer Erweiterbarkeit würde ich ein Dictionary (oder eine eigene Klasse)
für die Sprachen verwenden, z. B.:public class PolFotLabel2 { public string Id { get; set; } public string Target { get; set; } public IDictionary<string, string> Texte { get; set; } public override string ToString() { return String.Format("Id: {0}, Target: {1}\r\n", this.Id, this.Target) + String.Join("\r\n", Texte.Select(kvp => String.Format("\tSprache: {0} = {1}", kvp.Key, kvp.Value))); } } // und dann: IEnumerable<PolFotLabel2> values2 = from label in GetDocument().Root.Descendants("Label") select new PolFotLabel2 { Id = (string)label.Attribute("Id"), Target = (string)label.Attribute("Target"), Texte = label.Elements("Language").ToDictionary( language => (string)language.Attribute("lang"), text => (string)text) }; foreach (var value in values2) Console.WriteLine(value);
Womit man für alle Zeit / Sprachen ausgesorgt hat.Noch hübscher würde es wenn man sich eine Klasse schreibt, die den Sprachcode ergänzt.
Gruß Elmar
- Als Antwort markiert Gozar15 Freitag, 15. Juli 2011 12:46
Alle Antworten
-
Hi,
ich hätte es wie folgt gemacht :
var file = XDocument.Load("file.xml"); var ele = from i in file.Element("Labels").Elements("Label") select new PolFotLabel() { Id = (string) i.Attribute("Id"), Target = (string) i.Attribute("Target"), TextEnglish = (string) i.Elements("Language").FirstOrDefault(p => (string)p.Attribute("lang") == "en"), TextGerman = (string)i.Elements("Language").FirstOrDefault(p => (string)p.Attribute("lang") == "de") };
Ich ahbe bewusst nicht die Value genommen , da ich damit auch NULL Werte erlaube.Grüße
Pawel
- Als Antwort vorgeschlagen Stefan Hoffmann Freitag, 15. Juli 2011 11:33
- Als Antwort markiert Gozar15 Freitag, 15. Juli 2011 12:29
-
Hallo,
das wäre dann:
IEnumerable<PolFotLabel> values = from label in GetDocument().Root.Descendants("Label") select new PolFotLabel { Id = (string)label.Attribute("Id"), Target = (string)label.Attribute("Target"), TextGerman = (from language in label.Elements("Language") where (string)language.Attribute("lang") == "de" select (string)language).SingleOrDefault(), TextEnglish = (from language in label.Elements("Language") where (string)language.Attribute("lang") == "en" select (string)language).SingleOrDefault() };
was dann etwas umfangreicher wird.
Und sollte auch zeigen, dass man sich mit beiden Syntaxarten vertraut machen sollte.Im Sinne späteren einer Erweiterbarkeit würde ich ein Dictionary (oder eine eigene Klasse)
für die Sprachen verwenden, z. B.:public class PolFotLabel2 { public string Id { get; set; } public string Target { get; set; } public IDictionary<string, string> Texte { get; set; } public override string ToString() { return String.Format("Id: {0}, Target: {1}\r\n", this.Id, this.Target) + String.Join("\r\n", Texte.Select(kvp => String.Format("\tSprache: {0} = {1}", kvp.Key, kvp.Value))); } } // und dann: IEnumerable<PolFotLabel2> values2 = from label in GetDocument().Root.Descendants("Label") select new PolFotLabel2 { Id = (string)label.Attribute("Id"), Target = (string)label.Attribute("Target"), Texte = label.Elements("Language").ToDictionary( language => (string)language.Attribute("lang"), text => (string)text) }; foreach (var value in values2) Console.WriteLine(value);
Womit man für alle Zeit / Sprachen ausgesorgt hat.Noch hübscher würde es wenn man sich eine Klasse schreibt, die den Sprachcode ergänzt.
Gruß Elmar
- Als Antwort markiert Gozar15 Freitag, 15. Juli 2011 12:46