xdocument tutorial query net manejo leer example ejemplos c# .net xml linq linq-to-xml

c# - tutorial - Consulta un XDocument para elementos por nombre a cualquier profundidad



xdocument c# example (8)

Estoy usando el método de extensión XPathSelectElements que funciona de la misma manera que el método 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); } } } }

Tengo un objeto XDocument . Deseo consultar elementos con un nombre particular a cualquier profundidad usando LINQ. Cuando uso Descendants("element_name") , solo obtengo elementos que son hijos directos del nivel actual. Lo que estoy buscando es el equivalente de "// element_name" en XPath ... ¿debería usar XPath , o hay una forma de hacerlo con los métodos LINQ? Gracias.


Hay dos maneras de lograr esto,

  1. Linq-to-xml
  2. XPath

Las siguientes son muestras del uso de estos enfoques,

List<XElement> result = doc.Root.Element("emails").Elements("emailAddress").ToList();

Si utilizas XPath, necesitas hacer algo de manipulación con IEnumerable:

IEnumerable<XElement> mails = ((IEnumerable)doc.XPathEvaluate("/emails/emailAddress")).Cast<XElement>();

Tenga en cuenta que

var res = doc.XPathEvaluate("/emails/emailAddress");

da como resultado un puntero nulo o ningún resultado.


Los descendientes deberían trabajar absolutamente bien. Aquí hay un ejemplo:

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

Resultados:

<grandchild id="3" />
<grandchild id="4" />


Los descendientes harán exactamente lo que necesiten, pero asegúrese de haber incluido un nombre de espacio de nombres junto con el nombre del elemento. Si lo omite, probablemente obtendrá una lista vacía.


Puedes hacerlo de esta manera:

xml.Descendants().Where(p => p.Name.LocalName == "Name of the node to find")

donde xml es un XDocument .

Tenga en cuenta que el Name propiedad devuelve un objeto que tiene un LocalName y un Namespace . Es por eso que debe usar Name.LocalName si desea comparar por nombre.


Siguiendo la respuesta de @Francisco Goldenstein, escribí un método de extensión

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


Un ejemplo que indica el espacio de nombres:

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


(El código y las instrucciones son para C # y es posible que deba modificarse levemente para otros idiomas)

Este ejemplo funciona perfecto si desea leer desde un nodo principal que tenga muchos elementos secundarios, por ejemplo, consulte el siguiente XML;

<?xml version="1.0" encoding="UTF-8"?> <emails> <emailAddress>[email protected]</emailAddress> <emailAddress>[email protected]</emailAddress> <emailAddress>rgreen@set_ig.ca</emailAddress> </emails>

Ahora con este código a continuación (tenga en cuenta que el archivo XML se almacena en los recursos (consulte los enlaces al final del fragmento para obtener ayuda sobre los recursos). Puede obtener cada dirección de correo electrónico dentro de la etiqueta "correos electrónicos".

XDocument doc = XDocument.Parse(Properties.Resources.EmailAddresses); var emailAddresses = (from emails in doc.Descendants("emailAddress") select emails.Value); foreach (var email in emailAddresses) { //Comment out if using WPF or Windows Form project Console.WriteLine(email.ToString()); //Remove comment if using WPF or Windows Form project //MessageBox.Show(email.ToString()); }

Resultados

  1. [email protected]
  2. [email protected]
  3. rgreen@set_ig.ca

Nota: Para la aplicación de consola y WPF o formularios de Windows, debe agregar "using System.Xml.Linq;" Con la directiva en la parte superior de su proyecto, para Console también necesitará agregar una referencia a este espacio de nombres antes de agregar la directiva Using. Además, para la consola no habrá ningún archivo de recursos de forma predeterminada en la "carpeta de propiedades", por lo que deberá agregar manualmente el archivo de recursos. Los artículos de MSDN a continuación, explican esto en detalle.

Agregar y editar recursos

Cómo agregar o eliminar recursos