web-dev-qa-db-fra.com

Lecture de plusieurs nœuds enfants du fichier xml

J'ai créé un fichier XML avec un exemple de contenu, comme suit:

<?xml version="1.0" encoding="utf-8" ?>
<Periods>
  <PeriodGroup name="HER">
    <Period>
      <PeriodName>Prehistoric</PeriodName>
      <StartDate>-500000</StartDate>
      <EndDate>43</EndDate>
    </Period>
    <Period>
      <PeriodName>Iron Age</PeriodName>
      <StartDate>-800</StartDate>
      <EndDate>43</EndDate>
    </Period>
    <Period>
      <PeriodName>Roman</PeriodName>
      <StartDate>43</StartDate>
      <EndDate>410</EndDate>
    </Period>
  </PeriodGroup>
  <PeriodGroup name="CAFG">
    <Period>
      <PeriodName>Prehistoric</PeriodName>
      <StartDate>-500000</StartDate>
      <EndDate>43</EndDate>
    </Period>
    <Period>
      <PeriodName>Roman</PeriodName>
      <StartDate>43</StartDate>
      <EndDate>410</EndDate>
    </Period>
    <Period>
      <PeriodName>Anglo-Saxon</PeriodName>
      <StartDate>410</StartDate>
      <EndDate>800</EndDate>
    </Period>   
  </PeriodGroup>
</Periods>

Je dois être capable de lire les enfants du noeud Période dans un groupe de périodes sélectionné. Je suppose que PeriodName pourrait être un attribut de Period si cela est plus judicieux.

J'ai examiné une foule d'exemples, mais aucun ne semble être tout à fait correct et il semble y avoir des dizaines de méthodes différentes, certaines utilisant XmlReader, d'autres XmlTextReader et d'autres non. Comme c'est la première fois que je lis un fichier XML, j'ai pensé demander à quelqu'un si quelqu'un pouvait me donner un pointeur. Il y a quelque chose qui fonctionne juste pour essayer, mais ça semble maladroit. J'utilise VS2010 et c #. En outre, je constate que de nombreuses personnes utilisent LINQ-Xml. J'apprécierais donc les avantages et les inconvénients de cette méthode. 

string PG = "HER";
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath("./Xml/XmlFile.xml"));
string text = string.Empty;
XmlNodeList xnl = doc.SelectNodes("/Periods/PeriodGroup");
foreach (XmlNode node in xnl)
{
    text = node.Attributes["name"].InnerText;
    if (text == PG)
    {
        XmlNodeList xnl2 = doc.SelectNodes("/Periods/PeriodGroup/Period");
        foreach (XmlNode node2 in xnl2)
        {
            text = text + "<br>" + node2["PeriodName"].InnerText;
            text = text + "<br>" + node2["StartDate"].InnerText;
            text = text + "<br>" + node2["EndDate"].InnerText;
        }
    }
    Response.Write(text);
}
13
Peter C

Vous pouvez utiliser une approche XPath comme ceci:

XmlNodeList xnl = doc.SelectNodes(string.Format("/Periods/PeriodGroup[@name='{0}']/Period", PG));

Bien que préfère LINQ to XML pour sa lisibilité. 

Ceci retournera les enfants du noeud Period en fonction de l'attribut PeriodGroupname fourni, par exemple. HER:

XDocument xml = XDocument.Load(HttpContext.Current.Server.MapPath(FileLoc));

var nodes = (from n in xml.Descendants("Periods")
            where n.Element("PeriodGroup").Attribute("name").Value == "HER"
            select n.Element("PeriodGroup").Descendants().Elements()).ToList();

Résultats:

<PeriodName>Prehistoric</PeriodName>
<StartDate>-500000</StartDate>
<EndDate>43</EndDate>

<PeriodName>Iron Age</PeriodName>
<StartDate>-800</StartDate>
<EndDate>43</EndDate>

<PeriodName>Roman</PeriodName>
<StartDate>43</StartDate>
<EndDate>410</EndDate>

La requête est assez simple

from n in xml.Descendants("Periods")

Renverra une collection d'éléments descendants pour l'élément Periods. Nous utilisons ensuite where pour filtrer cette collection de nœuds en fonction de la valeur de l'attribut:

where n.Element("PeriodGroup").Attribute("name").Value == "HER"

Filtre ensuite la collection en éléments PeriodGroup qui ont un attribut name avec une valeur de HER

Enfin, nous sélectionnons l'élément PeriodGroup et obtenons ses nœuds descendants

select n.Element("PeriodGroup").Descendants().Elements()

EDIT (Voir les commentaires)

Le résultat de cette expression n'étant qu'une requête, nous utilisons .ToList() pour énumérer la collection et renvoyer un objet contenant les valeurs nécessaires. Vous pouvez également créer des types anonymes pour stocker les valeurs d'élément, par exemple:

var nodes = (from n in xml.Descendants("Period").
             Where(r => r.Parent.Attribute("name").Value == "HER")
             select new
             {
                  PeriodName = (string)n.Element("PeriodName").Value,
                  StartDate = (string)n.Element("StartDate").Value,
                  EndDate = (string)n.Element("EndDate").Value
             }).ToList();

//Crude demonstration of how you can reference each specific element in the result
//I would recommend using a stringbuilder here..
foreach (var n in nodes)
{
      text += "<br>" + n.PeriodName;
      text += "<br>" + n.StartDate;
      text += "<br>" + n.EndDate;
}

Voici à quoi ressemblera l'objet nodes après l'exécution de la requête:

enter image description here

12
DGibbs

Puisque la méthode XmlDocument.SelectNodes accepte en réalité une expression XPath, vous êtes libre de procéder comme suit:

XmlNodeList xnl = doc.SelectNodes("/Periods/PeriodGroup[@name='" + PG + "']/Period");
foreach (XmlNode node in xnl) {
    // Every node here is a <Period> child of the relevant <PeriodGroup>.
}

Vous pouvez en apprendre plus sur XPath à l’adresse w3schools .

4
shakurov

aller à travers cela

 public static void XMLNodeCheck(XmlNode xmlNode)
    {
        if (xmlNode.HasChildNodes)
        {
            foreach (XmlNode node in xmlNode)
            {
                if (node.HasChildNodes)
                {
                    Console.WriteLine(node.Name);
                    if (node.Attributes.Count!=0)
                    {
                        foreach (XmlAttribute att in node.Attributes)
                        {
                            Console.WriteLine("----------" + att.Name + "----------" + att.Value);
                        }
                    }

                    XMLNodeCheck(node);//recursive function 
                }
                else
                {
                    if (!node.Equals(XmlNodeType.Element))
                    {
                        Console.WriteLine(node.InnerText);
                    }

                }
            }
        }
    }
0
chandu