c# - node - xelement descendants
Encontrar elemento en XDocument? (6)
Tengo un XML simple
<AllBands>
<Band>
<Beatles ID="1234" started="1962">greatest Band<![CDATA[lalala]]></Beatles>
<Last>1</Last>
<Salary>2</Salary>
</Band>
<Band>
<Doors ID="222" started="1968">regular Band<![CDATA[lalala]]></Doors>
<Last>1</Last>
<Salary>2</Salary>
</Band>
</AllBands>
Sin embargo ,
cuando quiero llegar a la "banda Doors" y cambiar su ID:
using (var stream = new StringReader(result))
{
XDocument xmlFile = XDocument.Load(stream);
var query = from c in xmlFile.Elements("Band")
select c;
...
query
no tiene resultados
Pero
Si escribo xmlFile.Elements().Elements("Band")
para que lo encuentre.
Cuál es el problema ?
¿Es necesario el camino completo desde la raíz?
Y si es así, ¿por qué funcionó sin especificar AllBands
?
¿ XDocument
navegación de XDocument
me exige conocer la estructura de nivel completo hasta el elemento requerido?
Debe usar Root
para referirse al elemento raíz:
xmlFile.Root.Elements("Band")
Si desea buscar elementos en cualquier lugar del documento, use Descendants
lugar:
xmlFile.Descendants("Band")
El método Elements()
devuelve un IEnumerable<XElement>
contiene todos los elementos secundarios del nodo actual. Para un XDocument, esa colección solo contiene el elemento Root. Por lo tanto, se requiere lo siguiente:
var query = from c in xmlFile.Root.Elements("Band")
select c;
El problema es que Elements
solo toma los elementos secundarios directos de lo que sea que lo invoque. Si desea todos los descendientes, use el método Descendants
:
var query = from c in xmlFile.Descendants("Band")
Mi experiencia al trabajar con archivos XML grandes y complicados es que a veces ni los Elementos ni los Descendientes parecen funcionar para recuperar un Elemento específico (y todavía no sé por qué).
En tales casos, descubrí que una opción mucho más segura es buscar manualmente el Elemento, como se describe en la siguiente publicación de MSDN:
En resumen, puede crear una función GetElement:
private XElement GetElement(XDocument doc,string elementName)
{
foreach (XNode node in doc.DescendantNodes())
{
if (node is XElement)
{
XElement element = (XElement)node;
if (element.Name.LocalName.Equals(elementName))
return element;
}
}
return null;
}
A continuación, puedes llamar así:
XElement element = GetElement(doc,"Band");
Tenga en cuenta que esto devolverá nulo si no se encuentra ningún elemento coincidente.
Puedes hacerlo de esta manera:
xml.Descendants().SingleOrDefault(p => p.Name.LocalName == "Name of the node to find")
donde xml es un XDocument.
Tenga en cuenta que el Nombre de propiedad devuelve un objeto que tiene un LocalName y un Namespace. Es por eso que debe usar Name.LocalName si desea comparar por nombre.
Elements()
solo verificará los hijos directos, que en el primer caso es el elemento raíz, en el segundo caso los hijos del elemento raíz, por lo tanto, se obtiene una coincidencia en el segundo caso. Si solo quieres un descendiente coincidente usa Descendants()
lugar:
var query = from c in xmlFile.Descendants("Band") select c;
También le sugiero que vuelva a estructurar su Xml: el nombre de la banda debe ser un atributo o valor de elemento, no el nombre del elemento en sí, esto hace que la consulta (y la validación de esquema para el caso) sea mucho más difícil, es decir algo como esto:
<Band>
<BandProperties Name ="Doors" ID="222" started="1968" />
<Description>regular Band<![CDATA[lalala]]></Description>
<Last>1</Last>
<Salary>2</Salary>
</Band>