Kajzer
Kajzer

Reputation: 2385

How to use XmlWriter recursively?

My code crashes when using the XmlWriter, saying it is used by another process.

    private void generateXml(Control receivedControl)
    {
        foreach (Control subCtrl in receivedControl.Controls)
        {
            using (XmlWriter writer = XmlWriter.Create("C:\\ui.xml"))
            {
                writer.WriteStartElement(subCtrl.Name);
                generateXml(subCtrl);
                writer.WriteEndElement();
            }
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        foreach (Control c in this.Controls)
        {
            generateXml(c);
        }
    }

Here's the error I get debugging:

Additional information: The process cannot access the file 'C:\ui.xml' because it is being used by another process.

EDIT: So thanks to you I've managed to get the recursion working, but it only writes the last object in the xml file, anybody knows why? Here's the updated code:

    private void generateXml(XmlWriter receivedWriter, Control receivedControl)
    {
        receivedWriter.WriteStartElement(receivedControl.Name);
        foreach (Control subCtrl in receivedControl.Controls)
        {
            generateXml(receivedWriter, subCtrl);
        }
        receivedWriter.WriteEndElement();
    }
    private void button2_Click(object sender, EventArgs e)
    {
        foreach (Control c in this.Controls)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;

            using(XmlWriter writer = XmlWriter.Create("c:\\ui.xml", settings))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement("Form");
                generateXml(writer, c);
                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
        }
    }

Upvotes: 0

Views: 990

Answers (3)

Kami
Kami

Reputation: 19407

The file when accessed by the XmlWriter will become locked, so an subsequent attempts to read it result in error.

You can change the function to pass the writer as a parameter, thereby have one copy and hopefully avoid the issue.

private void generateXml(XmlWriter writer, Control receivedControl)
{
    foreach (Control subCtrl in receivedControl.Controls)
    {
            writer.WriteStartElement(subCtrl.Name);
            generateXml(writer, subCtrl);
            writer.WriteEndElement();
    }
}

private void button2_Click(object sender, EventArgs e)
{
    using (XmlWriter writer = XmlWriter.Create("C:\\ui.xml"))
    {
        writer.WriteStartDocument();
        writer.WriteStartElement(this.Name); // This is the document element
        foreach (Control c in this.Controls)
        {
            generateXml(writer, c);
        }
        writer.WriteEndDocument(); // Close any open tags
    }
}

Above is a sample - not tested.

Edit : Updated to include root element

Upvotes: 3

Danny D
Danny D

Reputation: 875

you can also use a File that shares write access

        using (var f = new FileStream("C:\\ui.xml",      FileMode.Append,FileAccess.Write,FileShare.Write))
            {
                using (XmlWriter writer = XmlWriter.Create(f))                 
                {
                    writer.WriteStartElement(subCtrl.Name);
                    generateXml(subCtrl);
                    writer.WriteEndElement();
                }
            }

Upvotes: 0

that's because you're opening multiple instances of your XmlWriter writer at once.

What you should do, is put your using statement outside the recursive function, and then pass your XmlWriter in

using (XmlWriter writer = XmlWriter.Create("C:\\ui.xml"))
{
    generateXml(c, writer);

Upvotes: 0

Related Questions