2012-04-05 3 views
2

Ich stieß vor kurzem auf eine Situation, in der ich XPath als Teil einer Linq zu XML-Abfrage verwenden musste und fand, dass es ein bisschen seltsam wirkt. Ich bin sicher, dass es andere Möglichkeiten gibt, das Problem mit den nativen XElement-API-Methoden zu lösen, aber in dieser Situation war XPath viel besser geeignet, um die spezifischen XML-Textwerte zu finden, die ich benötigte, da die Dokumentstruktur ziemlich komplex war. Ich habe schließlich einen Weg gefunden, es zum Laufen zu bringen (siehe unten), aber es war nicht sehr hübsch, was normalerweise bedeutet, dass ich etwas verpasst habe.XPathEvaluate verwenden, um Textknotenwert in Linq-to-Xml-Abfrage zu erhalten

Meine Frage ist, wie können Sie XPathEvalute oder eine andere XPath-Methode verwenden, um einen Zeichenfolgenwert zurückzugeben, der in einer Where-Anweisung oder als Teil eines neuen Objekts in der Select-Methode verwendet werden kann. Ich fand eine Lösung, die eine Menge Casting und die Null coalesing operator in LINQ verwendet, aber es muss einen saubereren Weg geben. Die Ursache des Problems liegt darin, dass die XPathEvaluate-Methode normalerweise ein XText-Element (in ein generisches Objekt umgewandelt) zurückgibt, aber Linq konvertiert es in ein IEnumerable, sodass die Ausführung verzögert werden kann. Das verursacht Problem, wenn Sie versuchen, auf den Wert dieses Objekts zuzugreifen, da es nicht materialisiert wird, bis die Abfrage ausgeführt wird.

Hier ist das Beispiel: Mit dem folgenden XML-Dokument finden Sie alle Eltern, die einen Jungen und ein Mädchen mit demselben Namen haben. Dies muss mit einer XPath-Abfrage geschehen, da die Dokumentstruktur in meiner Situation sehr komplex war.

//Use C# Program Language type in LinqPad 
void Main() 
{ 
    var xml = XElement.Parse(@"<Root> 
     <Parent> 
      <Boy>Anne</Boy> 
     </Parent> 
     <Parent> 
      <Boy>Alex</Boy> 
      <Girl>Alex</Girl> 
     </Parent> 
     <Parent> 
      <Boy>Jay</Boy> 
     </Parent> 
    </Root>"); 

    var q1 = from e in xml.XPathSelectElements("/Parent") 
      select e; 

    q1.Dump(); 

    var q2 = from e in q1 
      let boy = ((IEnumerable<Object>)e.XPathEvaluate("Boy/text()")).Cast<System.Xml.Linq.XText>().FirstOrDefault() ?? new System.Xml.Linq.XText("") 
      let girl = ((IEnumerable<Object>)e.XPathEvaluate("Girl/text()")).Cast<System.Xml.Linq.XText>().FirstOrDefault() ?? new System.Xml.Linq.XText("") 
      select new {t=boy.GetType(), b=boy, g=girl, same=(boy.Value==girl.Value)}; 

    q2.Dump(); 
} 

Ergebnisse sind:

enter image description here

Sie, dass das zweite Element einen Jungen und Mädchen mit dem gleichen Namen haben identifiziert wird sehen können. Gibt es eine sauberere Möglichkeit, dies während der Verwendung von XPath zu tun, oder bin ich mit dem Code von oben stecken.

+0

Sie Ihre XPath vereinfachen könnten alle Eltern mit den Kriterien, die Sie suchen zu bekommen: // Eltern [Boy/text() = Girl/text()] – JWiley

Antwort

5

neu geschrieben werden kann, ist es akzeptabel, XPathSelectElement statt XPathEvaluate zu benutzen?

var q2 = from e in q1 
     let boy = (string)e.XPathSelectElement("Boy") 
     let girl = (string)e.XPathSelectElement("Girl") 
     where boy.StartsWith("A") //Optional use in where statement 
     select new { t = boy.GetType(), b = boy, g = girl, same = (boy == girl) }; 
+0

dass als meine :(besser und es ist alle auf die Besetzung zu (String). – Phil

+2

Die 'XElement' Cast-Operatoren sind sehr praktisch. –

+0

Sehr schön! Ich habe versucht, aber ich brauchte den Text-Knoten nicht das vollständige Element.Sieht wie alles, was ich brauchte, war zu einer Zeichenfolge zu werfen DANK! –

0

Wie wäre es damit, nicht sicher, ob Sie 't' brauchen.

var q2 = q1.Select (q => 
    new 
    { 
     Boy = q.XPathSelectElement("Boy"), 
     Girl = q.XPathSelectElement("Girl"), 
    } 
); 

var q3 = q2.Select (q => 
    new 
    { 
     Boy = q.Boy == null ? string.Empty : q.Boy.Value, 
     Girl = q.Girl == null ? string.Empty : q.Girl.Value 
    } 
); 

var q4 = q3.Select (q => new { q.Boy, q.Girl, same=q.Boy==q.Girl }); 

q4.Dump(); 

die als

var q2 = q1. 
    Select (q => new { Boy = q.XPathSelectElement("Boy"),Girl = q.XPathSelectElement("Girl"),}). 
    Select (q => new { Boy = q.Boy == null ? string.Empty : q.Boy.Value, Girl = q.Girl == null ? string.Empty : q.Girl.Value}). 
    Select (q => new { q.Boy, q.Girl, same=q.Boy==q.Girl } 
); 

q2.Dump(); 
Verwandte Themen