如何从XML文档中读取值以构建ComboBox?

6
我正在尝试读取一个文件,这是我想为我的母亲制作的。因此,基本上这就是我想做的事情:
  1. 一个ComboBox,它将显示XML中所有蔬菜的名称。
  2. 选择蔬菜后,第二个ComboBox将显示可以使用第一个ComboBox中选择的蔬菜进行烹饪的XML中的食谱名称。
  3. 最后,通过一个OKButton,所选食谱将读取导致该食谱的文件路径。

我编写的XML

<Vegetables>
    <vegetable name="Carrot">
        <recipe name="ABCrecipe">
            <FilePath>C:\\</FilePath>
        </recipe>
        <recipe name="DEFrecipe">
            <FilePath>D:\\</FilePath>
        </recipe>   
    </vegetable>
    <vegetable name="Potato">
        <recipe name="CBArecipe">
            <FilePath>E:\\</FilePath>
        </recipe>
            <recipe name"FEDrecipe">
            <FilePath>F:\\</FilePath>
        </recipe>
    </vegetable>
</Vegetables>

C# 代码

private void Form1_Load(object sender, EventArgs e)
{
    XmlDocument xDoc = new XmlDocument();
    xDoc.Load("Recipe_List.xml");
    XmlNodeList vegetables = xDoc.GetElementsByTagName("Vegetable");
    for (int i = 0; i < vegetables.Count; i++)
    {
        comboBox1.Items.Add(vegetables[i].Attributes["name"].InnerText);
    }
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    //I'm lost at this place.
}

第一个ComboBox现在能够显示蔬菜名称,但是我如何使第二个ComboBox读取食谱?

你应该将“potato”和“carrot”值放入它们自己的节点中。你只需要完善你的选择过程,你正在获取一个高级节点并打印出其中的所有内容,而不是使用更具体的选择器来查找特定的项目。 - SpaceBison
作为添加新节点的替代方案,您可以将蔬菜名称作为蔬菜节点的属性输入。 - Kobunite
3个回答

1
你的xml应该进行重构,因为在将食谱名称和文件路径节点作为食谱节点的值时混合了数据。
以下是更好的方法:
<Vegetables>
    <vegetable name="Carrot">
        <recipe name="ABCrecipe">
            <FilePath>C:\\</FilePath>
        </recipe>
        <recipe name="DEFrecipe">
            <FilePath>D:\\</FilePath>
        </recipe>   
    </vegetable>
    <vegetable name="Potato">
        <recipe name="CBArecipe">
            <FilePath>E:\\</FilePath>
        </recipe>
        <recipe name="FEDrecipe">
            <FilePath>F:\\</FilePath>
        </recipe>
    </vegetable>
</Vegetables>

因此,要显示食谱,您需要提取食谱节点的属性。如何做到这一点在这里解释:如何从C#中的XmlNode读取属性值?

编辑:由于评论进行了XML结构更正。谢谢


需要进行相同的重构才能将蔬菜名称提取到属性/节点中。一个XML元素可以包含文本一个或多个子元素;它不能同时包含两者。 - Phylogenesis
@Phylogenesis 您可以拥有同时包含文本和其他元素的元素。这被称为混合内容。一个很好的例子是XHTML,其中<p>Hello <span class="name"/>Mr X</span></p>是有效的XML。 - Paul Turner
@Tragedian 你说得对 - 但在这种情况下,混合内容会导致可读性很差的结构。 - Phylogenesis
混合内容是完全有效的,就像@Tragedian所说,但我确实会提取蔬菜名称。抱歉那个错过了。我会纠正它。 - Samuel

1
如果你想从文档中获取蔬菜名称,最简单的方法是将其定义为独立的数据。你所做的并没有什么不对,但它使得获取所需数据变得更加困难。
如果可以的话,请将结构更改为以下内容,这样可以让你的生活更轻松:
<vegetables>
    <vegetable>
        <name>Carrot</name>
        <recipe>
             <name>ABCrecipe</name>
             <path>C:\\</path>
        </recipe>
        <recipe>
            <name>DEFrecipe</name>
            <path>D:\\</path>
        </recipe>   
    </vegetable>
</vegetables>

假设你使用的是 .NET 3.5 或更新版本,那么你将有访问 LINQ-to-XML API 的权限。这些提供了一种简化的方式来从 XML 文档中读取值,应该能够让解决这个问题变得更容易。
你可以使用以下方式创建一个文档:
var document = XDocument.Load("Recipe_List.xml");

然后您可以编写一个查询来获取蔬菜元素,如下所示:
var vegetables = document
    .Element(XName.Get("vegetables"))
    .Elements(XName.Get("vegetable"));

一旦你拥有这些元素,你可以像这样获取它们的名称:
var vegNames = vegetables.Select(ele => ele.Element(XName.Get("name")).Value);

您可以很容易地将此信息插入到您的组合框中:
foreach (string name in vegNames)
{
    comboBox1.Items.Add(name);
}

1
我假设您正在使用 .Net 4.0 框架中的 C#。
您可以按照以下方式格式化您的 XML:
<Vegetables>
    <vegetable>
        <name>Carrot</name>
        <recipe>
            <name>ABCrecipe</name>
            <FilePath>C:\\</FilePath>
        </recipe>
        <recipe>
            <name>DEFrecipe</name>
            <FilePath>D:\\</FilePath>
        </recipe>   
    </vegetable>
    <vegetable>
        <name>Potato</name>
        <recipe>
            <name>CBArecipe</name>
            <FilePath>E:\\</FilePath>
        </recipe>
        <recipe>
            <name>FEDrecipe</name>
            <FilePath>F:\\</FilePath>
        </recipe>
    </vegetable>
</Vegetables>

然后只需使用此查询来选择这些项目:

var vegiesList = (from veg in xDoc.Descendants("vegetable")
                  select new Vegetable()
                  {
                       Name = veg.Element("name").Value,
                       Recipes = (from re in veg.Elements("recipe")
                                  select new Recipe(re.Element("name").Value, re.Element("FilePath").Value)).ToList()
                  })
                  .ToList();

那么关于你的类结构:
class Vegetable
{
    public string Name { get; set; }
    public List<Recipe> Recipes { get; set; }
}

class Recipe
{
    public Recipe(string name, string path)
    {
       Name = name;     Path = path;
    }
    public string Name { get; set; }
    public string Path { get; set; } 
}

vegiesList.ForEach(veg => comboBox1.Items.Add(veg.Name));
//You can select its property here depending on what property you want to add on your `ComboBox`

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接