Mostrando entradas con la etiqueta Chapter 6. Mostrar todas las entradas
Mostrando entradas con la etiqueta Chapter 6. Mostrar todas las entradas

jueves, 3 de diciembre de 2015

Receta C# No. 6-3: Inserción Rápida de Nodos en un Documento XML

Índice

1. Introducción
2. Palabras Clave
3. Problema
4. Solución
5. Discusión de la Solución
5.1 Clase ayudante AyudanteXml
5.2 Clonación de un nodo
6. Práctica: Código C#
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

Esta nueva receta C# enseña cómo el programador puede insertar nodos en un documento XML de forma más ágil. En la receta anterior se demostró cómo insertar un nodo usando los métodos directos que provee la clase XmlDocument; en esta oportunidad se muestra a través de una clase ayudante cómo realizar el mismo proceso escribiendo menos código sin dejar a un lado su legibilidad. Además, en breve, se demuestra cómo a través del mecanismo de clonación se puede efectuar una inserción rápida con un número inferior de líneas de código respecto al enfoque de la receta C# No. 6.2.

2. Palabras Clave

  • Atributo
  • Clase ayudante
  • Clonación
  • Documento XML
  • Elemento
  • Nodo
  • XML

3. Problema

Se requiere un enfoque programático más ágil para la inserción de nodos en un documento XML.

4. Solución

La solución consiste en la creación de una clase ayudante que contiene los métodos de agregación de un elemento y un atributo. (Una solución alternativa consiste en la clonación de un nodo existe, alterar sus valores, y agregarlo al documento XML usando los étodos de la clase XmlDocument).

5. Discusión de la Solución

5.1 Clase ayudante AyudanteHelper

En la receta Receta C# No. 6-2: Inserción de Nodos en un Documento XML se mostró cómo insertar elementos -nodos y atributos- en un documento XML usando dos de los métodos disponibles en la clase XmlDocument ("XmlDocument Class", 2015) -CreateElement y CreateAttribute-. A pesar de la abstracción que soporta el diseño de la clase XmlDocument para estas tareas, se puede optar aún por la escritura de una clase ayudante que simplifique los procesos de inserción de nodos y atributos de forma más ágil y sencilla.

Continuando, la clase AyudanteHelper que se diseña en la sección de práctica cuenta con métodos de alto nivel para soportar el requerimiento:
  • InsertarElemento y 
  • InsertarAtributo
Esta clase será usada por la clase cliente InsercionAgilNodos.

5.2 Clonación de un nodo

La clase XmlNode ("XmlNode Class", 2015) cuenta con el método CloneNode ("XmlNode.CloneNode Method", 2015) para crear una copia de un nodo. El parámetro de este método permite especificar si se copia el contenido anidado o no; para ello es necesario especificar true o false como argumento:

// Creación de un nuevo elemento a partir de uno existente:
producto = producto.CloneNode(true);

// Modificación de los valores del nodo recién clonado:
producto.Attributes[0].Value = "10002";
producto.ChildNodes[0].ChildNodes[0].Value = "Cappuccino";
producto.ChildNodes[1].ChildNodes[0].Value = "9500";

// Agrega el nuevo elemento:
productos.AppendChild(producto);

6. Práctica: Código C#

En primer lugar se escribe la clase AyudanteXml:

En las líneas 9-26 se especifica el método static AgregarElemento con los parámetros:
  • nodoPadre: referencia al nodo padre sobre el que se creará/agregará el nuevo nodo.
  • nombreEtiqueta: nombre para el nuevo nodo.
  • contenido: contenido textual para un nodo anidado al recién creado. (Opcional).
Más adelante -líneas 29-38-, se crea el método static AgregarAtributo para agregar un nuevo atributo al documento XML. Estos son sus parámetros:
  • nodoPadre: referencia al nodo padre sobre el que se creará el nuevo atributo.
  • nombreAtributo: nombre para el nuevo atributo.
  • contenido: contenido textual para el atributo recién creado.
Compilación:

csc /t:library AyudanteXml.cs

Las líneas de interés de este archivo son:
  • Líneas 22-25: crea un primer elemento y añade otros nodos y atributos usando los métodos AyudanteXml.AgregarElemento y AyudanteXml.AgregarAtributo. Estos operaciones se realizan para crear el producto con ID 10001.
  • Líneas 27-30: de manera análoga al caso anterior, estas líneas crean un producto con ID 10002.
Compilación: 

csc /t:exe /r:AyudanteXml.dll \InsercionAgilNodos.cs

Ejecución assembly:

.\InsercionAgilNodos.exe
Ejecución assembly InsercionAgilNodos.exe
Figura 1. Ejecución assembly InsercionAgilNodos.exe.

7. Conclusiones

Se comprendió el proceso de creación de una clase ayudante para agilizar el proceso de agregación de nodos y atributos a un documento XML. Es notable la diferencia respecto a la receta C# anterior: en este caso solo se requirió invocar los métodos de la clase ayudante en cuestión para especificar datos del nuevo elemento/atributo a crear en el documento XML. En la próxima receta C# se demostrará cómo buscar elementos en un documento XML a través de su nombre.

8. Literatura & Enlaces

Jones, A., Freeman (2010). Visual C# 2010 Recipes: A Problem-Solution Approach. United States: Apress.
Receta C# No. 6-2: Inserción de Nodos en un Documento XML (2015, diciembre 3). Recuperado desde: http://ortizol.blogspot.com/2015/11/receta-csharp-no-6-2-insercion-de-nodos-en-un-documento-xml.html.
XmlDocument Class (System.Xml) (2015, diciembre 29). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.xml.xmldocument(v=vs.110).aspx.
XmlNode Class (System.Xml) (2015, diciembre 29). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.xml.xmlnode(v=vs.110).aspx.
XmlNode.CloneNode Method (Boolean) (System.Xml) (2015, diciembre 3). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.xml.xmlnode.clonenode(v=vs.110).aspx.


V

miércoles, 2 de diciembre de 2015

Cadenas de Caracteres y Manipulación de Texto en C# - Parte 4/5: Clase StringBuilder

Índice

1. Introducción
2. Palabras Clave
3. La Clase StringBuilder
4. StringBuilder vs. String
5. Asignación de Memoria en StringBuilder
6. Otros Métodos de StringBuilder
7. Aspectos Importantes de StringBuilder
8. Conclusiones
9. Literatura & Enlaces

1. Introducción

En artículos anteriores de la serie Cadenas de Caracteres y Manipulación de Texto en C# se ha expuesto los métodos de manipulación de cadenas de caracteres inmutables: objeto que representa una cadena de caracteres que no cambia durante el tiempo de ejecución. En esta parte se discute los objetos opuestos a los anteriores, es decir las cadenas de caracteres mutables. Esto se logra a través del uso de la clase System.Text.StringBuilder. Se estudia de este modo los mecanismos propios de esta clase para manipular cadenas de caracteres de forma más eficiente respecto a String.

2. Palabras Clave

  • Buffer
  • Cadena de caracteres
  • CLR
  • Eficiencia
  • Inmutabilidad
  • Memoria
  • Mutabilidad
  • Stack

3. La Clase StringBuilder


La clase StringBuilder ("StringBuilder Class", 2015) (namespace System.Text) está diseñada para representar cadenas de caracteres mutables, es decir que su contenido se puede editar (Albahari, 2012). Esta clase cuenta con 6 constructores que permiten inicializar un objeto con diferentes parámetros: capacidad, cuota de crecimiento, entre otros.
Constructores StringBuilder
Tabla 1. Constructores StringBuilder ("StringBuilder", 2015).
Suponiendo que se inicia un objeto de esta clase con la capacidad predeterminada -16 caracteres-, a medida que se añada más contenido -caracteres- al objeto StringBuilder, de forma automática se redimensiona su estructura interna para soportar la nueva demanda de capacidad ("StringBuilder Class", 2015). Este proceso de redimensionamiento demanda un coste bajo cómputo; e inclusive cuando alcanza su capacidad máxima. Esta capacidad máxima está determinada por el valor máximo de Int32.MaxValue ("Int32.MaxValue Field", 2015): 2.147.483.647 bytes.

4. StringBuilder vs. String

La clase String posee la misma característica de los tipos primitivos (o integrados): inmutabilidad. Suponiendo que se tiene la expresión

"Blog" + " xCSw"

con se esto se crea una nueva cadena -"BlogxCSw"- en la memoria stack de la CRL. La cuenta de objetos en la estructura stack sería de 2. Mientras que con StringBuilder:

// La variable blog hace referencia al objeto StringBuilder con la cadena "Blog":
StringBuilder nombreCompleto = new StringBuilder("John");

Hasta este punto en la stack existe un objeto en memoria. Continuando:

// Proceso de 'adición' de cadenas
nombreCompleto.Append(" xCSw");

A pesar de la adición de la nueva cadena -"xCSw"- en la estructura stack se mantiene el mismo número de objetos: 1.

Esta es una de las principales diferencias entre estos dos tipos de datos: el almacenamiento. Es evidente que StringBuilder es más eficiente respecto a este requerimiento; y lo es más aún cuando se trata de almacenar cadenas de longitud superiores.

5. Asignación de Memoria en StringBuilder

A través del siguiente ejemplo se puede visualizar cómo un objeto StringBuilder adapta su capacidad de almacenamiento de acuerdo al tamaño o número caracteres que se adicionan a lo largo de la ejecución del programa.

En las líneas 26-36 -método InformacionObjetoStringBuilder- se obtiene a través de reflection ("Receta No. 3-14 en C#", 2015) las propiedades de interés del objeto StringBuider. Para este caso:
  • Capacity
  • MaxCapacity y 
  • Length
El texto inicial del objeto StringBuilder es "Es esta es una frase." -línea 46-. Luego en el ciclo for -líneas 51-55- se invoca hasta 11 veces el método Append para adicionar la cadena "Texto adicional." ese mismo número de veces al objeto objSB. En ese mismo ciclo se invoca al método InformacionObjetoStringBuilder para consultar el estado de las tres propiedades mencionadas.

Al ejecutar este assembly se obtiene en la salida estándar (http://ideone.com/v7AJV4):

MaxCapacity: 2,147,483,647     Capacity: 16     Length: 0     
MaxCapacity: 2,147,483,647     Capacity: 21     Length: 21     
MaxCapacity: 2,147,483,647     Capacity: 42     Length: 37     
MaxCapacity: 2,147,483,647     Capacity: 84     Length: 53     
MaxCapacity: 2,147,483,647     Capacity: 84     Length: 69     
MaxCapacity: 2,147,483,647     Capacity: 168     Length: 85     
MaxCapacity: 2,147,483,647     Capacity: 168     Length: 101     
MaxCapacity: 2,147,483,647     Capacity: 168     Length: 117     
MaxCapacity: 2,147,483,647     Capacity: 168     Length: 133     
MaxCapacity: 2,147,483,647     Capacity: 168     Length: 149     
MaxCapacity: 2,147,483,647     Capacity: 168     Length: 165     
MaxCapacity: 2,147,483,647     Capacity: 336     Length: 181     
MaxCapacity: 2,147,483,647     Capacity: 336     Length: 197

En la primera parte -MaxCapacity- se muestra la capacidad máxima soportada por el objeto StringBuilder: Int32.MaxValue. Enseguida, la capacidad actual del objeto en la propiedad Capacity. Finalmente, con Length el tamaño actual de la cadena de caracteres localizada en el objeto StringBuilder -objSB-.

6. Otros Métodos de StringBuilder

Además del método Append, la clase StringBuilder cuenta con AppendLine ("StringBuilder.AppendLine", 2015") para adicionar una nueva línea de texto:

StringBuilder sb = new StringBuilder("Blog xCSw");
sb.AppendLine();

Por otra parte, con el método AppendFormat ("StringBuilder.AppendFormat", 2015) se adiciona una cadena de caracteres con formato:

StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0} {1}", "Blog", "xCSw");

Existen otros métodos para manipular la cadena de caracteres que representa un objeto StringBuilder; entre esos métodos se puede contar:
  • Insert: para insertar valores de tipos de datos en una posición de la cadena de caracteres de StringBuilder.
  • Remove: para remover una rango de caracteres.
  • Replace: Reemplaza las ocurrencias de un carácter o una cadena de caracteres en la cadena de caracteres de StringBuilder.

7. Aspectos Importantes de StringBuilder

Otras consideraciones importantes a la hora de usar objetos de la clase StringBuilder (Albahari, 2012):
  • Al establecer la propiedad Capacity con una capacidad inferior a la de Length, la primera lanza la excepción: System.ArgumentOutOfRangeException.
  • La capacidad máxima de un objeto StringBuilder alcanza los 2 gigabytes.
  • Si se estable un valor inferior a la longitud actual -propiedad Length- de la cadena en el objeto StringBuilder, entonces su contenido es truncado al nuevo valor inferior al actual.
  • Al establecer un valor superior al de la propiedad Length, el buffer llena esos espacios vacíos con caracteres de espacio.

8. Conclusiones

Se ha estudiado la clase StringBuilder para entender cómo se pueden construir cadenas de caracteres mutables. Gracias a esta propiedad, el programador puede manipular texto en cualquiera de los lenguajes compatibles con la CLR. La amplia capacidad de StringBuilder -2GB- además de resultar apta para textos grandes es mucho más eficiente que la manipulación de cadenas de caracteres con String. En el próximo, y último, artículo de la serie Cadenas de Caracteres y Manipulación de Texto en C# se estudiará codificación de texto.

9. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.
StringBuilder Class (System.Text) (2015, diciembre 2). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.text.stringbuilder(v=vs.110).aspx.
Int32.MaxValue Field (System) (2015, diciembre 2). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.int32.maxvalue(v=vs.110).aspx.
Receta No. 3-14 en C#: Investigar los Atributos de un Elemento de Programa con Reflection (2015, diciembre 2). Recuperado desde: http://ortizol.blogspot.com/2014/06/receta-no-3-14-en-csharp-investigar-los-atributos-de-un-elemento-de-program-con-reflection.html.
StringBuilder.AppendLine Method (System.Text) (2015, diciembre 2). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.text.stringbuilder.appendline(v=vs.110).aspx.
StringBuilder.AppendFormat Method (System.Text) (2015, diciembre 2). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.text.stringbuilder.appendformat(v=vs.110).aspx.


V

lunes, 30 de noviembre de 2015

Cadenas de Caracteres y Manipulación de Texto en C# - Parte 3/5: Comparación de Cadenas de Caracteres

Índice

1. Introducción
2. Palabras Clave
3. Comparación de Valores en .NET
3.1 Comparación semántica
3.2 Comparación ordinal
3.3 Modos de comparación
3.4 Comparación de cadenas de caracteres
3.5 Comparación de cadenas de caracteres por orden
4. Compración Ordinal vs. Comparación Cultural de Cadenas de Caracteres
5. Comparación Semántica de Cadenas de Caracteres
6. Comparación Ordinal de cadenas d ecaracteres
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

En esta tercera parte de la serie Manipulación de Texto y Cadenas de Caracteres en C#, se estudia los métodos de comparación de cadenas de caracteres: comparación semántica y comparación ordinal. Estos métodos de comparación son de inmensa utilidad a la hora de construir nuevos tipos de datos para nuestros proyectos de ingeniería de software, o usar los definidos en las bibliotecas nativas de .NET Framework o desarrolladas por terceros, las cuales requieran un granulado sistema de comparación e igualdad. En especial se estudian los siguientes temas esenciales: comparación cultural vs comparación ordinal, comparación semántica de cadenas de caracteres y comparación ordinal de cadenas de caracteres.

2. Palabras Clave

  • Cadenas de caracteres
  • Comparación
  • Comparación ordinal
  • Comparación semántica
  • Cultura
  • Igualdad

3. Comparación de Valores en .NET

En Microsoft .NET se distingue entre la comparación semántica y la comparación ordinal (Albahari, 2012).

3.1 Comparación semántica

La comparación semántica -también conocida como comparación de igualdad- se caracteriza por determinar o validar si dos instancias son a nivel semántico iguales, es decir, si sus valores tienen el mismo significado en un determinado contexto (Albahari, 2012).

3.2 Comparación ordinal

Por su parte, la comparación ordinal consiste en comparar dos instancias respecto al orden natural de su tipo de dato. En el caso de números enteros la comparación ordinal consiste en determinar cuál es menor -descendencia-, cuál es mayor -ascendencia- o si los valores iguales.

3.3 Modos de comparación

Hay que tener en cuenta que estos modos de comparación son totalmente independientes y ninguno de ellos es una subcategoría del otro. Esto se advierte en Albahari (2012) de la siguiente manera:
"It's legal, for instance, to have two unequal values in the same ordering position."
Esto quiere decir que dos valores distintos pueden ocupar un misma posición de orden. Se puede pensar en este caso en agrupaciones o jerarquías de valores, por ejemplo.

3.4 Comparación de cadenas de caracteres

Para la comparación de cadenas de caracteres, el cual es tema principal de esta serie de artículos, el programador puede usar las siguientes dos alternativas:
  • el operador == o 
  • el método static Equals de la clase String
Para comparaciones básicas basta con el uso del operador ==, pero para comparaciones más granulares o especializadas, es preferible recurrir a la última opción: el método Equals. Con esto último el programador puede especificar opciones para no distinguir entre minúsculas y mayúsculas; algo que no se puede lograr con el operador nativo ==.

En Albahari (2012) se hace la siguiente advertencia:
"Another difference is that == does not work reliably on strings if the variables are cast to the object type."
En resumen, el operador de igualdad, ==, no es apto para comparar cadenas de caracteres convertidas al tipo de dato base object.

3.5 Comparación de cadenas de caracteres por orden

En .NET Framework el desarrollador encontrará los métodos de instancia: 
  • CompareTo
  • Compare, y 
  • CompareOrdinal
para efectuar una comparación ordinal entre instancias. Estos métodos se caracterizan por su tipo de retorno: que consiste en un número entero que determina su posición en una jerarquía de orden -ascendente o descendente-.

4. Comparación Ordinal vs. Comparación Cultural de Cadenas de Caracteres

.NET Framework cuenta con dos algoritmos de comparación de cadenas de caracteres (Albahari, 2012)
  • Ordinal y  
  • Cultural-sensitivo
Estos dos algoritmos de comparación de cadenas de caracteres se diferencian en que el primero, el ordinal, lleva a cabo las comparaciones de forma numérica. Esta comparación considera el valor numérico asignado en el juego de caracteres Unicode; mientras que el segundo, cultural-sensitivo, las comparaciones se interpretan de acuerdo a un alfabeto de una cultura específica (Albahari, 2012)

Vale advertir que respecto al método de comparación cultural-sensitivo existen estas dos variantes:
  • cultura actual: basada en la configuración regional del sistema actual donde se ejecuta la aplicación, y 
  • cultura no-variante: basada en el sistema americano.
Con un ejemplo se puede ampliar estos conceptos; en particular para diferenciar los algoritmos de comparación de cadenas caracteres. El siguiente programa en código fuente C# compara a nivel ordinal las cadenas de caracteres chsarp, CSharp y FSharp:

Al ejecutar este programa se obtienen los siguientes resultados -http://ideone.com/I5uOxy-:


Comparación independiente de la cultura:
einstein
Einstein
Newton

Comparación ordinal:
Einstein
Newton
einstein

Nótese que los resultados de la comparación de las cadenas "Einstein""einstein" y "Newton" con el uso StringComparer.InvariantCulture sigue el orden alfabético primeros letras minúsculas (a-z) y luego mayúsculas (A-Z); mientras que al especificar StringComparer.Ordinal para la comparación ordinal, el orden está basado en A...Z, a...z.

5. Comparación Semántica de Cadenas de Caracteres

La comparación semántica o de igualdad de cadenas de caracteres se puede llevar a cabo con los métodos 

public static bool Equals(string a, string b, StringComparison comparisonType)




public bool Equals(string value, StringComparison comparisonType)


Estos métodos están definidos en la clase String. El parámetro común de ambos métodos, StringComparison, es una enumeración con los siguientes miembros ("StringComparison Enumeration", 2015):
Miembros de StringComparison
Tabla 1. Miembros de StringComparison ("StringComparison Enumeration", 2015).

Con estos miembros de esta enumeración se especifica el modo de comparación del contenido de cadenas de caracteres.

Ejemplo de uso:

Archivo C# ComparacionSemantica.cs [Enlace alternativo][Enlace alternativo]:

Los resultados de ejecución de este código son:


¿Iguales EINSTEIN y Einstein?: True

¿Iguales Ṻ y Ǖ?: False

¿Iguales Ṻ y Ǖ?: True


La primera evaluación -línea 9- compara los valores de las cadenas de caracteres "EINSTEIN" y "Einstein" sin considerar si son o no mayúsculas; lo que da como resultado true. En el caso de la comparación ¿Iguales Ṻ y Ǖ? -línea 12- con el operador == su resultado es false debido a que son dos cadenas distintas -dos valores Unicode distintos: \u1E7A y \u01D5-.



Para el caso de ejemplo final -línea 15-, el resultado es dependiente de la configuración local de la computadora donde ejecuta el assembly.

6. Comparación Ordinal de Cadenas de Caracteres

En la clase System.String se halla el método CompareTo que cuenta con las siguientes versiones sobrecargadas ("String.CompareTo", 2015):
Método sobrecargado CompareTo
Tabla 2. Método sobrecargado CompareTo ("String.CompareTo", 2015).
Con este método de instancia se determina si una cadena de precede, procede o mantiene la misma posición en un orden específico a otra cadena de caracteres. El valor entero retornado determina su orden:
  • En caso de ser menor que cero: la instancia actual precede a otra cadena de caracteres.
  • En caso de ser igual a cero: la instancia mantiene la misma posición de orden.
  • En caso de ser mayor que cero: la instancia procede a otra cadena de caracteres.
Por ejemplo:

string cadena1 = "ani\u00ADmal";
string cadena2 = "animal";

Console.WriteLine (cadena1.CompareTo(cadena2)); // 0

Existen, además, los métodos Compare y CompareOrdinal para otros tipos de comparación. (Estos tipos de comparación se explorarán en otros artículos o recetas C#.)

7. Conclusiones

Se ha estudiado los métodos de comparación de cadenas de caracteres: semántico y ordinal. La distinción conceptual y práctica de éstos dos permite al programador conocer el conjunto de elementos de programa disponibles en .NET Framework para la comparación del contenido y orden de cadenas de caracteres. Se demostró, además, que la comparación se puede efectuar con dependencia o independencia de la configuración regional del sistema de cómputo donde se ejecuta un determinado programa que compara cadenas de caracteres. El próximo artículo de esta serie explicará la construcción de cadenas de caracteres a partir de la clase StringBuilder; en especial la propiedad de mutabilidad.

8. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.
StringComparison Enumeration (System) (2015, noviembre 30). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.stringcomparison(v=vs.110).aspx.
String.CompareTo Method (System) (2015, noviembre 30). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.string.compareto(v=vs.110).aspx.


V