200

It's a very simple problem that I have. I use XDocument to generate an XML file. I then want to return it as a XmlDocument class. And I have an XmlDocument variable which I need to convert back to XDocument to append more nodes.

So, what is the most efficient method to convert XML between XDocument and XmlDocument? (Without using any temporary storage in a file.)

Wim ten Brink
  • 25,901
  • 20
  • 83
  • 149

6 Answers6

329

You can use the built in xDocument.CreateReader() and an XmlNodeReader to convert back and forth.

Putting that into an Extension method to make it easier to work with.

using System;
using System.Xml;
using System.Xml.Linq;

namespace MyTest
{
    internal class Program
    {
        private static void Main(string[] args)
        {

            var xmlDocument = new XmlDocument();
            xmlDocument.LoadXml("<Root><Child>Test</Child></Root>");

            var xDocument = xmlDocument.ToXDocument();
            var newXmlDocument = xDocument.ToXmlDocument();
            Console.ReadLine();
        }
    }

    public static class DocumentExtensions
    {
        public static XmlDocument ToXmlDocument(this XDocument xDocument)
        {
            var xmlDocument = new XmlDocument();
            using(var xmlReader = xDocument.CreateReader())
            {
                xmlDocument.Load(xmlReader);
            }
            return xmlDocument;
        }

        public static XDocument ToXDocument(this XmlDocument xmlDocument)
        {
            using (var nodeReader = new XmlNodeReader(xmlDocument))
            {
                nodeReader.MoveToContent();
                return XDocument.Load(nodeReader);
            }
        }
    }
}

Sources:

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Mark Coleman
  • 40,542
  • 9
  • 81
  • 101
  • 4
    wouldn't you have to worry about disposing the reader that was created in the ToXmlDocument method? – CodeMonkey1313 May 19 '10 at 20:53
  • 5
    Why does ToXDocument() contain call to MoveToContent()? This looks liek it would skip over any content ahead of the document element, e.g. any comments and processing instructions at the top of the XML doc. – redcalx Apr 04 '12 at 14:43
  • @locster the declaration is handled differently between `XmlDocument` (as a property) and `XDocument` (as a node). If you want to preserve the declaration, you'll need to handle it explicitly (see http://blogs.msdn.com/b/ericwhite/archive/2010/03/05/convert-xdocument-to-xmldocument-and-convert-xmldocument-to-xdocument.aspx or @Dmitry's answer http://stackoverflow.com/a/8894680/2688) – bdukes Feb 05 '15 at 18:20
  • Unfortunately this doesn't work in Windows 10 UWP. I've posted my solution for that platform below if anybody's interested. – bc3tech Aug 19 '15 at 17:56
31

For me this single line solution works very well

XDocument y = XDocument.Parse(pXmldoc.OuterXml); // where pXmldoc is of type XMLDocument
Abhi
  • 5,501
  • 17
  • 78
  • 133
  • 23
    Don't use this - while this does work correctly, it is very inefficient since it converts the whole XML tree to a single string and parses that again afterwards. – Lucero Jan 09 '14 at 18:28
  • 3
    See this post for a benchmark of the different approaches https://blogs.msdn.microsoft.com/xmlteam/2009/03/31/converting-from-xmldocument-to-xdocument/ – Bernard Vander Beken Apr 21 '16 at 09:14
  • 2
    I'm working on a utility, not production code. Simple and easy is more important to me than performance. – todji Oct 12 '20 at 20:55
8

If you need to convert the instance of System.Xml.Linq.XDocument into the instance of the System.Xml.XmlDocument this extension method will help you to do not lose the XML declaration in the resulting XmlDocument instance:

using System.Xml; 
using System.Xml.Linq;

namespace www.dimaka.com
{ 
    internal static class LinqHelper 
    { 
        public static XmlDocument ToXmlDocument(this XDocument xDocument) 
        { 
            var xmlDocument = new XmlDocument(); 
            using (var reader = xDocument.CreateReader()) 
            { 
                xmlDocument.Load(reader); 
            }

            var xDeclaration = xDocument.Declaration; 
            if (xDeclaration != null) 
            { 
                var xmlDeclaration = xmlDocument.CreateXmlDeclaration( 
                    xDeclaration.Version, 
                    xDeclaration.Encoding, 
                    xDeclaration.Standalone);

                xmlDocument.InsertBefore(xmlDeclaration, xmlDocument.FirstChild); 
            }

            return xmlDocument; 
        } 
    } 
}

Hope that helps!

Dmitry Pavlov
  • 30,789
  • 8
  • 97
  • 121
4

You could try writing the XDocument to an XmlWriter piped to an XmlReader for an XmlDocument.

If I understand the concepts properly, a direct conversion is not possible (the internal structure is different / simplified with XDocument). But then, I might be wrong...

Daren Thomas
  • 67,947
  • 40
  • 154
  • 200
4

There is a discussion on http://blogs.msdn.com/marcelolr/archive/2009/03/13/fast-way-to-convert-xmldocument-into-xdocument.aspx

It seems that reading an XDocument via an XmlNodeReader is the fastest method. See the blog for more details.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
paul
  • 13,312
  • 23
  • 81
  • 144
-1

If you need a Win 10 UWP compatible variant:

using DomXmlDocument = Windows.Data.Xml.Dom.XmlDocument;

    public static class DocumentExtensions
    {
        public static XmlDocument ToXmlDocument(this XDocument xDocument)
        {
            var xmlDocument = new XmlDocument();
            using (var xmlReader = xDocument.CreateReader())
            {
                xmlDocument.Load(xmlReader);
            }
            return xmlDocument;
        }

        public static DomXmlDocument ToDomXmlDocument(this XDocument xDocument)
        {
            var xmlDocument = new DomXmlDocument();
            using (var xmlReader = xDocument.CreateReader())
            {
                xmlDocument.LoadXml(xmlReader.ReadOuterXml());
            }
            return xmlDocument;
        }

        public static XDocument ToXDocument(this XmlDocument xmlDocument)
        {
            using (var memStream = new MemoryStream())
            {
                using (var w = XmlWriter.Create(memStream))
                {
                    xmlDocument.WriteContentTo(w);
                }
                memStream.Seek(0, SeekOrigin.Begin);
                using (var r = XmlReader.Create(memStream))
                {
                    return XDocument.Load(r);
                }
            }
        }

        public static XDocument ToXDocument(this DomXmlDocument xmlDocument)
        {
            using (var memStream = new MemoryStream())
            {
                using (var w = XmlWriter.Create(memStream))
                {
                    w.WriteRaw(xmlDocument.GetXml());
                }
                memStream.Seek(0, SeekOrigin.Begin);
                using (var r = XmlReader.Create(memStream))
                {
                    return XDocument.Load(r);
                }
            }
        }
    }
bc3tech
  • 1,228
  • 14
  • 27