Search code examples
c#f#linq-to-xmlxmlwriter

Cant get XDocument/XmlWriter to write xml file with indents and new line (using XmlProvider underneath)


Here is the code (the xml document itself was created by reading an xml using an F# XmlProvider from FSharp.Data, and then manipulating it via its underling XDocument)

  static void Save(XDocument doc, string filename)
  {
     var settings = new XmlWriterSettings()
     {
        Indent = true,  // Set to true for indents
        IndentChars = "    ",  // Set the characters used for indentation
        NewLineChars = "\r\n",  // Set the newline characters
        NewLineHandling = NewLineHandling.Replace, // Replace the default newline characters
        Encoding = new UTF8Encoding(false)
     };

     using (var writer = XmlWriter.Create(filename, settings))
     {
        doc.Save(writer);
     }
  }

I KNOW this code is working (in the sense of the settings actually being used by the save because when I turn the BOM on and off in the Encoding I can see it in the file), but it will consistently output data like this:

<ES_XMLXPATH xp_ordernr="1" xp_xpath="ES_PUBLICATIONRECORD/ds_program" /><ES_XMLXPATH xp_ordernr="1" xp_xpath="ES_PUBLICATIONRECORD/ds_program/ES_PRODUCT/masterProgram" /><ES_XMLXPATH xp_ordernr="1" xp_xpath="ES_PUBLICATIONRECORD/ds_program/ES_PRODUCT/masterProgram/ES_PRODUCT/oid" />

clearly with no newline and no indent.

These elements I HAVE added to the document in the normal manner, and the rest of the document (which was originally read from disk) is correctly formatted with indents and newlines, but for some reasome these elements will defy any formatting.

Is there something I fundementally have misinterpreted (I work with XML a lot).


the ms documentation says this

Remarks This property only applies to XmlWriter instances that output text content; otherwise, this setting is ignored. The elements are indented as long as the element does not contain mixed content. Once the WriteString or WriteWhitespace method is called to write out a mixed element content, the XmlWriter stops indenting. The indenting resumes once the mixed content element is closed.

I cant comprehend how an xmlwriter doesnt output text content, xml is a text format!

I don't believe my content is mixed.


Solution

  • Sadly I havent diagnosed the specific issue, but I can say that there IS an issue, and it appears to be related to XML via an XmlProvider, I can give a workaround, rather than a fix.

    So the answer appears to be that if I use plain XDocument, this all works, if I use FSharp.Data.XmlProvider, and then use the XDocument inside the provider and add elements to it, something clearly gets confused (FSharp.Data.XmlProvider is probably optimized to read xml data, writing it is a bit of an abuse).

    So the solution!

    either don't use a type provider or...

    create a new xdocument from the ground up by serialising the XmlProvider xdocument to a string, and rereading it.

    (Save(..,..) below calls the function in the OP).

     var doc = XDocument.Parse(newRoot.ToString());
    
     Save(doc, reportDef.FullName);
    

    Its "expensive", but my docs are small so I don't care.