it-swarm.dev

Nalezení elementu v XDocumentu?

Mám jednoduchý XML

<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>

Nicméně , 

když se chci dostat do "Doors band" a změnit jeho ID: 

  using (var stream = new StringReader(result))
            {
                XDocument xmlFile = XDocument.Load(stream);

                var query = from c in xmlFile.Elements("Band")

                            select c;
                             ...

query nemá žádné výsledky

Ale

Pokud píšu xmlFile.Elements().Elements("Band") tak to najde.

Co je za problém ?

Je plná cesta z kořene potřebná?

A pokud ano, proč to fungovalo bez určení AllBands?

Vyžaduje XDocument Navigation, abych poznal celou strukturu úrovně až po požadovaný prvek?

49
Royi Namir

Elements() bude kontrolovat pouze přímé děti - což je v prvním případě kořenový prvek, ve druhém případě děti kořenového elementu, takže ve druhém případě dostanete zápas. Pokud chcete, aby Descendants() používali všechny odpovídající potomky:

var query = from c in xmlFile.Descendants("Band") select c;

Také bych vám doporučil změnit strukturu Xml: Název kapely by měl být atribut nebo hodnota prvku, nikoli samotný název prvku - to činí dotazování (a validaci schématu pro tuto záležitost) mnohem těžší, tj. Něco takového:

<Band>
  <BandProperties Name ="Doors" ID="222" started="1968" />
  <Description>regular Band<![CDATA[lalala]]></Description>
  <Last>1</Last>
  <Salary>2</Salary>
</Band>
72
BrokenGlass

Můžete to udělat takto:

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

kde xml je XDocument.

Uvědomte si, že vlastnost Name vrací objekt, který má LocalName a Namespace. To je důvod, proč musíte použít Name.LocalName, pokud chcete porovnat jméno.

27

Měli byste použít Root pro označení kořenového prvku:

xmlFile.Root.Elements("Band")

Pokud chcete najít prvky kdekoli v dokumentu, použijte Descendants namísto:

xmlFile.Descendants("Band")
23
Mark Byers

Problém je v tom, že Elements má pouze direct podřízené prvky toho, čemu se říká. Chcete-li všechny potomky, použijte metodu Descendants :

var query = from c in xmlFile.Descendants("Band")
6
Jon Skeet

Moje zkušenost při práci s velkými a komplikovanými XML soubory spočívá v tom, že někdy ani Elements ani Descendants nepůsobí při získávání specifického prvku (a stále nevím proč). 

V takových případech jsem zjistil, že mnohem bezpečnější možností je ručně vyhledat prvek, jak je popsáno v následujícím příspěvku MSDN:

https://social.msdn.Microsoft.com/Forums/vstudio/en-US/3d457c3b-292c-49e1-9fd4-9b6a950f9010/how-to-get-tag-name-of-xml-by-using- xdocument? forum = csharpgeneral

Stručně řečeno, můžete vytvořit funkci 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;
}

Kterou pak můžete volat takto:

XElement element = GetElement(doc,"Band");

Všimněte si, že tato volba vrátí null, pokud není nalezen žádný odpovídající prvek.

4
Human Wannabe

Metoda Elements() vrací IEnumerable<XElement> obsahující všechny podřízené prvky aktuálního uzlu. Pro XDocument tato kolekce obsahuje pouze kořenový prvek. Proto je vyžadováno následující:

var query = from c in xmlFile.Root.Elements("Band")
            select c;
2
Phil Klein

Sebastianova odpověď byla jedinou odpovědí, která pracovala pro mne při zkoumání dokumentu xaml. Pokud byste stejně jako já chtěli seznam všech prvků, pak by metoda vypadala jako Sebastianova odpověď výše, ale jen by se vrátil seznam ...

    private static List<XElement> GetElements(XDocument doc, string elementName)
    {
        List<XElement> elements = new List<XElement>();

        foreach (XNode node in doc.DescendantNodes())
        {
            if (node is XElement)
            {
                XElement element = (XElement)node;
                if (element.Name.LocalName.Equals(elementName))
                    elements.Add(element);
            }
        }
        return elements;
    }

Zavolej to takto:

var elements = GetElements(xamlFile, "Band");

nebo v případě mého xaml doc, kde jsem chtěl všechny TextBlocks, zavolejte to takto:

var elements = GetElements(xamlFile, "TextBlock");
0
Ewan