LINQ to XML frente a DOM

En este artículo se describen algunas diferencias fundamentales entre LINQ to XML y la API de programación XML predominante actual, Document Object Model (DOM) W3C.

Nuevas formas de crear árboles XML

En DOM W3C, los árboles XML se crean de abajo arriba; es decir, se crea un documento, se crean elementos y, a continuación, se agregan los elementos al documento.

Por ejemplo, en el siguiente ejemplo se muestra una forma típica de crear un árbol XML mediante la implementación de DOM de Microsoft, 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 codificación oculta la estructura del árbol XML. LINQ to XML también admite un enfoque alternativo, la construcción funcional, que muestra mejor la estructura. Este enfoque se puede realizar con los constructores XElement y XAttribute. En Visual Basic, también se puede hacer con literales XML. En este ejemplo se muestra la construcción del mismo árbol XML mediante la construcción 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>

Tenga en cuenta que si se aplica la sangría al código para crear el árbol XML, se mostrará la estructura XML subyacente. La versión de Visual Basic usa literales XML.

Para más información, consulte Árboles XML.

Uso directo de elementos XML

La programación con XML suele centrarse en elementos XML y quizás en los atributos. En LINQ to XML, se puede trabajar directamente con atributos y elementos XML. Por ejemplo, puede realizar lo siguiente:

  • Crear elementos XML sin usar un objeto de documento. Esto simplifica la programación cuando se tiene que trabajar con fragmentos de árboles XML.
  • Cargar objetos T:System.Xml.Linq.XElement directamente de un archivo XML.
  • Serializar objetos T:System.Xml.Linq.XElement a un archivo o una secuencia.

Compare esto con modelo DOM del consorcio W3C, en el que el documento XML se usa como contenedor lógico para el árbol XML. En DOM, los nodos XML, incluyendo elementos y atributos, se deben crear en el contexto de un documento XML. A continuación se muestra un fragmento del código para crear un nombre de elemento en 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)

Si desea usar un elemento en varios documentos, debe importar los nodos en los documentos. LINQ to XML evita este grado de complejidad.

Cuando se utiliza LINQ to XML, se usa la clase XDocument solamente si se desea agregar un comentario o una instrucción de procesamiento en el nivel de raíz del documento.

Control simplificado de nombres y espacios de nombres

Controlar nombres, espacios de nombres y prefijos de espacios de nombres suele ser una parte compleja de la programación XML. LINQ to XML simplifica los nombres y los espacios de nombres al eliminar el requisito de tener que tratar con prefijos de espacios de nombres. Si lo desea, puede controlar los prefijos de espacios de nombres. Pero si decide no controlar explícitamente los prefijos de espacios de nombres, durante la serialización, LINQ to XML asignará prefijos de espacios de nombres si son necesarios, o serializará con espacios de nombres predeterminados si no lo son. Si se usan espacios de nombres predeterminados, no habrá prefijos de espacios de nombres en el documento resultante. Para más información, consulte Introducción a los espacios de nombres.

Otro problema de DOM consiste en que no permite cambiar el nombre de un nodo. Por el contrario, hay que crear un nuevo nodo y copiar en él todos los nodos secundarios, por lo que se pierde la identidad del nodo original. LINQ to XML evita este problema al permitir que se establezca la propiedad XName en un nodo.

Compatibilidad con el método estático para cargar XML

LINQ to XML permite cargar XML mediante métodos estáticos en lugar de métodos de instancia. Esto simplifica la carga y el análisis. Para más información, consulte Procedimiento para cargar un documento XML desde un archivo.

Eliminación de la compatibilidad con construcciones DTD

LINQ to XML simplifica aún más la programación XML quitando la compatibilidad con entidades y referencias a entidades. La administración de entidades es compleja y su uso es muy poco común. La eliminación de la compatibilidad aumenta el rendimiento y simplifica la interfaz de programación. Cuando se rellena un árbol de LINQ to XML, se expanden todas las entidades DTD.

Compatibilidad con fragmentos

LINQ to XML no proporciona un equivalente para la clase XmlDocumentFragment. En cambio, es bastante común que el concepto XmlDocumentFragment se pueda controlar mediante el resultado de una consulta que se escribe como IEnumerable<T> de XNode o IEnumerable<T> de XElement.

Compatibilidad con XPathNavigator

LINQ to XML proporciona compatibilidad con XPathNavigator mediante los métodos de extensión del espacio de nombres System.Xml.XPath. Para obtener más información, vea System.Xml.XPath.Extensions.

Compatibilidad con espacios en blanco y sangría

LINQ to XML trata los espacios en blanco de forma más sencilla que DOM.

Un caso muy común es aquel en el que se leen datos XML con sangría, se crea un árbol XML en memoria sin ningún nodo de texto con espacios en blanco (es decir, sin conservar los espacios en blanco), se realizan ciertas operaciones sobre el XML y este se guarda con sangría. Si se serializa el XML con formato, solo se preservan en el XML aquellos espacios en blanco más significativos. Éste es el comportamiento predeterminado en LINQ to XML.

Otro escenario muy común es aquel en el que se lee y se modifica código XML en el que se ha aplicado sangría de forma intencionada. Es posible que no desee modificar esta sangría de ninguna forma. En LINQ to XML, para hacerlo haga lo siguiente:

  • Conserve el espacio en blanco al cargar o analizar el XML.
  • Deshabilite el formato al serializar el XML.

LINQ to XML almacena un espacio en blanco como un nodo XText, en lugar de tener un tipo de nodo Whitespace especializado, como en DOM.

Compatibilidad con anotaciones

Los elementos de LINQ to XML admiten un conjunto extensible de anotaciones. Esto puede resultar útil para realizar un seguimiento de información diversa de un elemento, como la información de esquema, información acerca de si un elemento está enlazado a una interfaz de usuario o cualquier otro tipo de información específica de una aplicación. Para más información, consulte Anotaciones en LINQ to XML.

Compatibilidad con la información de esquema

LINQ to XML proporciona compatibilidad con la validación XSD mediante métodos de extensión en el espacio de nombres System.Xml.Schema. Puede validar que un árbol XML sea compatible con un XSD. Puede rellenar el árbol XML con el conjunto de información posterior a la validación del esquema (PSVI). Para más información, consulte Procedimiento para validar con XSD (LINQ to XML) (C#) y Extensions.

Consulte también