14

我创建了一个带有示例内容的 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);
}
4

3 回答 3

14

您可以像这样使用 XPath 方法:

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

虽然更喜欢 LINQ to XML 因为它的可读性。

这将Period根据提供的PeriodGroup 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")

将返回 element 的后代元素的集合Periods。然后我们使用where基于属性值过滤这个节点集合:

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

然后将集合过滤到具有值为的属性的PeriodGroup元素nameHER

最后,我们选择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查询运行后对象的样子:

在此处输入图像描述

于 2013-04-12T11:43:48.953 回答
4

由于该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>.
}

您可以在w3schools了解有关 XPath 的更多信息。

于 2013-04-12T11:39:36.040 回答
0

通过这个

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

                }
            }
        }
    }
于 2017-08-29T09:52:05.083 回答