I'm trying to write out a series of objects as an XML file so they can be read in later. I have all the code to build the XML tree and set all the attributes, etc. I've looked through the whole tree in VS so I know all of my data is there.

To write it to a file I use:

writer.WriteStartDocument();
writer.WriteStartElement("####");

node.WriteTo(writer);

writer.WriteEndElement();
writer.Close();

It works - mostly. The last child from most of the branches is missing it's last attribute. The final last child has all of it's attributes, but all the others are missing the last one.

Here is the output:

<Campaign Name="No Mercy">
    <Level Name="The Apartments" Variants="2">
      <Variant Mode="Coop" Map="l4d_hospital01_apartment" />
      <Variant Mode="Versus" />
    </Level>
    <Level Map="The Subway" Variants="3">
      <Variant Mode="Coop" Map="l4d_hospital02_subway" />
      <Variant Mode="Versus" Map="l4d_vs_hospital02_subway" />
      <Variant Mode="Survival" />
    </Level>
    <Level Map="The Sewers" Variants="3">
      <Variant Mode="Coop" Map="l4d_hospital03_sewers" />
      <Variant Mode="Versus" Map="l4d_vs_hospital03_sewers" />
      <Variant Mode="Survival" />
    </Level>
    <Level Map="The Hospital" Variants="3">
      <Variant Mode="Coop" Map="l4d_hospital04_interior" />
      <Variant Mode="Versus" Map="l4d_vs_hospital04_interior" />
      <Variant Mode="Survival" />
    </Level>
    <Level Map="The Rooftop" Variants="3">
      <Variant Mode="Coop" Map="l4d_hospital05_rooftop" />
      <Variant Mode="Versus" Map="l4d_vs_hospital05_rooftop" />
      <Variant Mode="Survival" Map="l4d_vs_hospital05_rooftop" />
    </Level>
  </Campaign>

The last variant node on each Level node is missing the Map attribute. Except for the final one. Any ideas?

Can you post your code of where you attach the Map attribute to the Variant node in your application?

I do it in a loop that iterates thru the level objects in the campaign object.

XmlNode c = xml.CreateNode(XmlNodeType.Element, "Campaign", "");
            XmlAttribute attr = xml.CreateAttribute("Name");

            foreach (Level l in update.Missions)
            {
                XmlNode lvl = xml.CreateNode(XmlNodeType.Element, "Level", "");
                attr.Value = l.Name;
                lvl.Attributes.Append(attr);
                attr = xml.CreateAttribute("Variants");
                attr.Value = l.Variant.Count.ToString();
                lvl.Attributes.Append(attr);

                foreach (KeyValuePair<GameMode, string> kv in l.Variant)
                {
                    XmlNode var = xml.CreateNode(XmlNodeType.Element, "Variant", "");
                    attr = xml.CreateAttribute("Mode");
                    attr.Value = kv.Key.ToString();
                    var.Attributes.Append(attr);
                    attr = xml.CreateAttribute("Map");
                    attr.Value = kv.Value;
                    var.Attributes.Append(attr);
                    lvl.AppendChild(var);
                }

                c.AppendChild(lvl);
            }

Sorry I can't see anything wrong with your code, that's exactly how I would do it. I'm surprised that the compiler lets you get away with using the variable name var though, I thought var was a reserved word in C#. Have you tried stepping through your code and viewing the node attributes each time to make sure that the kv.Value is correct?

That's the most confusing part. I step through and check var, lvl, and c and the attributes are all there. Then I write it out and some of them are missing.

As for the "var" keyword, I think that became a keyword in .NET 4. I'm using 3.5 since the people who use this little program don't have 4 installed and it's way too much hassle

Well, I have no idea what I did to fix it, but it's fixed. I went through and had the loops create new attribute variables instead of just reusing the 1 attribute variable and giving it new data. I also renamed all of them to be more descriptive and remove the keyword thing you mentioned. Not sure which of these fixed it, but here is the working code:

private void ToXML()
        {
            // Create new XML Document with a Document Node "Left4Dead"
            XmlDocument xml = new XmlDocument();
            XmlNode l4d = xml.CreateNode(XmlNodeType.Element, "Left4Dead", "");

            // Generate a Campaign node with levels, variants and attributes
            foreach (Campaign update in Maps)
            {
                XmlNode c = xml.CreateNode(XmlNodeType.Element, "Campaign", "");
                XmlAttribute campaignName = xml.CreateAttribute("Name");
                XmlAttribute file = xml.CreateAttribute("File");
                campaignName.Value = update.Name;
                file.Value = update.File;
                c.Attributes.Append(campaignName);
                c.Attributes.Append(file);

                // Each level has a name and level variants (ie versus, coop, etc)
                foreach (Level l in update.Missions)
                {
                    XmlNode lvl = xml.CreateNode(XmlNodeType.Element, "Level", "");
                    XmlAttribute lvlName = xml.CreateAttribute("Name");
                    XmlAttribute vCount = xml.CreateAttribute("Variants");
                    lvlName.Value = l.Name;
                    vCount.Value = l.Variant.Count.ToString();

                    lvl.Attributes.Append(lvlName);
                    lvl.Attributes.Append(vCount);

                    foreach (KeyValuePair<GameMode, string> kv in l.Variant)
                    {
                        XmlNode variant = xml.CreateNode(XmlNodeType.Element, "Variant", "");
                        XmlAttribute mode = xml.CreateAttribute("Mode");
                        XmlAttribute map = xml.CreateAttribute("Map");

                        mode.Value = kv.Key.ToString();
                        map.Value = kv.Value;

                        variant.Attributes.Append(mode);
                        variant.Attributes.Append(map);

                        lvl.AppendChild(variant);
                    }

                    c.AppendChild(lvl);
                }

                l4d.AppendChild(c);
            }

            // Insert the Left4Dead node into the document
            xml.AppendChild(l4d);

            XmlWriterSettings s = new XmlWriterSettings();
            s.CloseOutput = true;
            s.Indent = true;
            XmlWriter writer = XmlWriter.Create("Campaigns.xml", s);

            // Write the XML declaration node, then the content of the document.
            writer.WriteStartDocument();
            xml.WriteTo(writer);
            writer.Close();
        }

Well, I have no idea what I did to fix it, but it's fixed. I went through and had the loops create new attribute variables instead of just reusing the 1 attribute variable and giving it new data. I also renamed all of them to be more descriptive and remove the keyword thing you mentioned. Not sure which of these fixed it, but here is the working code:

private void ToXML()
        {
            // Create new XML Document with a Document Node "Left4Dead"
            XmlDocument xml = new XmlDocument();
            XmlNode l4d = xml.CreateNode(XmlNodeType.Element, "Left4Dead", "");

            // Generate a Campaign node with levels, variants and attributes
            foreach (Campaign update in Maps)
            {
                XmlNode c = xml.CreateNode(XmlNodeType.Element, "Campaign", "");
                XmlAttribute campaignName = xml.CreateAttribute("Name");
                XmlAttribute file = xml.CreateAttribute("File");
                campaignName.Value = update.Name;
                file.Value = update.File;
                c.Attributes.Append(campaignName);
                c.Attributes.Append(file);

                // Each level has a name and level variants (ie versus, coop, etc)
                foreach (Level l in update.Missions)
                {
                    XmlNode lvl = xml.CreateNode(XmlNodeType.Element, "Level", "");
                    XmlAttribute lvlName = xml.CreateAttribute("Name");
                    XmlAttribute vCount = xml.CreateAttribute("Variants");
                    lvlName.Value = l.Name;
                    vCount.Value = l.Variant.Count.ToString();

                    lvl.Attributes.Append(lvlName);
                    lvl.Attributes.Append(vCount);

                    foreach (KeyValuePair<GameMode, string> kv in l.Variant)
                    {
                        XmlNode variant = xml.CreateNode(XmlNodeType.Element, "Variant", "");
                        XmlAttribute mode = xml.CreateAttribute("Mode");
                        XmlAttribute map = xml.CreateAttribute("Map");

                        mode.Value = kv.Key.ToString();
                        map.Value = kv.Value;

                        variant.Attributes.Append(mode);
                        variant.Attributes.Append(map);

                        lvl.AppendChild(variant);
                    }

                    c.AppendChild(lvl);
                }

                l4d.AppendChild(c);
            }

            // Insert the Left4Dead node into the document
            xml.AppendChild(l4d);

            XmlWriterSettings s = new XmlWriterSettings();
            s.CloseOutput = true;
            s.Indent = true;
            XmlWriter writer = XmlWriter.Create("Campaigns.xml", s);

            // Write the XML declaration node, then the content of the document.
            writer.WriteStartDocument();
            xml.WriteTo(writer);
            writer.Close();
        }
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.