117

Is there any way to get the xml encoding in the toString() Function?

Example:

xml.Save("myfile.xml");

leads to

<?xml version="1.0" encoding="utf-8"?>
<Cooperations>
  <Cooperation>
    <CooperationId>xxx</CooperationId>
    <CooperationName>Allianz Konzern</CooperationName>
    <LogicalCustomers>

But

tb_output.Text = xml.toString();

leads to an output like this

<Cooperations>
  <Cooperation>
    <CooperationId>xxx</CooperationId>
    <CooperationName>Allianz Konzern</CooperationName>
    <LogicalCustomers>
    ...
Henrik P. Hessel
  • 36,243
  • 17
  • 80
  • 100

9 Answers9

103

Either explicitly write out the declaration, or use a StringWriter and call Save():

using System;
using System.IO;
using System.Text;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        string xml = @"<?xml version='1.0' encoding='utf-8'?>
<Cooperations>
  <Cooperation />
</Cooperations>";

        XDocument doc = XDocument.Parse(xml);
        StringBuilder builder = new StringBuilder();
        using (TextWriter writer = new StringWriter(builder))
        {
            doc.Save(writer);
        }
        Console.WriteLine(builder);
    }
}

You could easily add that as an extension method:

public static string ToStringWithDeclaration(this XDocument doc)
{
    if (doc == null)
    {
        throw new ArgumentNullException("doc");
    }
    StringBuilder builder = new StringBuilder();
    using (TextWriter writer = new StringWriter(builder))
    {
        doc.Save(writer);
    }
    return builder.ToString();
}

This has the advantage that it won't go bang if there isn't a declaration :)

Then you can use:

string x = doc.ToStringWithDeclaration();

Note that that will use utf-16 as the encoding, because that's the implicit encoding in StringWriter. You can influence that yourself though by creating a subclass of StringWriter, e.g. to always use UTF-8.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 14
    This has a small issue in that the encoding in the XDocument declaration is ignored and replaced by the encoding of the StringWriter when doing the save, which may or may not be what you want – Sam Holder Oct 13 '10 at 11:25
  • 2
    Then you combine the extension method with: Utf8StringWriter from http://stackoverflow.com/a/1564727/75963 ;) – Nick Josevski Sep 06 '12 at 14:31
  • 12
    Found it easier to use the extension method above but return the following... return doc.Declaration + doc.ToString(); If the Declaration is null, it just results in an empty string. – Steve G. Dec 06 '12 at 17:17
  • Strange, but I can't get it working now ([.net fiddle](https://dotnetfiddle.net/LbIltF)) - it always uses "utf-16" encoding. I've looked inside `XDocument.Save(TextWriter)` implementation and it just ignores the declaration's encoding, as opposed to `XDocument.Save(String)` or `XDocument.Save(Stream)` implementations. I wonder why... – Ilya Luzyanin Nov 24 '15 at 17:00
  • @IlyaLuzyanin: Yes, it will use "utf-16" as the encoding when you pass in a `StringWriter`, unless you use one which overrides the `Encoding` property. I've got another answer about that. I thought you were saying it was dropping "encoding" entirely... – Jon Skeet Nov 24 '15 at 17:05
  • @IlyaLuzyanin: See http://stackoverflow.com/questions/955611/xmlwriter-to-write-to-a-string-instead-of-to-a-file/955698#955698 - I'll edit that into the answer. – Jon Skeet Nov 24 '15 at 17:06
  • But it really ignores the declaration's encoding still! I mean shouldn't we use other implementations (`XDocument.Save(String)` or `XDocument.Save(Stream)`) if we want to keep the declaration's encoding? Something like in this [demo](https://dotnetfiddle.net/ZSn5bj)? – Ilya Luzyanin Nov 24 '15 at 17:13
  • @IlyaLuzyanin: Then you'd have to detect the existing encoding (which will be in the document) and create an instance of a subclass of `StringWriter` which claims the same encoding, basically. – Jon Skeet Nov 24 '15 at 17:18
56

The Declaration property will contain the XML declaration. To get the contents plus declaration, you can do the following:

tb_output.Text = xml.Declaration.ToString() + xml.ToString()
Ryan Brunner
  • 14,723
  • 1
  • 36
  • 52
13

use this:

output.Text = String.Concat(xml.Declaration.ToString() , xml.ToString())
Gonzalo.-
  • 12,512
  • 5
  • 50
  • 82
Farooq Kaiser
  • 339
  • 4
  • 5
  • 2
    Without creating new XDeclaration("1.0", "utf-8", "yes") and adding into XDocument or other object, xml.Declaration.ToString() will threw a null exception. – Ziggler Dec 02 '14 at 19:54
  • 1
    it's safer like below because Concat does not care about null strings: output.Text = String.Concat(xml.Declaration , xml) – dmihailescu Jan 22 '15 at 22:01
3

I did like this

        string distributorInfo = string.Empty;

        XDocument distributors = new XDocument();

     //below is important else distributors.Declaration.ToString() throws null exception
        distributors.Declaration = new XDeclaration("1.0", "utf-8", "yes"); 

        XElement rootElement = new XElement("Distributors");
        XElement distributor = null;
        XAttribute id = null;

        distributor = new XElement("Distributor");
        id = new XAttribute("Id", "12345678");
        distributor.Add(id);
        rootElement.Add(distributor);

        distributor = new XElement("Distributor");
        id = new XAttribute("Id", "22222222");

        distributor.Add(id);

        rootElement.Add(distributor);         

        distributors.Add(rootElement);

        distributorInfo = String.Concat(distributors.Declaration.ToString(), distributors.ToString());

Please see below for what I get in distributorInfo

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Distributors>
  <Distributor Id="12345678" />
  <Distributor Id="22222222" />
  <Distributor Id="11111111" />
</Distributors>
Ziggler
  • 3,361
  • 3
  • 43
  • 61
  • 1
    good example. some notes: 1) use new XDeclaration("1.0", "utf-8") instead of new XDeclaration("1.0", "utf-8", "yes"), 2) insert new line in last line: distributors.Declaration.ToString() + Environment.NewLine + distributors.ToString() – Alexey Obukhov Aug 04 '16 at 12:14
2

Similar to the other +1 answers, but a bit more detail about the declaration, and a slightly more accurate concatenation.

<xml /> declaration should be on its own line in a formatted XML, so I'm making sure we have the newline added. NOTE: using Environment.Newline so it will produce the platform specific newline

// Parse xml declaration menthod
XDocument document1 =
  XDocument.Parse(@"<?xml version=""1.0"" encoding=""iso-8859-1""?><rss version=""2.0""></rss>");
string result1 =
  document1.Declaration.ToString() +
  Environment.NewLine +
  document1.ToString() ;

// Declare xml declaration method
XDocument document2 = 
  XDocument.Parse(@"<rss version=""2.0""></rss>");
document2.Declaration =
  new XDeclaration("1.0", "iso-8859-1", null);
string result2 =
  document2.Declaration.ToString() +
  Environment.NewLine +
  document2.ToString() ;

Both results produce:

<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0"></rss>
sonjz
  • 4,870
  • 3
  • 42
  • 60
2

A few of these answers solve the poster's request, but seem overly complicated. Here's a simple extension method that avoids the need for a separate writer, handles a missing declaration and supports the standard ToString SaveOptions parameter.

public static string ToXmlString(this XDocument xdoc, SaveOptions options = SaveOptions.None)
{
    var newLine =  (options & SaveOptions.DisableFormatting) == SaveOptions.DisableFormatting ? "" : Environment.NewLine;
    return xdoc.Declaration == null ? xdoc.ToString(options) : xdoc.Declaration + newLine + xdoc.ToString(options);
}

To use the extension, just replace xml.ToString() with xml.ToXmlString()

B2K
  • 2,541
  • 1
  • 22
  • 34
0

You can also use an XmlWriter and call the

Writer.WriteDocType() 

method.

Adriano Carneiro
  • 57,693
  • 12
  • 90
  • 123
Gus Paul
  • 945
  • 2
  • 9
  • 17
0
string uploadCode = "UploadCode";
string LabName = "LabName";
XElement root = new XElement("TestLabs");
foreach (var item in returnList)
{  
       root.Add(new XElement("TestLab",
                new XElement(uploadCode, item.UploadCode),
                new XElement(LabName, item.LabName)
                            )
               );
}

XDocument returnXML = new XDocument(new XDeclaration("1.0", "UTF-8","yes"),
             root);

string returnVal;
using (var sw = new MemoryStream())
{
       using (var strw = new StreamWriter(sw, System.Text.UTF8Encoding.UTF8))
       {
              returnXML.Save(strw);
              returnVal = System.Text.UTF8Encoding.UTF8.GetString(sw.ToArray());
       }
}

// ReturnVal has the string with XML data with XML declaration tag
David
  • 73
  • 7
0

Extension method to get the Xml Declaration included, using string interpolation here and chose to add a new line after xml declaration as this is the standard I guess.

public static class XDocumentExtensions {
        
public static string ToStringIncludeXmlDeclaration(this XDocument doc){
               return $"({((doc.Declaration != null ? doc.Declaration.ToString() + 
     Environment.NewLine : string.Empty) + doc.ToString())}";
    }  
  }
}

Usage:

tb_output.Text = xml.ToStringIncludeXmlDeclaration();
Tore Aurstad
  • 3,189
  • 1
  • 27
  • 22