51

Many .NET functions use XmlWriter to output/generate xml. Outputting to a file/string/memory is a very operation:

XmlWriter xw = XmlWriter.Create(PutYourStreamFileWriterEtcHere);
xw.WriteStartElement("root");
...

Sometimes , you need to manipulate the resulting Xml and would therefore like to load it into a XmlDocument or might need an XmlDocument for some other reason but you must generate the XML using an XmlWriter. For example, if you call a function in a 3rd party library that outputs to a XmlWriter only.

One of the things you can do is write the xml to a string and then load it into your XmlDocument:

StringWriter S = new StringWriter();
XmlWriter xw = XmlWriter.Create(S);
/* write away */
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(S.ToString());

However this is inefficient - first you serialize all the xml info into a string, then you parse the string again to create the DOM.

How can you point an XmlWriter to build a XmlDocument directly?

Boaz
  • 25,331
  • 21
  • 69
  • 77

5 Answers5

94

Here's at least one solution:

XmlDocument doc = new XmlDocument(); 
using (XmlWriter writer = doc.CreateNavigator().AppendChild()) 
{ 
    // Do this directly 
     writer.WriteStartDocument(); 
     writer.WriteStartElement("root"); 
     writer.WriteElementString("foo", "bar"); 
     writer.WriteEndElement(); 
     writer.WriteEndDocument();
    // or anything else you want to with writer, like calling functions etc.
}

Apparently XpathNavigator gives you a XmlWriter when you call AppendChild()

Credits go to Martin Honnen on : http://groups.google.com/group/microsoft.public.dotnet.xml/browse_thread/thread/24e4c8d249ad8299?pli=1

Boaz
  • 25,331
  • 21
  • 69
  • 77
  • 1
    Thanks! It was obvious to me that you'd be able to use XmlWriter as a builder for XmlDocument but I just couldn't find an easy way to do it so I ended up writing to buffer and parsing again. They could've made it a little easier to find. – Tomek Szpakowicz Apr 26 '10 at 11:41
  • Anyone know if the same is possible using xdocument/xelement (using .NET 3.5 so cant load directly from the memorystream) – baileyswalk Mar 23 '11 at 10:14
  • 3
    Also note that, as written, the resulting `XmlWriter` will have a conformance level of `Document`, so if you do send it as the input to an XSL transform as input (and you're not creating a complete document), you can use `new XmlDocument().CreateFragment().CreateNavigator()` instead. – harpo May 23 '11 at 03:47
  • 2
    Note one drawback to this is that WriteRaw behaves differently for an XmlWriter based on XPathNavigator — namely, it escapes output. – harpo Jul 23 '11 at 20:09
  • And finally (since I'm still using this), note that the navigator throws away the `DOCTYPE`. Not sure of a workaround for that. – harpo Dec 16 '13 at 00:03
  • Doesn't work if you're using `async` versions of the `XmlWriter` methods - you'll just get `System.NotImplementedException`: *The method or operation is not implemented.* – Xharlie Mar 28 '17 at 08:49
  • 1
    This is totally great.So speedy and elegant to build an `XmlDocument` without going through `String` or `Stream`. A useful example: convert arbitrary **WPF** runtime instance directly into an `XmlDocument` representation of the `XAML` object graph it roots: `var xd = new XmlDocument(); var w = xd.CreateNavigator().AppendChild(); XamlWriter.Save(inst, new XamlDesignerSerializationManager(w) { XamlWriterMode = XamlWriterMode.Expression });` (Make sure to use the `XamlWriter` from `System.Windows.Markup`) This obviously makes the alternatives look very clunky. Fantastic! – Glenn Slayden Dec 09 '17 at 00:06
11

You could do the opposite : build the XmlDocument first using DOM, then write it to a XmlWriter :

XmlDocument xdoc = new XmlDocument();
... // build the document

StringWriter S = new StringWriter();
XmlWriter xw = XmlWriter.Create(S);
xdoc.WriteTo(xw);
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • Sorry but this doesn't answer the question. I need to use a XmlWriter to generate the XML - not a XmlDocument. – Boaz Aug 28 '09 at 13:46
  • 4
    XmlWriter isn't designed to write to a XmlDocument, it's designed to write to a Stream or TextWriter. What you're asking is simply not possible, I'm just suggesting another approach... – Thomas Levesque Aug 28 '09 at 13:47
  • Anyway, if you can generate the XML with a XmlWriter, I don't see why you couldn't generate it with a XmlDocument... – Thomas Levesque Aug 28 '09 at 13:48
  • 2
    +1 to counter pointless downvote. This is a decent answer to the question as asked IMHO – Binary Worrier Aug 28 '09 at 13:48
  • 1
    I don't like the answer either. It's the classic SO-problem: "How can I solve this in Javascript only?" -- "Use jQuery!" – Seb Nilsson Aug 28 '09 at 13:50
  • @Seb Nilsson: what's your point ? Loading the XmlDocument from a Stream has the same issue as parsing a string. And I don't see how it compares to jQuery... – Thomas Levesque Aug 28 '09 at 13:51
  • 2
    @Tomas Levesque: My point is that someone asks a question "How do I solve X" and the answer is "Don't solve X, solve Y instead", when that's not the question. If it's impossible to do, then that's the answer. – Seb Nilsson Aug 28 '09 at 13:59
  • 2
    @Seb: I strongly disagree. We wouldn't get far as programmers if we stopped every time we needed to get from A to C and there was no direct root. Our profession depends on being able to find the alternative route through B. Thomas is suggesting an alternative approach, honestly I don't understand the vilification of this answer (Yes, I realise this is a community. Yes I have exercised my right to vote on this answer. However I am allowed to express my dissatisfaction with the general response) – Binary Worrier Aug 28 '09 at 14:15
  • 1
    @Thomas Levesque - apparently it is possible. – Boaz Aug 28 '09 at 14:31
  • Yes, I thought I had seen something like that, but couldn't remember what it was exactly... – Thomas Levesque Aug 28 '09 at 14:35
  • 1
    It's nice to find a supplement answer which goes both ways. I need to convert back and forth due to incorporating two separate assemblies using each method. Thanks! – TamusJRoyce Oct 03 '11 at 18:18
  • 1
    i think it is a correct approach, not good for large XML, but this is answering the question and even not to bad of practice, even better then the stated pseudo in the question body. – Tomer W Aug 30 '12 at 12:58
  • This does not answer the question, let me quote `Many .NET functions use XmlWriter to output/generate xml.` - you can't use this approach to call those functions. – Zarat Jan 24 '19 at 15:25
7

You can write xml file using XMLWriter class. Here is example for this.

    XmlWriterSettings objSetting = new XmlWriterSettings();
    objSetting.Indent = true;
    objSetting.NewLineOnAttributes = true;

    System.Text.StringBuilder sb = new System.Text.StringBuilder();


    using (XmlWriter objWriter = XmlWriter.Create(sb, objSetting))
    {
        //Note the artificial, but useful, indenting
        objWriter.WriteStartDocument();

        objWriter.WriteStartElement("books");

        ////////Start Book Element///////

        objWriter.WriteStartElement("book");

        objWriter.WriteStartAttribute("ISBN");
        objWriter.WriteValue("asp1");
        objWriter.WriteEndAttribute();

        objWriter.WriteStartElement("Title");
        objWriter.WriteValue("ASP.NET");
        objWriter.WriteEndElement();

        objWriter.WriteElementString("ReleaseDate", "11/11/2010");

        objWriter.WriteStartElement("Pages");
        objWriter.WriteValue(200);
        objWriter.WriteEndElement(); //price

        objWriter.WriteEndElement(); //book
        ////////End Book Element///////


        ////////Another Element

        ////////Start Book Element///////

        objWriter.WriteStartElement("book");

        objWriter.WriteStartAttribute("ISBN");
        objWriter.WriteValue("c#2");
        objWriter.WriteEndAttribute();

        objWriter.WriteStartElement("Title");
        objWriter.WriteValue("C#.NET");
        objWriter.WriteEndElement();

        objWriter.WriteElementString("ReleaseDate", "10/11/2010");

        objWriter.WriteStartElement("Pages");
        objWriter.WriteValue(500);
        objWriter.WriteEndElement(); 

        objWriter.WriteEndElement(); //book
        ////////End Book Element///////



        objWriter.WriteEndElement(); //books
        objWriter.WriteEndDocument();

    }

    File.WriteAllText(Server.MapPath("BooksList.xml"), sb.ToString());
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Jayesh Sorathia
  • 1,596
  • 15
  • 16
4

The idea behind XmlWriter is to wait until you have finished modifying your data before you start writing.

XmlWriter wasn't built with your situation in mind.

Either

  • Wait until you know what your data is going to be before writing

or

  • Do what you're currently doing
Binary Worrier
  • 50,774
  • 20
  • 136
  • 184
  • 5
    I disagree. XmlWriter is a nice example of builder pattern and it makes perfect sense to use it to build DOM (XmlDocument or any other implementation). And I have very real use case: I read XML data and transform it using some XslCompiledTransform, which writes to XmlWriter, which directly constructs XmlDocument, which I can process and then write out (possibly applying some other XSLT on output). What's wrong with that? And writing out to stream and then parsing again is: a) pointless (it doesn't help or make design any clearer), b) unnecessary and c) highly inefficient. – Tomek Szpakowicz Apr 26 '10 at 11:50
1

There is an underlying Stream object that the XmlWriter was writing to, if it was bidirectional (MemoryStream), you could simply re-position it back to -0- and then use the Stream object in the XmlDocument.Load(stream).

HTH,

Z

Zach Bonham
  • 6,759
  • 36
  • 31