Convertendo XDocument em XmlDocument e vice-versa

189

É um problema muito simples que eu tenho. Eu uso o XDocument para gerar um arquivo XML. Desejo retorná-lo como uma classe XmlDocument. E eu tenho uma variável XmlDocument que preciso converter novamente em XDocument para acrescentar mais nós.

Então, qual é o método mais eficiente para converter XML entre XDocument e XmlDocument? (Sem usar armazenamento temporário em um arquivo.)

Wim ten Brink
fonte

Respostas:

304

Você pode usar o xDocument.CreateReader () incorporado e um XmlNodeReader para converter para frente e para trás.

Colocando isso em um método de extensão para facilitar o trabalho.

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);
            }
        }
    }
}

Fontes:

Mark Coleman
fonte
4
você não precisaria se preocupar em descartar o leitor criado no método ToXmlDocument?
CodeMonkey1313
5
Por que ToXDocument () contém chamada para MoveToContent ()? Parece que ele ignoraria qualquer conteúdo antes do elemento do documento, por exemplo, comentários e instruções de processamento na parte superior do documento XML.
redcalx
@locster a declaração é tratada de maneira diferente entre XmlDocument(como uma propriedade) e XDocument(como um nó). Se você deseja preservar a declaração, precisará manipulá-la explicitamente (consulte blogs.msdn.com/b/ericwhite/archive/2010/03/05/… ou a resposta de @ Dmitry stackoverflow.com/a/8894680/2688 )
bdukes
Infelizmente, isso não funciona no Windows 10 UWP. Publiquei minha solução para essa plataforma abaixo, se alguém estiver interessado.
bc3tech
28

Para mim, esta solução de linha única funciona muito bem

XDocument y = XDocument.Parse(pXmldoc.OuterXml); // where pXmldoc is of type XMLDocument
Abhi
fonte
21
Não use isso - embora isso funcione corretamente, é muito ineficiente, pois converte toda a árvore XML em uma única string e analisa isso novamente posteriormente.
Lucero
3
Veja este post para um benchmark das diferentes abordagens blogs.msdn.microsoft.com/xmlteam/2009/03/31/...
Bernard Vander Beken
7
using System.Xml;
using System.Xml.Linq;

   #region Extention Method
    public static XElement ToXElement(this XmlElement element)
    {
        return XElement.Parse(element.OuterXml);
    }

    public static XmlElement ToXmlElement(this XElement element)
    {
        var doc = new XmlDocument();
        doc.LoadXml(element.ToString());
        return doc.DocumentElement;            
    }
    #endregion

O uso desta extensão é feito usando simplesmente algo como isto

System.Xml.XmlElement systemXml = (new XElement("nothing")).ToXmlElement();
System.Xml.Linq.XElement linqXml = systemXml.ToXElement();
Robert Harvey
fonte
13
Não use isso - embora isso funcione corretamente, é muito ineficiente, pois converte toda a árvore XML em uma única string e analisa isso novamente posteriormente.
Lucero
5

Se você precisar converter a instância de System.Xml.Linq.XDocument na instância de System.Xml.XmlDocument, esse método de extensão ajudará você a não perder a declaração XML na instância resultante de XmlDocument:

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; 
        } 
    } 
}

Espero que ajude!

Dmitry Pavlov
fonte
4

Você pode tentar gravar o XDocument em um XmlWriter canalizado para um XmlReader para um XmlDocument.

Se eu entendo os conceitos corretamente, uma conversão direta não é possível (a estrutura interna é diferente / simplificada com o XDocument). Mas então, eu posso estar errado ...

Daren Thomas
fonte
-1

Se você precisar de uma variante compatível com Win 10 UWP:

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
fonte