如何获取具有特定属性的节点的所有子节点?

时间:2012-05-30 20:11:32

标签: c# xml parsing xmldocument xmltextreader

我有一个xml文档,如下所示:

<Menu>
    <Category name="Comida Rapida">
        <Food cocina="si">
            <Name>Haburguesa</Name>
            <Price>10</Price>
        </Food>
        <Food>
            <Name>Papas Fritas</Name>
            <Price>20</Price>
        </Food>
    </Category>
    <Category name="Bebidas">
        <Food>
            <Name>Pepsi</Name>
            <Price>30</Price>
        </Food>
        <Food cocina="si">
            <Name>Coca Cola</Name>
            <Price>40</Price>
        </Food>
    </Category>
</Menu>

我想要做的是检查每个<Category>检查属性是否是我需要的,例如“Bebidas”,所以我感兴趣的部分是:

<Food>
    <Name>Pepsi</Name>
    <Price>30</Price>
</Food>
<Food cocina="si">
    <Name>Coca Cola</Name>
    <Price>40</Price>
</Food>

现在我有了这个,我想做一些类似于我已经做过的事情:

首先,我要打印出所有内容:

Pepsi 30
Coca Cola 40

而且我想打印出食物具有属性cocina="si"的那些,所以:

Coca Cola 40

所以我有各种各样的问题:

首先使用哪种方法,我对大量可能的方法和实现感到困惑:XmlDocument,XmlReader,XmlTextReader等。

this question我收集XmlDocument更容易使用,这将是伟大的,更简单,更好,因为我是一个很新的解析Xml文件,你可以欣赏。

现在实际的实施,我已经尝试了各种各样的事情并没有太大的成功,我似乎能够做一些部分,但不是所有部分。

XmlNodeList elemList = doc.GetElementsByTagName("Category");
for (int i = 0; i < elemList.Count; i++)
{
    Console.WriteLine(elemList[i].InnerXml);
}

这将输出:

<Food><Name>Haburguesa</Name><Price>10</Price></Food><Food><Name>Papas Fritas</Name><Price>20</Price></Food>
<Food><Name>Pepsi</Name><Price>30</Price></Food><Food><Name>Coca Cola</Name><Price>40</Price></Food> 

哪个有意义,但现在,如何检查类别是否具有属性name="cocina"

我猜这样的事情会有所帮助:

for (int j = 0; j < elemList[i].Attributes.Count; j++)
{
    //??                
}

但我在XmlTextReader中找不到类似MoveToAttribute()的内容。

然后,我如何检查是否具有属性cocina="si"

3 个答案:

答案 0 :(得分:2)

我认为LINQ to XML是最简单的方法:

您必须在此处使用XDocument课程。使用静态方法创建文档对象XDocument.Parse(DOCUMENT) - 从字符串加载文档 - 或XDocument.Load(PATH) - 从给定路径的文件加载文档。

之后,您可以通过以下查询轻松找到所需内容:

var doc = XDocument.Parse("<Menu> ... </Menu>");
var results = doc.Descendants("Category")
                 .Where(cat => (string)cat.Attribute("name") == "Bebidas")
                 .SelectMany(cat => cat.Elements("Food"))
                 .Where(food => (string)food.Attribute("cocina") == "si")
                 .Select(food => string.Format("{0} {1}", food.Element("Name"), food.Element("Price"))).ToList();

为了更清楚,我将尝试描述该查询的作用:

  1. 将名为“Category”的所有元素作为文档根元素
  2. 的后代
  3. 仅选择“name”属性具有值“Bebidas”
  4. 的类别
  5. 将该类别中的“食物”元素投射到一个集合中
  6. 选择“cocina”属性值等于“si”的“food”元素
  7. 将结果元素投影到格式为“name - price”
  8. 的字符串中

答案 1 :(得分:2)

LINQ to XML很好但很快就会变得混乱。如果您打算使用XML,您应该知道如何使用XPath来过滤所需的节点。

试试这个:

foreach (XmlNode node in doc.SelectNodes("//Food[@cocina = 'si']"))
{
    Console.WriteLine(node.SelectSingleNode("Name").InnerText
        + " " 
        + node.SelectSingleNode("Price").InnerText);
}

各地都支持XPath; LINQ to XML在.NET之外对你不利。

答案 2 :(得分:1)

您应该使用XPATH,而不是编写代码来检索这些节点。

你想要的XPath表达式是“//食物[@cocina ='si']”

IE使用doc.selectNodes(xpath)作为使用XPath的方式,好的浏览器使用doc.evaluate()。

看看这里:http://www.w3schools.com/xpath/xpath_examples.asp