Search code examples
c#excelxmllinqxmldocument

How can I change " " to ' ' in XmlDocument C#?


Currently, I have a code project to convert data from excel to xml and I am using XmlDocument to write xml file to run testcase in available software. But in that software when running xml it only receives.

<?xml version='1.0' encoding='utf-8'?>

When I use CreateXmlDeclaration function of XmlDocument

XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("'1.0", "'utf-8'", null);

My result -> <?xml version="1.0" encoding="utf-8"?>

I try modify it <?xml version="'1.0'" encoding="'utf-8'"?> and I get exception:

an unhandled exception of type 'System.ArgumentException' occurred in System.Xml.dll Wrong XML version information. The XML must match production "VersionNum ::= '1.' [0-9]+".

How can I use ' ' in CreateXmlDeclaration or use another API as an alternative to XmlDocument ?


Solution

  • You have a couple of issues here:

    1. There is no need to manually add an XML Declaration to an XmlDocument by calling CreateXmlDeclaration(). The XML Declaration will be written automatically using the current encoding when you call one of the overloads of XmlDocument.Save(). It will not be written when you inspect the value of OuterXml or call XmlDocument.WriteTo().

    2. When writing XML using XmlTextWriter you may control the quote character by setting XmlTextWriter.QuoteChar = '\''[1].

      Note that this property controls both the quote character used in the XML declaration, and the quote character used for attribute values.

      Note also that, while XmlTextWriter has been deprecated in favor of calling XmlWriter.Create(), there does not appear to be a way to set the quote character using XmlWriterSettings.

    Thus, if you want to use a single quote character for both the XML declaration and attribute values, you can introduce the following extension method:

    public static partial class XmlSerializationHelper
    {
        public static string GetOuterXml(this XmlDocument doc, bool indent = true, char quoteChar = '"')
        {
            if (doc == null)
                return null;
            using (var textWriter = new StringWriterWithEncoding())
            {
                using (var xmlWriter = new XmlTextWriter(textWriter) { Formatting = indent ? Formatting.Indented : Formatting.None, QuoteChar = quoteChar })
                {
                    doc.Save(xmlWriter);
                }
                return textWriter.ToString();
            }
        }
    }
    
    public sealed class StringWriterWithEncoding : StringWriter
    {
        // From this answer https://stackoverflow.com/a/42584394/3744182
        // To https://stackoverflow.com/questions/42583299/xmlwriter-encoding-utf-8-using-stringwriter-in-c-sharp
        public StringWriterWithEncoding() : this(Encoding.UTF8) { }
        public StringWriterWithEncoding(Encoding encoding) => this.Encoding = encoding;
        public override Encoding Encoding { get; }
    }
    

    And, for the XML <foo Name="hello"><bar Id="101">var value</bar></foo>, the method doc.GetOuterXml(quoteChar : '\'') will generate:

    <?xml version='1.0' encoding='utf-8'?>
    <foo Name='hello'>
      <bar Id='101'>var value</bar>
    </foo>
    

    Demo fiddle #1 here.

    Notice that the single quote character is used for both the XML declaration and attribute values. Your question is unclear, but if you need a single quote for the XML Declaration only and double quotes otherwise, you will need to subclass XmlTextWriter like so:

    public static partial class XmlSerializationHelper
    {
        public static string GetOuterXml(this XmlDocument doc, bool indent = true)
        {
            if (doc == null)
                return null;
            using (var textWriter = new StringWriterWithEncoding())
            {
                using (var xmlWriter = new CustomQuoteCharXmlTextWriter(textWriter) { Formatting = indent ? Formatting.Indented : Formatting.None })
                {
                    doc.Save(xmlWriter);
                }
                return textWriter.ToString();
            }
        }
    }
    
    public class CustomQuoteCharXmlTextWriter : XmlTextWriter
    {
        public CustomQuoteCharXmlTextWriter(Stream w, Encoding encoding) : base(w, encoding) => QuoteChar = '\'';
        public CustomQuoteCharXmlTextWriter(String filename, Encoding encoding) : base(filename, encoding) => QuoteChar = '\'';
        public CustomQuoteCharXmlTextWriter(TextWriter w) : base(w) => QuoteChar = '\'';
        
        public override void WriteStartDocument() 
        {
            base.WriteStartDocument();
            QuoteChar = '"';
        }
    }
    

    And now doc.GetOuterXml() will return:

    <?xml version='1.0' encoding='utf-8'?>
    <foo Name="hello">
      <bar Id="101">var value</bar>
    </foo>
    

    Demo fiddle #2 here.


    [1] See this answer by Peter Ritchie to Can one force XMLWriter to write elements in single quotes?