Как читать значения из XML-документа для создания ComboBox?

Я пытаюсь прочитать xml файл, который я хочу сделать для моей мамы. Так что в основном это то, что я хочу сделать:

  1. A ComboBox который покажет все имена овощей в XML.
  2. после выбора овоща, второй ComboBox покажет имена рецептов в XML, которые могут использовать овощ, выбранный в первом ComboBox для приготовления пищи.
  3. последний, с ОК Button выбранный рецепт будет читать Путь к файлу, который ведет к рецепту.

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 теперь может отображать имена овощей, но как я могу сделать 2nd ComboBox читать рецепты?

3 ответов


ваш 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>

Итак, чтобы отобразить рецепты, вам нужно извлечь атрибут узла recipe. Как это сделать описано здесь: как прочитать значение атрибута из XmlNode в C#?

Edit: исправлена структура xml из-за комментариев. Спасибо


если вы хотите иметь возможность получить имя овоща из документа, самое простое, что нужно сделать, это определить его как свой собственный отдельный кусок данных. Нет ничего недействительным о том, что вы сделали, но это сделало его довольно трудно добраться до данных, которые вы хотите.

если вы можете, измените структуру на что-то вроде этого, чтобы облегчить вашу жизнь:

<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 или новее, у вас будет доступ к the 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);
}

Я предполагаю, что вы используете C# в .Net 4.0 framework

вы можете отформатировать 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`