J'ai un objet XDocument
. Je souhaite interroger des éléments portant un nom particulier à n'importe quelle profondeur à l'aide de LINQ. Lorsque j'utilise Descendants("element_name")
, je ne reçois que des éléments qui sont des enfants directs du niveau actuel. Ce que je recherche, c'est l'équivalent de "// nom_élément" dans XPath ... devrais-je simplement utiliser XPath
, ou existe-t-il un moyen de le faire à l'aide des méthodes LINQ? Merci.
Les descendants devraient fonctionner parfaitement. Voici un exemple:
using System;
using System.Xml.Linq;
class Test
{
static void Main()
{
string xml = @"
<root>
<child id='1'/>
<child id='2'>
<grandchild id='3' />
<grandchild id='4' />
</child>
</root>";
XDocument doc = XDocument.Parse(xml);
foreach (XElement element in doc.Descendants("grandchild"))
{
Console.WriteLine(element);
}
}
}
Résultats:
<grandchild id="3" />
<grandchild id="4" />
Un exemple indiquant l'espace de nom:
String TheDocumentContent =
@"
<TheNamespace:root xmlns:TheNamespace = 'http://www.w3.org/2001/XMLSchema' >
<TheNamespace:GrandParent>
<TheNamespace:Parent>
<TheNamespace:Child theName = 'Fred' />
<TheNamespace:Child theName = 'Gabi' />
<TheNamespace:Child theName = 'George'/>
<TheNamespace:Child theName = 'Grace' />
<TheNamespace:Child theName = 'Sam' />
</TheNamespace:Parent>
</TheNamespace:GrandParent>
</TheNamespace:root>
";
XDocument TheDocument = XDocument.Parse( TheDocumentContent );
//Example 1:
var TheElements1 =
from
AnyElement
in
TheDocument.Descendants( "{http://www.w3.org/2001/XMLSchema}Child" )
select
AnyElement;
ResultsTxt.AppendText( TheElements1.Count().ToString() );
//Example 2:
var TheElements2 =
from
AnyElement
in
TheDocument.Descendants( "{http://www.w3.org/2001/XMLSchema}Child" )
where
AnyElement.Attribute( "theName" ).Value.StartsWith( "G" )
select
AnyElement;
foreach ( XElement CurrentElement in TheElements2 )
{
ResultsTxt.AppendText( "\r\n" + CurrentElement.Attribute( "theName" ).Value );
}
Vous pouvez le faire de cette façon:
xml.Descendants().Where(p => p.Name.LocalName == "Name of the node to find")
où xml
est un XDocument
.
Sachez que la propriété Name
renvoie un objet qui a LocalName
et Namespace
. C'est pourquoi vous devez utiliser Name.LocalName
si vous voulez comparer par nom.
Les descendants feront exactement ce dont vous avez besoin, mais assurez-vous d'avoir inclus un nom d'espace de noms avec le nom de l'élément. Si vous l'omettez, vous obtiendrez probablement une liste vide.
Il y a deux façons d'accomplir cela,
Voici des exemples d'utilisation de ces approches,
List<XElement> result = doc.Root.Element("emails").Elements("emailAddress").ToList();
Si vous utilisez XPath, vous devez manipuler IEnumerable:
IEnumerable<XElement> mails = ((IEnumerable)doc.XPathEvaluate("/emails/emailAddress")).Cast<XElement>();
Notez que
var res = doc.XPathEvaluate("/emails/emailAddress");
résulte soit un pointeur nul, soit aucun résultat.
J'utilise la méthode d'extension XPathSelectElements
qui fonctionne de la même manière que la méthode XmlDocument.SelectNodes
:
using System;
using System.Xml.Linq;
using System.Xml.XPath; // for XPathSelectElements
namespace testconsoleApp
{
class Program
{
static void Main(string[] args)
{
XDocument xdoc = XDocument.Parse(
@"<root>
<child>
<name>john</name>
</child>
<child>
<name>fred</name>
</child>
<child>
<name>mark</name>
</child>
</root>");
foreach (var childElem in xdoc.XPathSelectElements("//child"))
{
string childName = childElem.Element("name").Value;
Console.WriteLine(childName);
}
}
}
}
Suite à la réponse de @Francisco Goldenstein, j’ai écrit une méthode d’extension
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Mediatel.Framework
{
public static class XDocumentHelper
{
public static IEnumerable<XElement> DescendantElements(this XDocument xDocument, string nodeName)
{
return xDocument.Descendants().Where(p => p.Name.LocalName == nodeName);
}
}
}
nous savons que ce qui précède est vrai. Jon n'a jamais tort. les souhaits de la vie réelle peuvent aller un peu plus loin
<ota:OTA_AirAvailRQ
xmlns:ota="http://www.opentravel.org/OTA/2003/05" EchoToken="740" Target=" Test" TimeStamp="2012-07-19T14:42:55.198Z" Version="1.1">
<ota:OriginDestinationInformation>
<ota:DepartureDateTime>2012-07-20T00:00:00Z</ota:DepartureDateTime>
</ota:OriginDestinationInformation>
</ota:OTA_AirAvailRQ>
Par exemple, le problème est généralement de savoir comment obtenir EchoToken dans le document XML ci-dessus. Ou comment rendre flou l'élément avec le nom attrbute.
1- Vous pouvez les trouver en accédant avec l'espace de noms et le nom comme ci-dessous
doc.Descendants().Where(p => p.Name.LocalName == "OTA_AirAvailRQ").Attributes("EchoToken").FirstOrDefault().Value
2- Vous pouvez le trouver par la valeur du contenu de l'attribut, comme celui-ci
Ceci ma variante de la solution basée sur la méthode Linq
et Descendants de la classe XDocument
using System;
using System.Linq;
using System.Xml.Linq;
class Test
{
static void Main()
{
XDocument xml = XDocument.Parse(@"
<root>
<child id='1'/>
<child id='2'>
<subChild id='3'>
<extChild id='5' />
<extChild id='6' />
</subChild>
<subChild id='4'>
<extChild id='7' />
</subChild>
</child>
</root>");
xml.Descendants().Where(p => p.Name.LocalName == "extChild")
.ToList()
.ForEach(e => Console.WriteLine(e));
Console.ReadLine();
}
}
Pour plus de détails sur la méthode Desendants
, regardez ici.