Christopher B. Adkins
Christopher B. Adkins

Reputation: 3567

Indentation in programmatically created XML in C#

I have an XmlWriter as follows

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.NewLineHandling = NewLineHandling.Entitize;
using (XmlWriter currentWriter = XmlWriter.Create(filePath, settings))
{
    workingXmlDocument.WriteTo(currentWriter);
    currentWriter.Flush();
} // using (XmlWriter xw = XmlWriter.Create(FilePath))

I have programmatically created an Xml Document that I am trying to write with this, and it is writting just fine, except that I have a block of elements that are created in a loop and it is putting all these elements onto one line. If you need to see any other code from the program let me know and I can put it here. I welcome any ideas even if they aren't full solutions.

Update - the complete method where the problem is happening

private void XMLReaderUtil(string filePath)
    {
        XDocument workingXmlDocument;

        using (XmlReader currentReader = XmlReader.Create(filePath))
        {

            workingXmlDocument = XDocument.Load(currentReader);

            foreach (KeyValuePair<string, string> currentIteration in logDataRaw)
            {
                FileInfo currentEntry = new FileInfo(currentIteration.Value);

                string testString = currentEntry.Directory.Name;

                if (testString.Contains(" ")) { testString = testString.Replace(" ", "_"); }

                IEnumerable<XElement> list = from XElement e in workingXmlDocument.Descendants(wixNS + testString)
                                             select e;

                DirectoryInfo temp = currentEntry.Directory;

                while (list.Count() == 0 && !temp.Name.Contains(":"))
                {
                    testString = temp.Name;

                    if (testString.Contains(" ")) { testString = testString.Replace(" ", "_"); }

                    list = from XElement e in workingXmlDocument.Descendants(wixNS + testString)
                           select e;
                    temp = temp.Parent;
                } // while (list.Count() == 0 && !temp.Name.Contains(":"))

                if (list.Count() == 0)
                {
                    IEnumerable<XElement> targetDirectory =
                        from XElement e in workingXmlDocument.Descendants(wixNS + "Directory")
                        where e.Attribute("Id").Value == "TARGETDIR"
                        select e;

                    var outXml = new XElement("root");
                    foreach (var item in targetDirectory)
                    {
                        item.Add(new XElement(
                             "Directory",
                             new XAttribute("new", 1)));

                        outXml.Add(item);
                    }

                    outXml.Save(@"c:\users\adkins\desktop\temp.wxs", SaveOptions.None);

                }
            } // foreach (KeyValuePair<string, string> kvp in xmlDataChanged)
            // return workingXmlDocument;
        } // using (XmlReader sr = XmlReader.Create(FilePath))

        IEnumerable<XElement> cleanup =
            from XElement e in workingXmlDocument.Descendants(wixNS + "Directory")
            select e;
        Collection<string> keep = new Collection<string>();
        XElement[] blah;
        blah = cleanup.ToArray();

        for (int i = 0; i < blah.Length; i++)
        {
            if (!keep.Contains(blah[i].Attribute("Id").Value))
            {
                keep.Add(blah[i].Attribute("Id").Value);
            }
            else
            {
                blah[i].Remove();
            }
        }

        workingXmlDocument.Save(filePath, SaveOptions.None);

        // XMLWriter attempt
        //XmlWriterSettings settings = new XmlWriterSettings();
        //settings.Indent = true;
        //settings.IndentChars = "\t";
        //settings.NewLineHandling = NewLineHandling.Entitize;
        //settings.NewLineChars = "\n";
        //settings.CloseOutput = true;
        //settings.Encoding = System.Text.Encoding.UTF8;
        //using (XmlWriter currentWriter = XmlWriter.Create(filePath, settings))
        //{
        //    workingXmlDocument.WriteTo(currentWriter);
        //    currentWriter.Flush();
        //} // using (XmlWriter xw = XmlWriter.Create(FilePath))

        //TextWriter test run - nothing changed
        //XmlTextWriter writer = new XmlTextWriter(filePath, System.Text.Encoding.UTF8);
        //writer.Formatting = Formatting.Indented;
        //writer.IndentChar = '\t';
        //writer.Indentation = 1;

        //workingXmlDocument.WriteTo(writer);
        //writer.Flush();
        //writer.Close();

    }

Here is the complete problem method. It includes my attempts at various forms of saving the file. It is a complete mess due to my efforts to solve this problem and problems that I encountered before getting to this one. Any help would be greatly appreciated!

The variable "logDataRaw" is a dictionary containing the name of a file and the path to where it is stored. If you need any other clarification please let me know.

Upvotes: 1

Views: 3036

Answers (4)

andrew.sanin
andrew.sanin

Reputation: 51

If somebody uses XDocument and still has problems with saving XML to file with correct indent this might help you, it did for me:

  1. In addition to Chad's answer I had to use XName.Get(...) when specifying XElement name:

    var xdoc = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes"),
                new XElement(XName.Get("TranslationContainer"),
                             new XElement(XName.Get("Translations"))));
    
  2. Check that you have a well-formatted xml (don't have text outside xml tags)

Good luck.

Upvotes: 0

Christopher B. Adkins
Christopher B. Adkins

Reputation: 3567

The problem was that I was loading the XML file through an XMLReader. Once I removed that and just loaded it directly into my XDocument than everything worked fine.

Upvotes: 2

Mostafa Elmoghazi
Mostafa Elmoghazi

Reputation: 2154

You might just need to use an XmlTextWriter with default encoding instead of XmlWriter and set the Formatting property of the Writer object to Formatting.Indented

Upvotes: 0

CaffGeek
CaffGeek

Reputation: 22054

Why not just use XElement.Save() instead of XmlWriter?

http://msdn.microsoft.com/en-us/library/bb538458.aspx

EDIT:

I just ran the following bit of code

        var xml = new XElement("root",
                               new XElement("node",
                                            new XAttribute("index", 1)
                                ),
                               new XElement("node",
                                            new XAttribute("index", 2)
                                ),
                               new XElement("node",
                                            new XAttribute("index", 3)
                                ),
                               new XElement("node",
                                            new XAttribute("index", 4)
                                )
            );

        IEnumerable<XElement> ieXml =
            from XElement e in xml.Elements()
            select e;

        var outXml = new XElement("root");
        foreach (var item in ieXml)
        {
            item.Add(new XElement(
                 "Directory",
                 new XAttribute("new", 1)));

            outXml.Add(item);
        }


        outXml.Save(@"d:\foo.xml", SaveOptions.None);

and the result is formatted

<?xml version="1.0" encoding="utf-8"?>
<root>
  <node index="1">
    <Directory new="1" />
  </node>
  <node index="2">
    <Directory new="1" />
  </node>
  <node index="3">
    <Directory new="1" />
  </node>
  <node index="4">
    <Directory new="1" />
  </node>
</root>

I don't know what you're doing differently, but this works.

Upvotes: 1

Related Questions