web-dev-qa-db-ja.com

XMLファイルの複数の子ノードの読み取り

次のようなサンプルコンテンツを含むXmlファイルを作成しました。

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

選択したPeriodGroup内のPeriodノードの子を読み取ることができる必要があります。 PeriodNameは、より理にかなっている場合、Periodの属性である可能性があります。

私はたくさんの例を見てきましたが、どれもまったく正しくないようで、XmlReaderを使用するメソッド、XmlTextReaderを使用するメソッド、使用しないメソッドなどがあります。 Xmlファイルを読むのはこれが初めてなので、誰かがポインタをくれないかと尋ねると思った。何かを試すためだけに機能するものはありますが、不格好に感じます。 VS2010とc#を使用しています。また、多くの人がLINQ-Xmlを使用しているのを見ているので、この方法を使用することの長所と短所を高く評価します。

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

次のようなXPathアプローチを使用できます。

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

LINQはXMLよりも読みやすいので好まれます。

これは、指定されたPeriodPeriodGroup属性に基づいてnameノードの子を返します。 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();
_

結果:

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

クエリは非常に簡単です

_from n in xml.Descendants("Periods")
_

要素Periodsの子孫要素のコレクションを返します。次に、whereを使用して、属性値に基づいてこのノードのコレクションをフィルタリングします。

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

コレクションをPeriodGroupの値を持つname属性を持つHER要素にフィルターします

最後に、PeriodGroup要素を選択し、その子孫ノードを取得します

_select n.Element("PeriodGroup").Descendants().Elements()
_

編集(コメントを参照)

この式の結果は単なるクエリであるため、.ToList()を使用してコレクションを列挙し、必要な値を含むオブジェクトを返します。匿名型を作成して、要素の値を保存することもできます。例:

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

これは、クエリの実行後のnodesオブジェクトの外観です。

enter image description here

14
DGibbs

XmlDocument.SelectNodesメソッドは実際にXPath式を受け入れます。次のように自由に進んでください:

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

XPathの詳細については、 w3schools をご覧ください。

4
shakurov

これを通り抜ける

 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