Leer y escribir documentos XML (C#)

www.altova.com Imprimir este apartado Página anterior Subir un nivel Página siguiente

Inicio >  Guía y referencia del usuario > Generador de código > Generar código fuente a partir de esquemas o DTD > Ejemplo: usar las bibliotecas contenedoras de esquemas >

Leer y escribir documentos XML (C#)

Tras generarse el código a partir del esquema de Library (véase Ejemplo de esquema), se crea una aplicación de prueba C# junto con varias bibliotecas Altova secundarias.

 

Información sobre las bibliotecas C# generadas

 

En este diagrama puede ver algunas de las clases más importantes del código generado.

 

csharp_class_diagram

 

La clase central del código generado es la clase Library2, que representa el documento XML. Dicha clase se genera por cada esquema y su nombre depende del nombre del archivo de esquema (en nuestro ejemplo es Library.xsd). Observe que esta clase se llama Library2 para evitar conflictos entre los nombres de espacio de nombres. Como puede verse en el diagrama, esta clase aporta métodos para cargar documentos desde archivos, secuencias binarias o cadenas de texto (o para guardar documentos en archivos, secuencias y cadenas). Para ver una descripción de esta clase consulte la referencia de la clase ([SuEsquema].[Doc]).

 

El miembro Library3 de la clase Library2 representa la raíz real del documento. De nuevo podemos observar que el número que aparece al final sirve para evitar conflictos entre los nombres de clase.

 

De acuerdo con las reglas de generación de código mencionadas en el apartado Bibliotecas contenedoras de esquemas (C#), se generan clases miembro por cada atributo y por cada elemento de un tipo. En el código generado el nombre de dichas clases miembros va precedido por el prefijo MemberAttribute_ y MemberElement_ respectivamente. En el diagrama anterior puede ver ejemplos de dichas clases: MemberAttribute_ID y MemberElement_Author, que se generan a partir del elemento Author y del atributo ID de un libro respectivamente. Dichas clases permiten manipular los correspondientes elementos y atributos del documento XML de instancia mediante programación (operaciones anexar, eliminar, establecer valor, etc.). Para más información consulte la referencia de las clases [SuTipoEsquema].MemberAttribute y [SuTipoEsquema].MemberElement.

 

Como en el esquema DictionaryType es un tipo complejo derivado de BookType, esta relación también se refleja en las clases generadas. Como puede verse en el diagrama, la clase DictionaryType hereda la clase BookType.

 

Si su esquema XML define tipos simples como enumeraciones, los valores enumerados están disponibles como valores Enum en el código generado. En el esquema utilizado en este ejemplo, el formato de los libros puede ser tapa dura, bolsillo, libro electrónico y audiolibro. Por tanto, en el código generado estos valores estarán disponibles a través de un Enum que es miembro de la clase BookFormatType.

 

Escribir un documento XML

 

1.En Visual Studio abra la solución LibraryTest.sln que se generó a partir del esquema Library mencionado anteriormente.

 

Cuando cree prototipos de aplicaciones a partir de esquemas XML que cambien con frecuencia, a veces será necesario generar código una y otra vez en el mismo directorio para que los cambios en el esquema se reflejen inmediatamente en el código. Recuerde que la aplicación de prueba que se genera y las bibliotecas de Altova se sobrescribirán cada vez que genere código en el mismo directorio de destino. Por tanto, recuerde que no debe añadir código a la aplicación de prueba que se genera, sino que debe integrar las bibliotecas de Altova en el proyecto (ver Integrar bibliotecas contenedoras de esquemas).

 

2.En el explorador de soluciones abra el archivo LibraryTest.cs y edite el método Example() como se indica a continuación:

 

      protected static void Example()
      {
          // Crear una biblioteca XML nueva
          Library2 doc = Library2.CreateDocument();
          // Anexar el elemento raíz
          LibraryType root = doc.Library3.Append();
 
          // Crear la fecha de generación de biblioteca con ayuda de la clase DateTime de Altova
          Altova.Types.DateTime dt = new Altova.Types.DateTime(System.DateTime.Now);
          // Anexar la fecha a la raíz
          root.LastUpdated.Value = dt;
 
          // Agregar un libro nuevo
          BookType book = root.Book.Append();
          // Establecer el valor del atributo ID
          book.ID.Value = 1;
          // Establecer el formato del libro (enumeración)
          book.Format.EnumerationValue = BookFormatType.EnumValues.eHardcover;
          // Establecer los elementos Title y Author
          book.Title.Append().Value = "The XMLSpy Handbook";
          book.Author.Append().Value = "Altova";
 
          // Anexar un diccionario (libro de tipo derivado) y rellenar sus atributos y elementos
          DictionaryType dictionary = new DictionaryType(root.Book.Append().Node);
          dictionary.ID.Value = 2;
          dictionary.Title.Append().Value = "English-German Dictionary";
          dictionary.Format.EnumerationValue = BookFormatType.EnumValues.eE_book;
          dictionary.Author.Append().Value = "John Doe";
          dictionary.FromLang.Append().Value = "English";
          dictionary.ToLang.Append().Value = "German";
          // Como es un tipo derivado, establecer el atributo xsi:type del elemento book
          dictionary.SetXsiType();
 
          // De forma opcional, establecer la ubicación del esquema (ajustar la ruta de acceso
          // si el esquema no está en la misma carpeta que el archivo de instancia que se generó)
          doc.SetSchemaLocation("Library.xsd");
 
          // Guardar el documento XML con la opción pretty print habilitada
          doc.SaveToFile("GeneratedLibrary.xml", true);
      }

 

3.Pulse F5 para iniciar la depuración. Si el código se ejecuta correctamente, el archivo GeneratedLibrary.xml se crea en el directorio de salida de la solución (que suele ser bin/Debug).

 

Leer un documento XML

 

1.Abra la solución LibraryTest.sln en Visual Studio.
2.Guarde el código que aparece a continuación en un archivo llamado Library.xml en el directorio de salida del proyecto (predeterminado: bin/Debug). Este es el archivo que leerá el código de programa.

 

<?xml version="1.0" encoding="utf-8"?>
<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.nanonull.com/LibrarySample" xsi:schemaLocation="http://www.nanonull.com/LibrarySample Library.xsd" LastUpdated="2016-02-03T17:10:08.4977404">  
  <Book ID="1" Format="E-book">
    <Title>The XMLSpy Handbook</Title>
    <Author>Altova</Author>    
  </Book>
  <Book ID="2" Format="Paperback" xmlns:n1="http://www.nanonull.com/LibrarySample" xsi:type="n1:DictionaryType">
    <Title>English-German Dictionary</Title>
    <Author>John Doe</Author>
    <FromLang>English</FromLang>
    <ToLang>German</ToLang>
  </Book>
</Library>

 

3.En el explorador de soluciones abra el archivo LibraryTest.cs y edite el método Example() como se indica a continuación:

 

      protected static void Example()
      {
          // Cargar el archivo XML en una instancia nueva de Library
          Library2 doc = Library2.LoadFromFile("Library.xml");
          // Obtener el elemento raíz
          LibraryType root = doc.Library3.First;
 
          // Leer la fecha de generación de Library
          Altova.Types.DateTime dt = root.LastUpdated.Value;
          string dt_as_string = dt.ToString(DateTimeFormat.W3_dateTime);
          Console.WriteLine("The library generation date is: " + dt_as_string);
 
          // Iteración: por cada <Book>...
          foreach (BookType book in root.Book)
          {
              // Valores de salida del atributo ID y del (primer y único) elemento title
              Console.WriteLine("ID:    " + book.ID.Value);
              Console.WriteLine("Title: " + book.Title.First.Value);
 
              // Leer y comparar un valor de enumeración
              if (book.Format.EnumerationValue == BookFormatType.EnumValues.ePaperback)
                  Console.WriteLine("This is a paperback book.");
 
              // Iteración: por cada <Author>
              foreach (xs.stringType author in book.Author)
                  Console.WriteLine("Author: " + author.Value);
 
              // Determinar si se trata de un libro de tipo derivado
              if (book.Node.Attributes.GetNamedItem("xsi:type") != null)
              {
                  // Buscar el valor del atributo xsi:type
                  string xsiTypeValue = book.Node.Attributes.GetNamedItem("xsi:type").Value;
                  // Obtener el URI de espacio de nombres

                   // y el prefijo de consulta de este espacio de nombres
                  string namespaceUri = book.Node.NamespaceURI;
                  string prefix = book.Node.GetPrefixOfNamespace(namespaceUri);
 
                  // si este libro tiene DictionaryType
                  if (namespaceUri == "http://www.nanonull.com/LibrarySample" && xsiTypeValue.Equals(prefix + ":DictionaryType"))
                  {
                      // generar campos adicionales
                      DictionaryType dictionary = new DictionaryType(book.Node);
                      Console.WriteLine("Language from: " + dictionary.FromLang.First.Value);
                      Console.WriteLine("Language to: " + dictionary.ToLang.First.Value);
                  }
                  else
                  {
                      throw new Exception("Unexpected book type");
                  }
              }
          }
 
          Console.ReadLine();
      }

 

4.Pulse F5 para iniciar la depuración. Si el código se ejecuta correctamente, el código de programa leerá el archivo GeneratedLibrary.xml y su contenido aparecerá en el resultado de la consola.

 

Leer y escribir elementos y atributos

 

El acceso a los atributos y elementos se consigue con la propiedad Value de la clase de elemento o atributo miembro que se genera. Por ejemplo:

 

// Valores de salida del atributo ID y del (primer y único) elemento title

Console.WriteLine("ID:    " + book.ID.Value);

Console.WriteLine("Title: " + book.Title.First.Value);

 

Para obtener el valor del elemento Title en este ejemplo concreto también se utilizó el método First(). Esto se debe a que este es el primer (y único) elemento Title de un libro. Cuando necesite seleccionar un elemento concreto de una lista por medio del índice, utilice el método At().

 

La clase que se genera por cada elemento miembro de un tipo implementa la interfaz estándar System.Collections.IEnumerable. Esto permite recorrer varios elementos del mismo tipo. En este ejemplo concreto puede recorrer todos los libros de un objeto Library como se puede ver a continuación:

 

// Iteración: por cada <Book>...

foreach (BookType book in root.Book)

{

  // introduzca aquí su código...                                        

}

 

Para agregar un elemento nuevo utilice el método Append(). Por ejemplo, a continuación se anexa el elemento raíz al documento:

 

// Anexar el elemento raíz a la biblioteca

LibraryType root = doc.Library3.Append();

 

Puede establecer el valor de un atributo (como ID) de la siguiente manera:

 

// Establecer el valor del atributo ID

book.ID.Value = 1;

 

Para más información consulte la referencia de las clases [SuTipoEsquema].MemberAttribute y [SuTipoEsquema].MemberElement.

 

Leer y escribir valores de enumeración

 

Si el esquema XML define tipos simples como enumeraciones, los valores enumerados estarán disponibles como valores Enum en el código generado. En el esquema utilizado en este ejemplo el formato de un libro puede ser tapa dura, bolsillo, libro electrónico y audiolibro. Por tanto, en el código generado estos valores estarán disponibles a través de una Enum:

ex_class_BookFormatType

Para asignar valores de enumeración a un objeto utilice código como este:

 

// Establecer el formato del libro (enumeración)

book.Format.EnumerationValue = BookFormatType.EnumValues.eHardcover;

 

Puede leer dichos valores de enumeración desde documento XML de instancia de la siguiente manera:

 

// Leer y comparar un valor de enumeración

if (book.Format.EnumerationValue == BookFormatType.EnumValues.ePaperback)

Console.WriteLine("This is a paperback book.");

 

Cuando la condición IF no sea suficiente, cree un modificador para determinar cada valor de enumeración y procesarlos según corresponda en cada caso.

 

Trabajar con tipos xs:dateTime y xs:duration

 

Si el esquema desde el que se genera código utiliza tipos de hora y duración como xs:dateTime o xs:duration, estos tipos se convierten en clases nativas de Altova en el código generado. Por tanto, para escribir un valor de fecha o duración en el documento XML debe seguir estas instrucciones:

 

1.Construya un objeto Altova.Types.DateTime o Altova.Types.Duration (bien desde System.DateTime o utilizando partes como horas y minutos como en Altova.Types.DateTime y Altova.Types.Duration).
2.Establezca el objeto como valor del elemento o atributo que necesita. Por ejemplo:

 

// Crear la fecha de generación de la biblioteca usando la clase DateTime de Altova

Altova.Types.DateTime dt = new Altova.Types.DateTime(System.DateTime.Now);

// Anexar la fecha a la raíz

root.LastUpdated.Value = dt;

 

Para leer una fecha o duración de un documento XML:

 

1.Declare el valor de elemento (o atributo) como objeto Altova.Types.DateTime o Altova.Types.Duration.
2.Aplique formato al elemento o atributo que necesita. Por ejemplo:

 

// Leer la fecha de generación de la biblioteca

Altova.Types.DateTime dt = root.LastUpdated.Value;

string dt_as_string = dt.ToString(DateTimeFormat.W3_dateTime);

Console.WriteLine("The library generation date is: " + dt_as_string);

 

Para más información consulte la referencia de las clases Altova.Types.DateTime y Altova.Types.Duration.

 

Trabajar con tipos derivados

 

Si su esquema XML define tipos derivados puede conservar la derivación de tipos en los documentos XML que cree o cargue mediante programación. Tomando el esquema utilizado en este ejemplo, el fragmento de código que aparece a continuación explica cómo se crea un libro nuevo de tipo derivado DictionaryType:

 

// Anexar un diccionario (libro de tipo derivado) y rellenar sus atributos y elementos

DictionaryType dictionary = new DictionaryType(root.Book.Append().Node);

dictionary.ID.Value = 2;

dictionary.Title.Append().Value = "English-German Dictionary";

dictionary.Author.Append().Value = "John Doe";

dictionary.FromLanguage.Append().Value = "English";

dictionary.ToLanguage.Append().Value = "German";

 

// Como es un tipo derivado, asegúrese de establecer el atributo xsi:type del elemento book

dictionary.SetXsiType();

 

Recuerde que es importante establecer el atributo xsi:type del libro recién creado. Esto garantiza que el esquema interprete correctamente el tipo de libro a la hora de validar el documento XML.

 

El fragmento de código que aparece a continuación identifica un libro de tipo derivado DictionaryType en la instancia XML que se carga. Primero se busca el valor del atributo xsi:type del nodo book. Si el URI de espacio de nombres de este nodo es http://www.nanonull.com/LibrarySample y el prefijo de consulta URI y el tipo coinciden con el valor del atributo xsi:type, entonces sabemos que se trata de un diccionario.

 

    // Determinar si este libro es de tipo derivado
    if (book.Node.Attributes.GetNamedItem("xsi:type") != null)
    {
        // Buscar el valor del atributo xsi:type
        string xsiTypeValue = book.Node.Attributes.GetNamedItem("xsi:type").Value;
        // Obtener el URI de espacio de nombres y el prefijo de consulta de este espacio de nombres
        string namespaceUri = book.Node.NamespaceURI;
        string prefix = book.Node.GetPrefixOfNamespace(namespaceUri);
 
        // Si este libro tiene DictionaryType
        if (namespaceUri == "http://www.nanonull.com/LibrarySample" && xsiTypeValue.Equals(prefix + ":DictionaryType"))
        {
            // generar campos adicionales
            DictionaryType dictionary = new DictionaryType(book.Node);
            Console.WriteLine("Language from: " + dictionary.FromLang.First.Value);
            Console.WriteLine("Language to: " + dictionary.ToLang.First.Value);
        }
        else
        {
            throw new Exception("Unexpected book type");
        }
    }


© 2019 Altova GmbH