Capitulo 5 - LINQ to XML (Parte 1)

El XML ha sido una tecnología con crecimiento rápido , proporciona un medio detallado para la transferencia de datos que pueden ser fácilmente comprensible por las computadoras, así como por la gente. A menudo tendrá que consultar los datos XML.
Otro requisito común es transformar XML en un formato diferente, convertir un  XML a una forma diferente de XML, convertir XML en HTML, convertir texto en XML.

Lección 1: Trabajando con las clases XmlDocument y XmlReader
La clase XmlDocument
El W3C ha proporcionado las normas que definen la estructura y una interfaz de programación estándar llamado Document Object Model (DOM) que se pueden utilizar en una amplia variedad de entornos y aplicaciones para documentos XML.
Las clases XML son accesibles haciendo una referencia a System.Xml.dll y agregando  Imports System.Xml (C # using System.Xml;) en el código.La clase XmlDocument es una representación en memoria de XML utilizando el DOM Nivel 1 y Nivel 2. Esta clase se puede utilizar para navegar y editar los nodos XML.
Hay otra clase, XmlDataDocument, que hereda de la clase XmlDocument y representa datos relacionales, se encuentra en System.Data.dll, Estas clases proporcionan varios métodos para implementar la especificación de nivel 2 y tienen métodos para facilitar las operaciones comunes. La clase XmlDocument, que hereda de XmlNode, contiene todos los métodos para la creación de elementos y atributos XML.
Nombre Descripción
AppendChild Agrega el nodo especificado al final de la lista de nodos secundarios de este nodo. (Se hereda de XmlNode).
Clone Crea un duplicado de este nodo. (Se hereda de XmlNode).
CloneNode Crea un duplicado de este nodo. (Invalida a XmlNode.CloneNode(Boolean)).
CreateAttribute(String) Crea un XmlAttribute con el Name especificado.
CreateAttribute(String, String) Crea un XmlAttribute con el nombre completo y el NamespaceURI especificados.
CreateAttribute(String, String, String) Crea un XmlAttribute con los Prefix, LocalName y NamespaceURI especificados.
CreateCDataSection Crea un objeto XmlCDataSection que contiene los datos especificados.
CreateComment Crea un objeto XmlComment que contiene los datos especificados.
CreateDefaultAttribute Crea un atributo predeterminado con el prefijo, el nombre local y el identificador URI de espacio de nombres especificados.
CreateDocumentFragment Crea un objeto XmlDocumentFragment.
CreateDocumentType Devuelve un nuevo objeto XmlDocumentType.
CreateElement(String) Crea un elemento con el nombre especificado.
CreateElement(String, String) Crea un XmlElement con el nombre completo y el NamespaceURI.
CreateElement(String, String, String) Crea un elemento con los valores Prefix, LocalName y NamespaceURI especificados.
CreateEntityReference Crea un objeto XmlEntityReference con el nombre especificado.
CreateNavigator Crea un nuevo objeto XPathNavigator para navegar por este documento. (Invalida a XmlNode.CreateNavigator).
CreateNavigator(XmlNode) Crea un objeto XPathNavigator para navegar por este documento colocado en el nodo XmlNode especificado.
CreateNode(String, String, String) Crea un XmlNode con el tipo de nodo, Name y NamespaceURI especificados.
CreateNode(XmlNodeType, String, String) Crea un XmlNode con los XmlNodeType, Name y NamespaceURI especificados.
CreateNode(XmlNodeType, String, String, String) Crea un XmlNode con XmlNodeType, Prefix, Name y NamespaceURI especificados.
CreateProcessingInstruction Crea un objeto XmlProcessingInstruction con el nombre y los datos especificados.
CreateSignificantWhitespace Crea un nodo XmlSignificantWhitespace.
CreateTextNode Crea un objeto XmlText con el texto especificado.
CreateWhitespace Crea un nodo XmlWhitespace.
CreateXmlDeclaration Crea un nodo XmlDeclaration con los valores especificados.
Equals(Object) Determina si el objeto Object especificado es igual al objeto Object actual. (Se hereda de Object).
Finalize Permite que un objeto intente liberar recursos y realizar otras operaciones de limpieza antes de ser reclamado por la recolección de elementos no utilizados. (Se hereda de Object).
GetElementById Obtiene el XmlElement con el identificador especificado.
GetElementsByTagName(String) Devuelve un objeto XmlNodeList que contiene una lista de todos los elementos descendientes que coinciden con el Nameespecificado.
GetElementsByTagName(String, String) Devuelve un objeto XmlNodeList que contiene una lista de todos los elementos descendientes que coinciden con el LocalName y el NamespaceURI especificados.
GetEnumerator Proporciona funcionalidad para la iteración de estilo "foreach" en los nodos de XmlNode. (Se hereda de XmlNode).
GetHashCode Actúa como función hash para un tipo concreto. (Se hereda de Object).
GetNamespaceOfPrefix Busca la declaración xmlns más cercana para el prefijo especificado que está en el ámbito del nodo actual y devuelve el identificador URI de espacio de nombres de la declaración. (Se hereda de XmlNode).
GetPrefixOfNamespace Busca la declaración xmlns más cercana para el identificador URI de espacio de nombres especificado que está en el ámbito del nodo actual y devuelve el prefijo definido en la declaración. (Se hereda de XmlNode).
GetType Obtiene el objeto Type de la instancia actual. (Se hereda de Object).
ImportNode Importa un nodo de otro documento al documento actual.
InsertAfter Inserta el nodo especificado inmediatamente detrás del nodo de referencia igualmente especificado. (Se hereda deXmlNode).
InsertBefore Inserta el nodo especificado inmediatamente antes del nodo de referencia igualmente especificado. (Se hereda deXmlNode).
Load(Stream) Carga el documento XML desde la secuencia especificada.
Load(String) Carga el documento XML desde la dirección URL especificada.
Load(TextReader) Carga el documento XML desde el TextReader especificado.
Load(XmlReader) Carga el documento XML desde el XmlReader especificado.
LoadXml Carga el documento XML desde la cadena especificada.
MemberwiseClone Crea una copia superficial del objeto Object actual. (Se hereda de Object).
Normalize Hace que todos los nodos XmlText de toda la profundidad del subárbol situado bajo XmlNode aparezcan de forma "normal", de modo que sólo el marcado (es decir, las etiquetas, comentarios, instrucciones de procesamiento, secciones CDATA y referencias a entidades) separa los nodos XmlText, es decir, no hay nodos XmlText adyacentes. (Se hereda deXmlNode).
PrependChild Agrega el nodo especificado al principio de la lista de nodos secundarios de este nodo. (Se hereda de XmlNode).
ReadNode Crea un objeto XmlNode tomando como base la información de XmlReader. El lector debe estar situado en un nodo o en un atributo.
RemoveAll Quita todos los atributos y nodos secundarios del nodo actual. (Se hereda de XmlNode).
RemoveChild Quita el nodo secundario especificado. (Se hereda de XmlNode).
ReplaceChild Reemplaza el nodo secundario oldChild por el nodo newChild. (Se hereda de XmlNode).
Save(Stream) Guarda el documento XML en la secuencia especificada.
Save(String) Guarda el documento XML en el archivo especificado.
Save(TextWriter) Guarda el documento XML en el TextWriter especificado.
Save(XmlWriter) Guarda el documento XML en el XmlWriter especificado.
SelectNodes(String) Selecciona una lista de nodos que coinciden con la expresión XPath. (Se hereda de XmlNode).
SelectNodes(String, XmlNamespaceManager) Selecciona una lista de nodos que coinciden con la expresión XPath. Los prefijos encontrados en la expresión XPath se resuelven utilizando el XmlNamespaceManager proporcionado. (Se hereda de XmlNode).
SelectSingleNode(String) Selecciona el primer XmlNode que coincide con la expresión XPath. (Se hereda de XmlNode).
SelectSingleNode(String, XmlNamespaceManager) Selecciona el primer XmlNode que coincide con la expresión XPath. Los prefijos encontrados en la expresión XPath se resuelven utilizando el XmlNamespaceManager proporcionado. (Se hereda de XmlNode).
Supports Comprueba si la implementación de DOM incluye una característica específica. (Se hereda de XmlNode).
ToString Devuelve una cadena que representa el objeto actual. (Se hereda de Object).
Validate(ValidationEventHandler) Valida el objeto XmlDocument según los esquemas del lenguaje de definición de esquemas XML (XSD) de la propiedadSchemas.
Validate(ValidationEventHandler, XmlNode) Valida el objeto XmlNode especificado según los esquemas del lenguaje de definición de esquemas XML (XSD) de la propiedad Schemas.
WriteContentTo Guarda todos los nodos secundarios del nodo XmlDocument en el XmlWriter especificado. (Invalida aXmlNode.WriteContentTo(XmlWriter)).
WriteTo Guarda el nodo XmlDocument en el XmlWriter especificado. (Invalida a XmlNode.WriteTo(XmlWriter)).


Creando un XmlDocument
El siguiente ejemplo muestra cómo se puede crear un XmlDocument y después guardarlo en un archivo. Se debe importar System.Xml y System.IO.
-----------------------------VB----------------------------------
‘creo el xmlDocument
Dim xmlDoc As New XmlDocument()
Dim el As XmlElement
Dim childCounter As Integer
Dim grandChildCounter As Integer
’Creo la declaracion xml y la agrego
xmlDoc.AppendChild( _
xmlDoc.CreateXmlDeclaration("1.0", "utf-8", Nothing))

’Creo un elemento y lo agrego
el = xmlDoc.CreateElement("MyRoot")
xmlDoc.AppendChild(el)

For childCounter = 1 To 4
Dim childelmt As XmlElement
Dim childattr As XmlAttribute
’creo un elemento y le agrego el atributo ID
childelmt = xmlDoc.CreateElement("MyChild")
childattr = xmlDoc.CreateAttribute("ID")
childattr.Value = childCounter.ToString()
childelmt.Attributes.Append(childattr)
’Agrego el elemento al elemento root
el.AppendChild(childelmt)
For grandChildCounter = 1 To 3
’Creo el elemento nieto
childelmt.AppendChild(xmlDoc.CreateElement("MyGrandChild"))
Next
Next
’lo guardo al archivo
xmlDoc.Save(GetFilePath("XmlDocumentTest.xml"))
txtLog.AppendText("XmlDocumentTest.xml Created" + vbCrLf)
End Sub

Private Function getFilePath(ByVal fileName As String) As String
Return Path.Combine(Environment.GetFolderPath( _
Environment.SpecialFolder.Desktop), fileName)
End Function

-----------------------------CS----------------------------------
//creo un XmlDocument
var xmlDoc = new XmlDocument();
XmlElement el;
int childCounter;
int grandChildCounter;
//genero la declaracion XML
xmlDoc.AppendChild(
xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null));
//Creo el nodo root y se lo agrego a xmldoc
el = xmlDoc.CreateElement("MyRoot");
xmlDoc.AppendChild(el);

for (childCounter = 1; childCounter <= 4; childCounter++)
{
//creo el elemento hijo con el atributo ID
XmlElement childelmt;
XmlAttribute childattr;
childelmt = xmlDoc.CreateElement("MyChild");
childattr = xmlDoc.CreateAttribute("ID");
childattr.Value = childCounter.ToString();
childelmt.Attributes.Append(childattr);
el.AppendChild(childelmt);
for (grandChildCounter = 1; grandChildCounter <= 3;
grandChildCounter++)
{
//Creo el elemnto nieto
childelmt.AppendChild(xmlDoc.CreateElement("MyGrandChild"));
}
}
//lo guardo en un archivo
xmlDoc.Save(getFilePath("XmlDocumentTest.xml"));
txtLog.AppendText("XmlDocumentTest.xml Created\r\n");
}
private string getFilePath(string fileName)
{
return Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.Desktop), fileName);
}
Archivo Xml resultante:
<?xml version="1.0" encoding="utf-8"?>
<MyRoot>
<MyChild ID="1">
<MyGrandChild />
<MyGrandChild />
<MyGrandChild />
</MyChild>
<MyChild ID="2">
<MyGrandChild />
<MyGrandChild />
<MyGrandChild />
</MyChild>
<MyChild ID="3">
<MyGrandChild />
<MyGrandChild />
<MyGrandChild />
</MyChild>
<MyChild ID="4">
<MyGrandChild />
<MyGrandChild />
<MyGrandChild />
</MyChild>
</MyRoot>

Análisis de un XmlDocument utilizando DOM
Un XmlDocument se puede analizar mediante el uso de una rutina recursiva para recorrer todos sus elementos.

-----------------------------VB----------------------------------
Private Sub ParsingAnXmlDocumentToolStripMenuItem_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles ParsingAnXmlDocumentToolStripMenuItem.Click
Dim xmlDoc As New XmlDocument()
xmlDoc.Load(getFilePath("XmlDocumentTest.xml"))
RecurseNodes(xmlDoc.DocumentElement)
End Sub

Public Sub RecurseNodes(ByVal node As XmlNode)
Dim sb As New StringBuilder()
RecurseNodes(node, 0, sb)
txtLog.Text = sb.ToString()
End Sub

Public Sub RecurseNodes( _
ByVal node As XmlNode, ByVal level As Integer, _
ByVal sb As StringBuilder)
sb.AppendFormat("{0,2} Type:{1,-9} Name:{2,-13} Attr:", _
level, node.NodeType, node.Name)
For Each attr As XmlAttribute In node.Attributes
sb.AppendFormat("{0}={1} ", attr.Name, attr.Value)
Next
sb.AppendLine()
For Each n As XmlNode In node.ChildNodes
RecurseNodes(n, level + 1, sb)
Next
End Sub
-----------------------------CS---------------------------------- 
private void parsingAndXmlDocumentToolStripMenuItem_Click(object sender, EventArgs e)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(getFilePath("XmlDocumentTest.xml"));
RecurseNodes(xmlDoc.DocumentElement);
}
public void RecurseNodes(XmlNode node)
{
var sb = new StringBuilder();
//empiezo el loop en el nivel 0
RecurseNodes(node, 0, sb);
txtLog.Text = sb.ToString();
}
public void RecurseNodes(XmlNode node, int level, StringBuilder sb)
{
sb.AppendFormat("{0,2} Type:{1,-9} Name:{2,-13} Attr:",
level, node.NodeType, node.Name);
foreach (XmlAttribute attr in node.Attributes)
{
sb.AppendFormat("{0}={1} ", attr.Name, attr.Value);
}
sb.AppendLine();
foreach (XmlNode n in node.ChildNodes)
{
RecurseNodes(n, level + 1, sb);
}
}

Este código empieza cargando un archivo XML y después llama al método RecurseNodes, que está sobrecargado. La primera llamada simplemente pasa el nodo raíz xmlDoc. La llamada recursiva pasa el nivel de recursión y un objeto de cadena de constructor.

Resultado obtenido:
0 Type:Element Name:MyRoot Attr:
1 Type:Element Name:MyChild Attr:ID=1
2 Type:Element Name:MyGrandChild Attr:
2 Type:Element Name:MyGrandChild Attr:
2 Type:Element Name:MyGrandChild Attr:
1 Type:Element Name:MyChild Attr:ID=2
2 Type:Element Name:MyGrandChild Attr:
2 Type:Element Name:MyGrandChild Attr:
2 Type:Element Name:MyGrandChild Attr:
1 Type:Element Name:MyChild Attr:ID=3
2 Type:Element Name:MyGrandChild Attr:
2 Type:Element Name:MyGrandChild Attr:
2 Type:Element Name:MyGrandChild Attr:
1 Type:Element Name:MyChild Attr:ID=4
2 Type:Element Name:MyGrandChild Attr:
2 Type:Element Name:MyGrandChild Attr:
2 Type:Element Name:MyGrandChild Attr:

Búsqueda en el XmlDocument
El método SelectSingleNode puede buscar un elemento, este requiere una consulta XPath. El siguiente ejemplo llama al método SelectSingleNode para localizar el elemento MyChild con ID 3.
-----------------------------VB----------------------------------
Dim xmlDoc As New XmlDocument()
xmlDoc.Load(getFilePath("XmlDocumentTest.xml"))
Dim node = xmlDoc.SelectSingleNode("//MyChild[@ID='3']")
RecurseNodes(node)
-----------------------------CS---------------------------------- 
var xmlDoc = new XmlDocument();
xmlDoc.Load(getFilePath("XmlDocumentTest.xml"));
var node = xmlDoc.SelectSingleNode("//MyChild[@ID='3']");
RecurseNodes(node);

El resultado de la búsqueda seria:

0 Type:Element Name:MyChild Attr:ID=3
1 Type:Element Name:MyGrandChild Attr:
1 Type:Element Name:MyGrandChild Attr:
1 Type:Element Name:MyGrandChild Attr:

GetElementsByTagName

El método getElementsByTagName devuelve una lista de XmlNode contiene todos los elementos encontrados. El siguiente código devuelve una lista de nodos con el nombre de la etiqueta MyGrandChild.

-----------------------------VB----------------------------------
Dim elmts = xmlDoc.GetElementsByTagName("MyGrandChild")
-----------------------------CS---------------------------------- 
var elmts = xmlDoc.GetElementsByTagName("MyGrandChild");
 
SelectNodes
El método SelectNodes, requiere una consulta XPath y también puede recuperar una lista de XmlNode. El ejemplo de código anterior se ha modificado para llamar al método SelectNodes para lograr el mismo resultado:
-----------------------------VB---------------------------------- 
Dim elmts = xmlDoc.SelectNodes("//MyGrandChild")
-----------------------------CS---------------------------------- 
var elmts = xmlDoc.SelectNodes("//MyGrandChild");

La clase XmlReader
La clase XmlReader es una clase base abstracta que proporciona métodos para leer y analizar XML, sólo hacia delante, de acceso noncaching a una secuencia de datos XML.

Esta clase es ideal cuando la información deseada se encuentra en la parte superior del archivo XML y el archivo es grande. Si se necesita acceso al azar, se utiliza la clase XmlDocument.

-----------------------------VB----------------------------------
Dim sb As New StringBuilder()
Dim xmlReader As New _
XmlTextReader(getFilePath("XmlDocumentTest.xml"))

Do While xmlReader.Read()
Select Case xmlReader.NodeType
Case XmlNodeType.XmlDeclaration, _
XmlNodeType.Element, _
XmlNodeType.Comment
Dim s As String
sb.AppendFormat("{0}: {1} = {2}", _
xmlReader.NodeType, _
xmlReader.Name, _
xmlReader.Value)
sb.AppendLine()
Case XmlNodeType.Text
Dim s As String
sb.AppendFormat(" - Value: {0}", _
xmlReader.Value)
sb.AppendLine()
End Select
If xmlReader.HasAttributes Then

Do While xmlReader.MoveToNextAttribute()
sb.AppendFormat(" - Attribute: {0} = {1}", _
xmlReader.Name, xmlReader.Value)
sb.AppendLine()
Loop

End If

Loop
xmlReader.Close()
txtLog.Text = sb.ToString()
-----------------------------CS---------------------------------- 
var sb = new StringBuilder();
var xmlReader = new XmlTextReader(getFilePath("XmlDocumentTest.xml"));
while (xmlReader.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.XmlDeclaration:
case XmlNodeType.Element:
case XmlNodeType.Comment:
sb.AppendFormat("{0}: {1} = {2}",
xmlReader.NodeType,
xmlReader.Name,
xmlReader.Value);
sb.AppendLine();
break;
case XmlNodeType.Text:
sb.AppendFormat(" - Value: {0}", xmlReader.Value);
sb.AppendLine();
break;
}
if (xmlReader.HasAttributes)
{
while (xmlReader.MoveToNextAttribute())
{
sb.AppendFormat(" - Attribute: {0} = {1}",
xmlReader.Name,
xmlReader.Value);
sb.AppendLine();
}
}
}
xmlReader.Close();
txtLog.Text = sb.ToString();

Este código abre el archivo y luego realiza un ciclo simple, lee un elemento a la vez hasta que termine. Para cada nodo, se realiza una comprobación del NodeType, y la información del nodo se imprime.
XmlDeclaration: xml = version="1.0" encoding="utf-8"
- Attribute: version = 1.0
- Attribute: encoding = utf-8
Element: MyRoot =
Element: MyChild =
- Attribute: ID = 1
Element: MyGrandChild =
Element: MyGrandChild =
Element: MyGrandChild =
Element: MyChild =
- Attribute: ID = 2
Element: MyGrandChild =
Element: MyGrandChild =
Element: MyGrandChild =
Element: MyChild =
- Attribute: ID = 3
Element: MyGrandChild =
Element: MyGrandChild =
Element: MyGrandChild =
Element: MyChild =
- Attribute: ID = 4
Element: MyGrandChild =
Element: MyGrandChild =
Element: MyGrandChild =

Al ver los resultados, muchas líneas terminan con un signo igual porque ninguno de los nodos contenidos de texto.

Resumen de la lección
■ La clase XmlDocument proporciona en memoria, lectura-escritura de acceso aleatorio a los nodos XML.
■ La clase XmlReader proporciona un streaming, sólo hacia delante, de acceso de sólo lectura a los nodos XML.
■ La clase XmlDocument es más fácil de usar, mientras que la clase XmlReader es más rápido.
■ La clase XmlDocument permite recuperar los nodos XML utilizando el nombre del elemento.
■ La clase XmlDocument permite recuperar los nodos XML mediante una consulta XPath.

No hay comentarios:

Publicar un comentario