131

I have a WCF service that needs to return a string of XML. But it seems like the writer only wants to build up a file, not a string. I tried:

string nextXMLstring = "";
using (XmlWriter writer = XmlWriter.Create(nextXMLstring))

This generates an error saying nextXMLstring doesnt have a file path. It wants something like:

using (XmlWriter writer = XmlWriter.Create("nextXMLstring.xml"))

How can I build up my XML and then return it as a string??

Thanks!!

ChrisF
  • 134,786
  • 31
  • 255
  • 325
Blaze
  • 1,863
  • 7
  • 23
  • 40

6 Answers6

242

You need to create a StringWriter, and pass that to the XmlWriter.

The string overload of the XmlWriter.Create is for a filename.

E.g.

using (var sw = new StringWriter()) {
  using (var xw = XmlWriter.Create(sw)) {
    // Build Xml with xw.


  }
  return sw.ToString();
}
Richard
  • 106,783
  • 21
  • 203
  • 265
  • 3
    @Will: Rolled back your change. XmlTextWriter.Close() will flush to the stream, so want that to happen before extracting the string. (Little difference in this case, but prefer to do this consistently because flush semantics of *Writer and Stream classes is not always clearly documented.) – Richard Jun 05 '09 at 13:57
  • 1
    Just a comment for people using this. If you happen to omit the using() and instead declare your XmlWriter normally then make sure to call xw.Flush before you call sw.ToString() or else you may not get all content! (Obviously better to use the using brackets...) – Ravendarksky Jul 16 '14 at 10:34
  • Keep in mind that the following code gives CA2202 warning during code analysis, beacuse Dispose() method will be called twice on StringWriter object – Łukasz Kosiak Aug 25 '16 at 11:58
  • this is the answer I was looking for, thanks! – MAXE Feb 04 '22 at 13:51
121

As Richard said, StringWriter is the way forward. There's one snag, however: by default, StringWriter will advertise itself as being in UTF-16. Usually XML is in UTF-8. You can fix this by subclassing StringWriter;

public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding
    {
         get { return Encoding.UTF8; }
    }
}

This will affect the declaration written by XmlWriter. Of course, if you then write the string out elsewhere in binary form, make sure you use an encoding which matches whichever encoding you fix for the StringWriter. (The above code always assumes UTF-8; it's trivial to make a more general version which accepts an encoding in the constructor.)

You'd then use:

using (TextWriter writer = new Utf8StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(writer))
    {
        ...
    }
    return writer.ToString();
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
33

I know this is old and answered, but here is another way to do it. Particularly if you don't want the UTF8 BOM at the start of your string and you want the text indented:

using (var ms = new MemoryStream())
using (var x = new XmlTextWriter(ms, new UTF8Encoding(false)) 
                   { Formatting = Formatting.Indented })
{
     // ...
     return Encoding.UTF8.GetString(ms.ToArray());
}
brianary
  • 8,996
  • 2
  • 35
  • 29
  • 4
    `Encoding.UTF8.GetString(ms.ToArray())` is simplification on your return. – SliverNinja - MSFT Aug 30 '12 at 16:59
  • 1
    `ms.ToArray()` returns no items when I tried this. Had to add `x.Close()` or move the return statement just outside of the inner using statement. – Rich C Apr 12 '13 at 06:30
  • Does utf8.GetString(ms.GetBuffer(), 0, (int)ms.Length); work? – brianary Apr 16 '13 at 00:08
  • 1
    @Rich C - I suspect this is because your stream was not flushed. The XmlTextWriter would have been disposed outside of its using statement which would cause it to flush. – yourbuddypal Oct 20 '14 at 14:42
16

Use StringBuilder:

var sb = new StringBuilder();
    using (XmlWriter xmlWriter = XmlWriter.Create(sb))
    {
        ...
    }
return sb.ToString();
Ria
  • 10,237
  • 3
  • 33
  • 60
5

Guys don't forget to call xmlWriter.Close() and xmlWriter.Dispose() or else your string won't finish creating. It will just be an empty string

saunupe1911
  • 61
  • 1
  • 1
  • 1
    Don't worry, using statement will handle the disposal of the object. –  Apr 13 '16 at 21:51
  • This is a question from 2009. So, the value in providing an answer now would be for future users who might have similar issues. Consequently, answers to old questions like this should only be provided if they can clearly identify the problem and explain/provide a solution. It is usually fruitless to try to engage the OP in a conversation as they’re likely to have moved on. – MikeC Apr 13 '16 at 22:03
  • 1
    I was going through all these examples and was wonder why do I get empty string. `xmlWriter.Close()` was the solution. – Rafał Ryszkowski Dec 01 '18 at 07:28
0

Well I think the simplest and fastest solution here would be just to:

StringBuilder sb = new StringBuilder();

using (var writer = XmlWriter.Create(sb, settings))
{
    ... // Whatever code you have/need :)

    sb = sb.Replace("encoding=\"utf-16\"", "encoding=\"utf-8\""); //Or whatever uft you want/use.
    //Before you finally save it:
    File.WriteAllText("path\\dataName.xml", sb.ToString());
}
Deniz
  • 429
  • 1
  • 4
  • 19