LINQ to XML e DOM

Este artigo descreve algumas das principais diferenças entre o LINQ to XML e a atual API de programação de XML predominante, o W3C DOM (Modelo de Objeto do Documento).

Novas maneiras de criar árvores XML

No W3C DOM, você cria uma árvore XML de baixo para cima; ou seja, você cria um documento, cria elementos e, em seguida, adiciona elementos ao documento.

Por exemplo, a seguir é usada uma forma comum de criar uma árvore XML usando a implementação da Microsoft do DOM, XmlDocument.

XmlDocument doc = new XmlDocument();
XmlElement name = doc.CreateElement("Name");
name.InnerText = "Patrick Hines";
XmlElement phone1 = doc.CreateElement("Phone");
phone1.SetAttribute("Type", "Home");
phone1.InnerText = "206-555-0144";
XmlElement phone2 = doc.CreateElement("Phone");
phone2.SetAttribute("Type", "Work");
phone2.InnerText = "425-555-0145";
XmlElement street1 = doc.CreateElement("Street1");
street1.InnerText = "123 Main St";
XmlElement city = doc.CreateElement("City");
city.InnerText = "Mercer Island";
XmlElement state = doc.CreateElement("State");
state.InnerText = "WA";
XmlElement postal = doc.CreateElement("Postal");
postal.InnerText = "68042";
XmlElement address = doc.CreateElement("Address");
address.AppendChild(street1);
address.AppendChild(city);
address.AppendChild(state);
address.AppendChild(postal);
XmlElement contact = doc.CreateElement("Contact");
contact.AppendChild(name);
contact.AppendChild(phone1);
contact.AppendChild(phone2);
contact.AppendChild(address);
XmlElement contacts = doc.CreateElement("Contacts");
contacts.AppendChild(contact);
doc.AppendChild(contacts);
Dim doc As XmlDocument = New XmlDocument()
Dim name As XmlElement = doc.CreateElement("Name")
name.InnerText = "Patrick Hines"
Dim phone1 As XmlElement = doc.CreateElement("Phone")
phone1.SetAttribute("Type", "Home")
phone1.InnerText = "206-555-0144"
Dim phone2 As XmlElement = doc.CreateElement("Phone")
phone2.SetAttribute("Type", "Work")
phone2.InnerText = "425-555-0145"
Dim street1 As XmlElement = doc.CreateElement("Street1")
street1.InnerText = "123 Main St"
Dim city As XmlElement = doc.CreateElement("City")
city.InnerText = "Mercer Island"
Dim state As XmlElement = doc.CreateElement("State")
state.InnerText = "WA"
Dim postal As XmlElement = doc.CreateElement("Postal")
postal.InnerText = "68042"
Dim address As XmlElement = doc.CreateElement("Address")
address.AppendChild(street1)
address.AppendChild(city)
address.AppendChild(state)
address.AppendChild(postal)
Dim contact As XmlElement = doc.CreateElement("Contact")
contact.AppendChild(name)
contact.AppendChild(phone1)
contact.AppendChild(phone2)
contact.AppendChild(address)
Dim contacts As XmlElement = doc.CreateElement("Contacts")
contacts.AppendChild(contact)
doc.AppendChild(contacts)
Console.WriteLine(doc.OuterXml)

Este estilo de codificação oculta a estrutura da árvore XML. O LINQ to XML também dá suporte a uma abordagem alternativa, a construção funcional, que mostra melhor a estrutura. Essa abordagem pode ser adotada com os construtores XElement eXAttribute. No Visual Basic, isso também pode ser feito com literais XML. Este exemplo demonstra a construção da mesma árvore XML usando a construção funcional:

XElement contacts =
    new XElement("Contacts",
        new XElement("Contact",
            new XElement("Name", "Patrick Hines"),
            new XElement("Phone", "206-555-0144",
                new XAttribute("Type", "Home")),
            new XElement("phone", "425-555-0145",
                new XAttribute("Type", "Work")),
            new XElement("Address",
                new XElement("Street1", "123 Main St"),
                new XElement("City", "Mercer Island"),
                new XElement("State", "WA"),
                new XElement("Postal", "68042")
            )
        )
    );
Dim contacts = _
    <Contacts>
        <Contact>
            <Name>Patrick Hines</Name>
            <Phone Type="Home">206-555-0144</Phone>
            <Phone Type="Work">425-555-0145</Phone>
            <Address>
                <Street1>123 Main St</Street1>
                <City>Mercer Island</City>
                <State>WA</State>
                <Postal>68042</Postal>
            </Address>
        </Contact>
    </Contacts>

Observe que o recuo do código para construir a árvore XML mostra a estrutura do XML subjacente. A versão do Visual Basic usa literais XML.

Para obter mais informações, confira árvores XML.

Trabalhar diretamente com elementos XML

Quando você programa com XML, o foco principal é geralmente em elementos XML e talvez em atributos. No LINQ to XML, você pode trabalhar diretamente com elementos e atributos XML. Por exemplo, você pode fazer o seguinte:

  • Criar elementos XML sem usar nenhum objeto de documento. Isso simplifica a programação quando você tem que trabalhar com partes de árvores XML.
  • Carregue objetos T:System.Xml.Linq.XElement diretamente de um arquivo XML.
  • Serialize objetos T:System.Xml.Linq.XElement para um arquivo ou fluxo.

Compare isso para o W3C DOM, no qual o documento XML é usado como um contêiner lógico para a árvore XML. No DOM, os nós XML, incluindo elementos e atributos, devem ser criados no contexto de um documento XML. Aqui está um fragmento de código para criar um elemento de nome DOM:

XmlDocument doc = new XmlDocument();
XmlElement name = doc.CreateElement("Name");
name.InnerText = "Patrick Hines";
doc.AppendChild(name);
Dim doc As XmlDocument = New XmlDocument()
Dim name As XmlElement = doc.CreateElement("Name")
name.InnerText = "Patrick Hines"
doc.AppendChild(name)

Se você quiser usar um elemento em vários documentos, deverá importar os nós nos documentos. O LINQ to XML evita essa camada de complexidade.

Ao usar LINQ to XML, você usará a classe XDocument somente se você desejar adicionar um comentário ou uma instrução de processamento no nível raiz do documento.

Tratamento simplificado de nomes e namespaces

Tratar nomes, namespaces e prefixos de namespace é geralmente uma parte complexa da programação de XML. O LINQ to XML simplifica nomes e namespaces eliminando a necessidade de lidar com prefixos de namespace. Se quiser, você pode controlar prefixos de namespace. Mas, se você optar por não controlar explicitamente os prefixos de namespace, o LINQ to XML atribuirá prefixos de namespace durante a serialização se eles forem necessários ou os serializará usando namespaces padrão, se não forem. Se namespaces padrão forem usados, não haverá prefixos de namespace no documento resultante. Para obter mais informações, confira Visão geral de namespaces.

Outro problema com os DOM é que ele não permite que você altere o nome de um nó. Em vez disso, você precisa criar um novo nó e copiar todos os nós filhos para ele, perdendo a identidade do nó original. O LINQ to XML evita esse problema permitindo que você defina a propriedade XName em um nó.

Suporte de método estático para carregar XML

O LINQ to XML permite que você carregue XML usando métodos estáticos em vez de métodos de instância. Isso simplifica o carregamento e a análise. Para mais informações, confira Como carregar XML de um arquivo.

Remoção de suporte para construções de DTD

O LINQ to XML simplifica ainda mais a programação de XML removendo o suporte para entidades e referências a entidades. O gerenciamento de entidades é complexo e raramente é usado. Remover o suporte aumenta o desempenho e simplifica a interface de programação. Quando uma árvore do LINQ to XML é preenchida, todas as entidades de DTD são expandidas.

Suporte para fragmentos

O LINQ to XML não fornece um equivalente para a classe XmlDocumentFragment. Em muitos casos, no entanto, o conceito de XmlDocumentFragment pode ser tratado pelo resultado de uma consulta que é digitada como IEnumerable<T> de XNode ou IEnumerable<T> de XElement.

Suporte para XPathNavigator

O LINQ to XML dá suporte a XPathNavigator por meio de métodos de extensão no namespace System.Xml.XPath. Para obter mais informações, consulte System.Xml.XPath.Extensions.

Suporte para espaço em branco e recuo

O LINQ to XML trata espaços em branco de maneira mais simples que o DOM.

Um cenário comum é ler o XML recuado, criar uma árvore XML na memória sem nenhum nó de texto de espaço em branco (isto é, não preservar espaço em branco), execute algumas operações no XML e, em seguida, salvar o XML com recuo. Quando você serializa o XML com formatação, somente os espaços em branco significativos na árvore XML são preservados. Esse é o comportamento padrão para LINQ to XML.

Outro cenário comum é ler e modificar XML que já foi recuado intencionalmente. Você pode não querer modificar este recuo de nenhuma forma. No LINQ to XML, você pode fazer isso:

  • Preservando o espaço em branco ao carregar ou analisar o XML.
  • Desabilitando a formatação ao serializar o XML.

O LINQ to XML armazena o espaço em branco como um nó de XText, em vez de ter um tipo de nó especializado do Whitespace, assim como o DOM.

Suporte para anotações

Elementos do LINQ to XML dão suporte a um conjunto extensível de anotações. Isso é útil para acompanhar informações variadas sobre um elemento, como informações de esquema, informações sobre se o elemento está associado a uma interface do usuário ou qualquer outro tipo de informações específicas do aplicativo. Para mais informações, confira Anotações LINQ to XML.

Suporte para informações do esquema

O LINQ to XML dá suporte para validação de XSD por meio de métodos de extensão no namespace System.Xml.Schema. Você pode validar que uma árvore XML está em conformidade com XSD. Você pode preencher a árvore XML com o PSVI (post-schema-validation infoset). Para mais informações, confira Como validar usando XSD e Extensions.

Confira também