Search code examples
xmlvisual-studiowinformsdatagridviewxsd

How do I parse an XML file in C# Visual Studio based on a complex Schema found in another XML file?


I am creating a program to help gamers/coders design a technology tree. I am using Visual Studio and C#. The Schema for the technology tree is stored in an XML file. This XML file can have a complex structure, with nested elements. I need to be able to read the Schema and based on the fields available in the Schema, load another XML file into the Form. I am using DataGridView elements. My original plan was to load the Schema, then iterate through each element in order to design the Windows Form. The bulk of the elements will be displayed in the main DataGridView, and elements that have child elements will have a smaller DataGridView in a panel to the right which will display each such element in its own DataGridView.

It's supposed to look like this: Visual Studio Tech Tree demo

In this example image, I created the 3 DataGridView elements manually, and was trying to populate them using this code:

    private void frmDesigner_Load(object sender, EventArgs e)
    {
        dsMainTech.ReadXml("CIV4TechInfos.xml");

        dgvTechnologies.DataSource = dsMainTech.Tables["TechInfo"];
        dgvTechnologies.AutoResizeColumns();

        dgvFlavors.DataSource = dsMainTech.Tables["TechInfo"];
        dgvFlavors.DataMember = "TechInfo_Flavors";

        dgvOrPrereqs.DataSource = dsMainTech.Tables["TechInfo"];
        dgvOrPrereqs.DataMember = "TechInfo_OrPreReqs";

        dgvAndPrereqs.DataSource = dsMainTech.Tables["TechInfo"];
        dgvAndPrereqs.DataMember = "TechInfo_AndPreReqs";
    }

As you can see, the main TechInfo is loaded to the dgvTechnologies DataGridView, but the ones on the right do not get populated.

I also tried using this code to populate the child DataGridViews:

        dgvFlavors.DataSource = dsMainTech;
        dgvFlavors.DataMember = "Flavor";

        dgvOrPrereqs.DataSource = dsMainTech;
        dgvOrPrereqs.DataMember = "OrPreReqs";

        dgvAndPrereqs.DataSource = dsMainTech;
        dgvAndPrereqs.DataMember = "AndPreReqs";

But that didn't work for the Prereqs, and the Flavors all ran together, combining them rather than displaying only the ones associated with the row selected on the left (which is what I want to happen.) It looks like this:

enter image description here

Hopefully someone will understand what I am trying to do and if anyone has done this type of thing before please let me know what to do to get these to load properly. Again, the original goal was to use a schema file to tell which elements to create child DataGridViews for, but right now I would settle for any way to load the XML in a readable and (hopefully) editable way, such as the DataGridView.

Here is an example of an XML file that could be used:

https://github.com/f1rpo/AdvCiv/blob/master/Assets/XML/Technologies/CIV4TechInfos.xml

And here is the corresponding Schema file:

https://github.com/f1rpo/AdvCiv/blob/master/Assets/XML/Technologies/CIV4TechnologiesSchema.xml


Solution

  • I was not able to this Exactly the way I wanted. I was not able to parse the Schema file, due to it's very complex nature. Instead I opted for the more "fixed" approach, using fields I expected to find in the Tech file.

    I began by reading the Tech file into a datasource, and filling the DataGridView with the appropriate Table:

    dsMainTech.ReadXml(loadtech);
    
    dgvTechnologies.DataSource = dsMainTech.Tables["TechInfo"];
    

    Next, I read the same file into an XDocument, and parsed that into a List of XElements:

    XDocument xDocument = XDocument.Load(loadtech);
    List<XElement> xElementList = xDocument.Elements().ToList();
    

    After that, I looped through the Elements:

            foreach (XElement element in xElementList)
            {
    

    And looked for fields that matched known types I was looking for. I used a switch statement to parse the elements of the file, and stored key pieces of information in additional lists I had made:

    allTechs = new List<string>();
    allTechBasics = new Dictionary<string, TechBasics>();
    

    The TechBasics was a class I created to keep track of vital information such as the X and Y positions on the Tech Tree and Prerequisite technologies.

    Like I said, it's not what I originally had wanted, but it is working very well now, and I have made great progress on designing the visual representation of the tech tree.