Clase System.Xml.XmlReader

En este artículo se proporcionan comentarios adicionales a la documentación de referencia de esta API.

XmlReader proporciona acceso de solo avance y de solo lectura a los datos XML de un documento o secuencia. Esta clase se ajusta a las recomendaciones de W3C para el lenguaje de marcado extensible XML 1.0 (cuarta edición) y los espacios de nombres en XML 1.0 (tercera edición).

Los métodos de XmlReader le permiten desplazarse por los datos XML y leer el contenido de un nodo. Las propiedades de la clase reflejan el valor del nodo actual, que es donde se coloca el lector. El valor de la propiedad ReadState indica el estado actual del lector XML. Por ejemplo, la propiedad se establece en ReadState.Initial por el método XmlReader.Read y ReadState.Closed por el método XmlReader.Close. XmlReader también proporciona comprobaciones de conformidad de datos y validación en un DTD o un esquema.

XmlReader usa un modelo de extracción para recuperar datos. Este modelo:

  • Simplifica la administración del estado mediante un refinamiento de procedimientos natural y descendente.
  • Admite varios flujos de entrada y capas.
  • Permite al cliente proporcionar al analizador un búfer en el que se escribe directamente la cadena y, por tanto, evita la necesidad de una copia de cadena adicional.
  • Admite el procesamiento selectivo. El cliente puede omitir elementos y procesar los que son de interés para la aplicación. También puede establecer propiedades de antemano para administrar cómo se procesa la secuencia XML (por ejemplo, normalización).

Creación de un lector XML

Use el método Create para crear una instancia de XmlReader.

Aunque .NET proporciona implementaciones concretas de la clase XmlReader, como las clases XmlTextReader, XmlNodeReader y XmlValidatingReader, le recomendamos que use las clases especializadas solo en estos escenarios:

  • Cuando quiera leer un subárbol XML DOM de un objeto XmlNode, use la clase XmlNodeReader. (Sin embargo, esta clase no admite DTD ni validación de esquemas).
  • Si debe expandir entidades a petición, no desea que el contenido de texto se normalice o no quiere que se devuelvan atributos predeterminados, use la clase XmlTextReader.

Para especificar el conjunto de características que desea habilitar en el lector XML, pase un objeto System.Xml.XmlReaderSettings al método Create. Puede usar un solo objeto System.Xml.XmlReaderSettings para crear varios lectores con la misma funcionalidad o modificar el objeto System.Xml.XmlReaderSettings para crear un nuevo lector con un conjunto diferente de características. También puede agregar fácilmente características a un lector existente.

Si no usa un objeto System.Xml.XmlReaderSettings, se usa la configuración predeterminada. Consulte la página de referencia de Create para más información.

XmlReader genera un XmlException en los errores de análisis XML. Después de iniciar una excepción, el estado del lector no es predecible. Por ejemplo, el tipo de nodo notificado puede ser diferente del tipo de nodo real del nodo actual. Use la propiedad ReadState para comprobar si el lector está en estado de error.

Validación de datos XML

Para definir la estructura de un documento XML, así como las relaciones de sus elementos, tipos de datos y restricciones de contenido, se utiliza una definición de tipo de documento (DTD) o esquema del lenguaje de definición de esquemas (XSD). Se considera que un documento XML está bien formado si cumple todos los requisitos sintácticos definidos por la Recomendación XML 1.0 del W3C. Se considera válido si está bien formado y también se ajusta a las restricciones definidas por su DTD o esquema. (Consulte las recomendaciones de Esquema XML de W3C, parte 1: Estructuras y Esquema XML de W3C, parte 2: Tipos de datos). Por lo tanto, aunque todos los documentos XML válidos sean correctos, no todos los documentos XML correctos son válidos.

Puede validar los datos con respecto a un DTD, un esquema XSD en línea o un esquema XSD almacenado en un objeto XmlSchemaSet (una caché); estos escenarios se describen en la página de referencia de Create. XmlReader no admite la validación del esquema XML-Data Reduced (XDR).

Use la siguiente configuración en la clase XmlReaderSettings para especificar qué tipo de validación admite la instancia de XmlReader.

Usar este miembro de XmlReaderSettings Para especificar
PropiedadDtdProcessing Indica si se va a permitir el procesamiento de DTD. El valor predeterminado es no permitir el procesamiento de DTD.
PropiedadValidationType Si el lector debe validar los datos y qué tipo de validación se va a realizar (DTD o esquema). El valor predeterminado es que no hay validación de datos.
EventoValidationEventHandler Un controlador de eventos para recibir información sobre eventos de validación. Si no se proporciona un controlador de eventos, se inicia una XmlException en el primer error de validación.
PropiedadValidationFlags Opciones de validación adicionales a través de los miembros de enumeración XmlSchemaValidationFlags:

- AllowXmlAttributes-- Permitir atributos XML (xml:*) en documentos de instancia incluso cuando no están definidos en el esquema. Los atributos se validan basándose en su tipo de datos. Consulte la página de referencia de XmlSchemaValidationFlags para ver la configuración que se va a usar en escenarios específicos. (Deshabilitado de forma predeterminada).
- ProcessIdentityConstraints --Procesar las restricciones de identidad (xs:ID, xs:IDREF, xs:key, xs:keyref, xs:unique) encontradas durante la validación. (Habilitado de forma predeterminada).
- ProcessSchemaLocation --Procesar esquemas especificados por el atributo xsi:schemaLocation o xsi:noNamespaceSchemaLocation. (Habilitado de forma predeterminada).
- ProcessInlineSchema-- Procesar esquemas XML insertados durante la validación. (Deshabilitado de forma predeterminada).
- ReportValidationWarnings--Notificar eventos si se produce una advertencia de validación. Normalmente se produce una advertencia cuando no hay ninguna DTD ni esquema XML para validar un elemento o atributo en particular. ValidationEventHandler se utiliza para las notificaciones. (Deshabilitado de forma predeterminada).
Schemas XmlSchemaSet que se va a usar para validación.
PropiedadXmlResolver XmlResolver para resolver y acceder a recursos externos. Esto puede incluir entidades externas como DTD y esquemas, así como cualquier elemento xs:include o xs:import contenido en el esquema XML. Si no especifica un XmlResolver, XmlReader usa un XmlUrlResolver predeterminado sin credenciales de usuario.

Cumplimiento en datos

Los lectores XML creados por el método Create cumplen los siguientes requisitos de cumplimiento de forma predeterminada:

  • Las nuevas líneas y el valor de los atributos se normalizan de acuerdo con la Recomendación XML 1.0 del W3C.

  • Todas las entidades se expanden automáticamente.

  • Los atributos predeterminados declarados en la definición de tipo de documento siempre se agregan incluso cuando el lector no se valida.

  • Se permite la declaración del prefijo XML asignado al URI de espacio de nombres XML correcto.

  • Los nombres de notación de una sola declaración de atributo NotationType y NmTokens en una sola declaración de atributo Enumeration son distintos.

Use estas propiedades XmlReaderSettings para especificar el tipo de comprobaciones de conformidad que desea habilitar:

Use esta propiedad XmlReaderSettings En Valor predeterminado
PropiedadCheckCharacters Habilite o deshabilite las comprobaciones siguientes:

- Los caracteres están dentro del intervalo de caracteres XML legales, tal como se define en la sección 2.2 Caracteres de la Recomendación XML 1.0 del W3C.
- Todos los nombres XML son válidos, tal como se define en la sección 2.3 Construcciones sintácticas comunes de la Recomendación XML 1.0 del W3C.

Cuando esta propiedad se establece en true (valor predeterminado), se produce una excepción de XmlException si el archivo XML contiene caracteres no válidos o nombres XML no válidos (por ejemplo, un nombre de elemento comienza con un número).
La comprobación de caracteres y nombres está habilitada.

Al establecer CheckCharacters en false se desactiva la comprobación de caracteres para las referencias de entidad de caracteres. Si el lector está procesando datos de texto, siempre comprueba que los nombres XML son válidos, independientemente de esta configuración. Nota: La recomendación XML 1.0 requiere conformidad de nivel de documento cuando hay una DTD presente. Por lo tanto, si el lector está configurado para admitir ConformanceLevel.Fragment, pero los datos XML contienen una definición de tipo de documento (DTD), se produce un XmlException.
PropiedadConformanceLevel Elija el nivel de conformidad para aplicar:

- Document. Se ajusta a las normas de un documento XML 1.0 bien formado.
- Fragment. Se ajusta a las normas para un fragmento de documento bien formado que puede consumirse como una entidad externa analizada.
- Auto. Se ajusta al nivel decidido por el lector.

Si los datos no son conformes, se produce una excepción de XmlException.
Document

El nodo actual es el nodo XML en el que está colocado actualmente el lector XML. Todos los métodos XmlReader realizan operaciones en relación con este nodo y todas las propiedades XmlReader reflejan el valor del nodo actual.

Los siguientes métodos facilitan la navegación por los nodos y el análisis de los datos.

Usar este método de XmlReaderSettings En
Read Lea el primer nodo y avance por la secuencia de nodo en nodo. Estas llamadas normalmente se realizan dentro de un bucle while.

Use la propiedad NodeType para obtener el tipo (por ejemplo, atributo, comentario, elemento, etc.) del nodo actual.
Skip Omita los elementos secundarios del nodo actual y muévalo al siguiente nodo.
MoveToContent y MoveToContentAsync Omita los nodos que no son de contenido y pase al siguiente nodo de contenido o al final del archivo.

Los nodos que no son de contenido incluyen ProcessingInstruction, DocumentType, Comment, Whitespace y SignificantWhitespace.

Los nodos de contenido incluyen texto sin espacios en blanco, CDATA, EntityReference y EndEntity.
ReadSubtree Lea un elemento y todos sus elementos secundarios y devuelva una nueva instancia de XmlReader establecida en ReadState.Initial.

Este método es útil para crear límites alrededor de elementos XML. Por ejemplo, si desea pasar datos a otro componente para su procesamiento y desea limitar la cantidad de datos a los que puede acceder el componente.

Consulte la página de referencia de XmlReader.Read para ver un ejemplo de navegación por una secuencia de texto de un nodo a la vez y mostrar el tipo de cada nodo.

En las secciones siguientes se describe cómo leer tipos específicos de datos, como elementos, atributos y datos con tipo.

Leer elementos XML

En la tabla siguiente se enumeran los métodos y propiedades que proporciona la clase XmlReader para procesar elementos. Después de que XmlReader se sitúe en un elemento, las propiedades del nodo como, por ejemplo, Name, reflejan los valores del elemento. Además de los miembros que se describen a continuación, también se puede utilizar cualquiera de los métodos y propiedades generales de la clase XmlReader para procesar elementos. Por ejemplo, puede utilizar el método ReadInnerXml para leer el contenido de un elemento.

Nota:

Consulte la sección 3.1 de la Recomendación XML 1.0 del W3C para las definiciones de etiquetas de inicio, etiquetas de fin y etiquetas de elementos vacíos.

Usar este miembro de XmlReader En
Método IsStartElement Compruebe si el nodo actual es una etiqueta de inicio o una etiqueta de elemento vacía.
Método ReadStartElement Compruebe que el nodo actual es un elemento y avance el lector al siguiente nodo (llama a IsStartElement seguido de Read).
Método ReadEndElement Compruebe que el nodo actual es una etiqueta final y avance el lector al siguiente nodo.
Método ReadElementString Lea un elemento de solo texto.
Método ReadToDescendant Avance el lector XML al siguiente elemento descendiente (secundario) que tiene el nombre especificado.
Método ReadToNextSibling Avance el lector XML al siguiente elemento relacionado que tiene el nombre especificado.
PropiedadIsEmptyElement Compruebe si el elemento actual tiene una etiqueta de elemento final. Por ejemplo:

- <item num="123"/> (IsEmptyElement es true).
- <item num="123"> </item> (IsEmptyElement es false, aunque el contenido del elemento está vacío).

Para obtener un ejemplo de lectura del contenido de texto de los elementos, vea el método ReadString. En el ejemplo siguiente se procesan los elementos mediante un bucle while.

while (reader.Read()) {
  if (reader.IsStartElement()) {
    if (reader.IsEmptyElement)
                {
                    Console.WriteLine("<{0}/>", reader.Name);
                }
                else {
      Console.Write("<{0}> ", reader.Name);
      reader.Read(); // Read the start tag.
      if (reader.IsStartElement())  // Handle nested elements.
        Console.Write("\r\n<{0}>", reader.Name);
      Console.WriteLine(reader.ReadString());  //Read the text content of the element.
    }
  }
}
While reader.Read()
  If reader.IsStartElement() Then
    If reader.IsEmptyElement Then
      Console.WriteLine("<{0}/>", reader.Name)
    Else
      Console.Write("<{0}> ", reader.Name)
      reader.Read() ' Read the start tag.
      If reader.IsStartElement() Then ' Handle nested elements.
        Console.Write(vbCr + vbLf + "<{0}>", reader.Name)
      End If
      Console.WriteLine(reader.ReadString()) 'Read the text content of the element.
    End If
  End If
End While

Leer atributos XML

Los atributos XML se encuentran con más frecuencia en los elementos, pero también se permiten en los nodos de declaración XML y tipo de documento.

Cuando se coloca en un nodo de elemento, el método MoveToAttribute le permite recorrer la lista de atributos del elemento. Tenga en cuenta que después de llamar a MoveToAttribute, propiedades de nodo como Name, NamespaceURI y Prefix reflejan las propiedades de ese atributo, no las propiedades del elemento al que pertenece el atributo.

La clase XmlReader proporciona estos métodos y propiedades para leer y procesar atributos en elementos.

Usar este miembro de XmlReader En
PropiedadHasAttributes Compruebe si el nodo actual tiene atributos.
PropiedadAttributeCount Obtenga el número de atributos en el elemento actual.
Método MoveToFirstAttribute Vaya al primer atributo de un elemento.
Método MoveToNextAttribute Vaya al siguiente atributo de un elemento.
Método MoveToAttribute Vaya a un atributo especificado.
Método GetAttribute o propiedad Item[] Obtenga el valor de un atributo especificado.
PropiedadIsDefault Compruebe si el nodo actual es un atributo generado a partir del valor predeterminado definido en la DTD o el esquema.
Método MoveToElement Vaya al elemento que posee el atributo actual. Use este método para volver a un elemento después de navegar por sus atributos.
Método ReadAttributeValue Analice el valor del atributo en uno o varios nodos Text, EntityReference o EndEntity.

También se puede utilizar cualquiera de las propiedades y los métodos XmlReader generales para procesar atributos. Por ejemplo, después de situar XmlReader en un atributo, las propiedades Name y Value reflejan los valores del atributo. También puede utilizar cualquiera de los métodos Read de contenido para obtener el valor del atributo.

En este ejemplo se usa la propiedad AttributeCount para navegar por todos los atributos de un elemento.

// Display all attributes.
if (reader.HasAttributes) {
  Console.WriteLine("Attributes of <" + reader.Name + ">");
  for (int i = 0; i < reader.AttributeCount; i++) {
    Console.WriteLine("  {0}", reader[i]);
  }
  // Move the reader back to the element node.
  reader.MoveToElement();
}
' Display all attributes.
If reader.HasAttributes Then
  Console.WriteLine("Attributes of <" + reader.Name + ">")
  Dim i As Integer
  For i = 0 To (reader.AttributeCount - 1)
    Console.WriteLine("  {0}", reader(i))
  Next i
  ' Move the reader back to the element node.
  reader.MoveToElement() 
End If

En este ejemplo se usa el método MoveToNextAttribute en un bucle while para navegar por los atributos.

if (reader.HasAttributes) {
  Console.WriteLine("Attributes of <" + reader.Name + ">");
  while (reader.MoveToNextAttribute()) {
    Console.WriteLine(" {0}={1}", reader.Name, reader.Value);
  }
  // Move the reader back to the element node.
  reader.MoveToElement();
}
If reader.HasAttributes Then
  Console.WriteLine("Attributes of <" + reader.Name + ">")
  While reader.MoveToNextAttribute()
    Console.WriteLine(" {0}={1}", reader.Name, reader.Value)
  End While
  ' Move the reader back to the element node.
  reader.MoveToElement()
End If

Lectura de atributos en nodos de declaración XML

Cuando el lector XML se coloca en un nodo de declaración XML, la propiedad Value devuelve la información de versión, independiente y codificación como una sola cadena. Los objetos XmlReader creados por el método Create, la clase XmlTextReader y la clase XmlValidatingReader exponen los elementos de versión, independiente y codificación como atributos.

Lectura de atributos en nodos de tipo de documento

Cuando el lector XML se sitúa en un nodo de tipo documento, el método GetAttribute y la propiedad Item[] pueden usarse para usar los valores de los literales SYSTEM y PUBLIC. Por ejemplo, al llamar a reader.GetAttribute("PUBLIC"), se devuelve el valor PUBLIC.

Lectura de atributos en nodos de instrucción de procesamiento

Cuando XmlReader está situado en un nodo de instrucción de procesamiento, la propiedad Value devuelve el contenido de texto completo. Los elementos del nodo de instrucción de procesamiento no se tratan como atributos. No se pueden leer con el método GetAttribute o MoveToAttribute.

Leer contenido XML

La clase XmlReader incluye los siguientes miembros que leen contenido de un archivo XML y devuelven el contenido como valores de cadena. (Para devolver tipos CLR, consulte Convertir a tipos CLR).

Usar este miembro de XmlReader En
PropiedadValue Obtenga el contenido de texto del nodo actual. El valor devuelto depende del tipo de nodo; consulte la página de referencia de Value para más información.
Método ReadString Obtiene el contenido de un elemento o nodo de texto como una cadena. Este método se detiene en el procesamiento de instrucciones y comentarios.

Para más información sobre cómo este método controla tipos de nodo específicos, consulte la página de referencia de ReadString.
Métodos ReadInnerXml y ReadInnerXmlAsync Obtenga todo el contenido del nodo actual, incluido el marcado, pero sin incluir etiquetas de inicio y finalización. Por ejemplo, para:

<node>this<child id="123"/></node>

ReadInnerXml devuelve lo siguiente:

this<child id="123"/>
Métodos ReadOuterXml y ReadOuterXmlAsync Obtenga todo el contenido del nodo actual y sus elementos secundarios, incluidas las etiquetas de marcado y inicio y finalización. Por ejemplo, para:

<node>this<child id="123"/></node>

ReadOuterXml devuelve lo siguiente:

<node>this<child id="123"/></node>

Conversión a tipos CLR

Puede usar los miembros de la clase XmlReader (enumerada en la tabla siguiente) para leer datos XML y devolver valores como tipos de Common Language Runtime (CLR) en lugar de cadenas. Estos miembros le permiten obtener valores en la representación más adecuada para la tarea de codificación sin tener que analizar ni convertir manualmente valores de cadena.

  • Los métodos ReadElementContentAs solo se pueden llamar en tipos de nodo de elemento. Estos métodos no se pueden utilizar en elementos que contienen elementos segundarios o incluyen contenido mixto. Al llamar al objeto XmlReader, éste lee la etiqueta de inicio y el contenido del elemento y, a continuación, se mueve después de la etiqueta del elemento de fin. Las instrucciones de procesamiento y los comentarios se omiten y las entidades se expanden.

  • Los métodos ReadContentAs leen el contenido del texto en la posición actual del lector y, si los datos XML no tienen ninguna información de esquema o tipo de datos asociada, convierten el contenido del texto al tipo de valor devuelto solicitado. El texto, el espacio en blanco, el espacio en blanco significativo y las secciones CDATA se concatenan. Los comentarios y las instrucciones de procesamiento se omiten y las referencias de entidad se resuelven automáticamente.

La clase de XmlReader usa las reglas definidas por la recomendación de Esquema XML del W3C, parte 2: Tipos de datos.

Usar este método de XmlReader Para devolver este tipo CLR
ReadContentAsBoolean y ReadElementContentAsBoolean Boolean
ReadContentAsDateTime y ReadElementContentAsDateTime DateTime
ReadContentAsDouble y ReadElementContentAsDouble Double
ReadContentAsLong y ReadElementContentAsLong Int64
ReadContentAsInt y ReadElementContentAsInt Int32
ReadContentAsString y ReadElementContentAsString String
ReadContentAs y ReadElementContentAs Tipo que especifique con el parámetro returnType
ReadContentAsObject y ReadElementContentAsObject Tipo más adecuado, tal como se especifica en la propiedad XmlReader.ValueType. Consulte Compatibilidad de tipos en las clases System.Xml para obtener información sobre la asignación.

Si un elemento no se puede convertir fácilmente a un tipo CLR debido a su formato, puede usar una asignación de esquema para garantizar una conversión correcta. En el ejemplo siguiente se usa un archivo .xsd para convertir el elemento hire-date al tipo xs:date y, a continuación, se usa el método ReadElementContentAsDateTime para devolver el elemento como un objeto DateTime.

Entrada (hireDate.xml):

<employee xmlns="urn:empl-hire">
    <ID>12365</ID>
    <hire-date>2003-01-08</hire-date>
    <title>Accountant</title>
</employee>

Esquema (hireDate.xsd):

<?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="urn:empl-hire" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="employee">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="ID" type="xs:unsignedShort" />
        <xs:element name="hire-date" type="xs:date" />
        <xs:element name="title" type="xs:string" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Código:

// Create a validating XmlReader object. The schema
// provides the necessary type information.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas.Add("urn:empl-hire", "hireDate.xsd");
using (XmlReader reader = XmlReader.Create("hireDate.xml", settings)) {

  // Move to the hire-date element.
  reader.MoveToContent();
  reader.ReadToDescendant("hire-date");

  // Return the hire-date as a DateTime object.
  DateTime hireDate = reader.ReadElementContentAsDateTime();
  Console.WriteLine("Six Month Review Date: {0}", hireDate.AddMonths(6));
}
' Create a validating XmlReader object. The schema 
' provides the necessary type information.
Dim settings As XmlReaderSettings = New XmlReaderSettings()
settings.ValidationType = ValidationType.Schema
settings.Schemas.Add("urn:empl-hire", "hireDate.xsd")
Using reader As XmlReader = XmlReader.Create("hireDate.xml", settings) 
  ' Move to the hire-date element.
  reader.MoveToContent()
  reader.ReadToDescendant("hire-date")

  ' Return the hire-date as a DateTime object.
  Dim hireDate As DateTime = reader.ReadElementContentAsDateTime()
  Console.WriteLine("Six Month Review Date: {0}", hireDate.AddMonths(6))
End Using

Salida:

Six Month Review Date:  7/8/2003 12:00:00 AM

Programación asincrónica

La mayoría de los métodos XmlReader tienen homólogos asincrónicos que tienen "Async" al final de sus nombres de método. Por ejemplo, el equivalente asincrónico de ReadContentAsObject es ReadContentAsObjectAsync.

Los métodos siguientes se pueden usar con llamadas de método asincrónicas:

En las secciones siguientes se describe el uso asincrónico de los métodos que no tienen homólogos asincrónicos.

Método ReadStartElement

public static async Task ReadStartElementAsync(this XmlReader reader, string localname, string ns)
{
    if (await reader.MoveToContentAsync() != XmlNodeType.Element)
    {
        throw new InvalidOperationException(reader.NodeType.ToString() + " is an invalid XmlNodeType");
    }
    if ((reader.LocalName == localname) && (reader.NamespaceURI == ns))
    {
        await reader.ReadAsync();
    }
    else
    {
        throw new InvalidOperationException("localName or namespace doesn’t match");
    }
}
<Extension()>
Public Async Function ReadStartElementAsync(reader As XmlReader, localname As String, ns As String) As Task
    If (Await reader.MoveToContentAsync() <> XmlNodeType.Element) Then
        Throw New InvalidOperationException(reader.NodeType.ToString() + " is an invalid XmlNodeType")
    End If

    If ((reader.LocalName = localname) And (reader.NamespaceURI = ns)) Then
        Await reader.ReadAsync()
    Else
        Throw New InvalidOperationException("localName or namespace doesn’t match")
    End If
End Function

Método ReadEndElement

public static async Task ReadEndElementAsync(this XmlReader reader)
{
    if (await reader.MoveToContentAsync() != XmlNodeType.EndElement)
    {
        throw new InvalidOperationException();
    }
    await reader.ReadAsync();
}
<Extension()>
Public Async Function ReadEndElementAsync(reader As XmlReader) As task
    If (Await reader.MoveToContentAsync() <> XmlNodeType.EndElement) Then
        Throw New InvalidOperationException()
    End If
    Await reader.ReadAsync()
End Function

Método ReadToNextSibling

public static async Task<bool> ReadToNextSiblingAsync(this XmlReader reader, string localName, string namespaceURI)
{
    if (localName == null || localName.Length == 0)
    {
        throw new ArgumentException("localName is empty or null");
    }
    if (namespaceURI == null)
    {
        throw new ArgumentNullException("namespaceURI");
    }

    // atomize local name and namespace
    localName = reader.NameTable.Add(localName);
    namespaceURI = reader.NameTable.Add(namespaceURI);

    // find the next sibling
    XmlNodeType nt;
    do
    {
        await reader.SkipAsync();
        if (reader.ReadState != ReadState.Interactive)
            break;
        nt = reader.NodeType;
        if (nt == XmlNodeType.Element &&
             ((object)localName == (object)reader.LocalName) &&
             ((object)namespaceURI ==(object)reader.NamespaceURI))
        {
            return true;
        }
    } while (nt != XmlNodeType.EndElement && !reader.EOF);
    
    return false;
}
<Extension()>
Public Async Function ReadToNextSiblingAsync(reader As XmlReader, localName As String, namespaceURI As String) As Task(Of Boolean)
    If (localName = Nothing Or localName.Length = 0) Then
        Throw New ArgumentException("localName is empty or null")
    End If

    If (namespaceURI = Nothing) Then
        Throw New ArgumentNullException("namespaceURI")
    End If

    ' atomize local name and namespace
    localName = reader.NameTable.Add(localName)
    namespaceURI = reader.NameTable.Add(namespaceURI)

    ' find the next sibling
    Dim nt As XmlNodeType
    Do

        Await reader.SkipAsync()
        If (reader.ReadState <> ReadState.Interactive) Then
            Exit Do
        End If
        nt = reader.NodeType
        If ((nt = XmlNodeType.Element) And
           ((CObj(localName) = CObj(reader.LocalName))) And
           (CObj(namespaceURI) = CObj(reader.NamespaceURI))) Then
            Return True
        End If
    Loop While (nt <> XmlNodeType.EndElement And (Not reader.EOF))

    Return False

End Function

Método ReadToFollowing

public static async Task<bool> ReadToFollowingAsync(this XmlReader reader, string localName, string namespaceURI)
{
    if (localName == null || localName.Length == 0)
    {
        throw new ArgumentException("localName is empty or null");
    }
    if (namespaceURI == null)
    {
        throw new ArgumentNullException("namespaceURI");
    }

    // atomize local name and namespace
    localName = reader.NameTable.Add(localName);
    namespaceURI = reader.NameTable.Add(namespaceURI);

    // find element with that name
    while (await reader.ReadAsync())
    {
        if (reader.NodeType == XmlNodeType.Element && ((object)localName == (object)reader.LocalName) && ((object)namespaceURI == (object)reader.NamespaceURI))
        {
            return true;
        }
    }
    return false;
}
<Extension()>
Public Async Function ReadToFollowingAsync(reader As XmlReader, localName As String, namespaceURI As String) As Task(Of Boolean)
    If (localName = Nothing Or localName.Length = 0) Then
        Throw New ArgumentException("localName is empty or null")
    End If

    If (namespaceURI = Nothing) Then
        Throw New ArgumentNullException("namespaceURI")
    End If

    ' atomize local name and namespace
    localName = reader.NameTable.Add(localName)
    namespaceURI = reader.NameTable.Add(namespaceURI)

    ' find element with that name
    While (Await reader.ReadAsync())
        If ((reader.NodeType = XmlNodeType.Element) And
           (CObj(localName) = CObj(reader.LocalName)) And
           (CObj(namespaceURI) = CObj(reader.NamespaceURI))) Then
            Return True
        End If
    End While

    Return False
End Function

Método ReadToDescendant

public static async Task<bool> ReadToDescendantAsync(this XmlReader reader, string localName, string namespaceURI)
{
    if (localName == null || localName.Length == 0)
    {
        throw new ArgumentException("localName is empty or null");
    }
    if (namespaceURI == null)
    {
        throw new ArgumentNullException("namespaceURI");
    }
    // save the element or root depth
    int parentDepth = reader.Depth;
    if (reader.NodeType != XmlNodeType.Element)
    {
        // adjust the depth if we are on root node
        if (reader.ReadState == ReadState.Initial)
        {
            parentDepth--;
        }
        else
        {
            return false;
        }
    }
    else if (reader.IsEmptyElement)
    {
        return false;
    }

    // atomize local name and namespace
    localName = reader.NameTable.Add(localName);
    namespaceURI = reader.NameTable.Add(namespaceURI);

    // find the descendant
    while (await reader.ReadAsync() && reader.Depth > parentDepth)
    {
        if (reader.NodeType == XmlNodeType.Element && ((object)localName == (object)reader.LocalName) && ((object)namespaceURI == (object)reader.NamespaceURI))
        {
            return true;
        }
    }
    return false;
}
<Extension()>
Public Async Function ReadToDescendantAsync(reader As XmlReader, localName As String, namespaceURI As String) As Task(Of Boolean)
    If (localName = Nothing Or localName.Length = 0) Then
        Throw New ArgumentException("localName is empty or null")
    End If

    If (namespaceURI = Nothing) Then
        Throw New ArgumentNullException("namespaceURI")
    End If

    ' save the element or root depth
    Dim parentDepth As Integer = reader.Depth
    If (reader.NodeType <> XmlNodeType.Element) Then
        ' adjust the depth if we are on root node
        If (reader.ReadState = ReadState.Initial) Then
            parentDepth -= 1
        Else
            Return False
        End If
    ElseIf (reader.IsEmptyElement) Then
        Return False
    End If
    ' atomize local name and namespace
    localName = reader.NameTable.Add(localName)
    namespaceURI = reader.NameTable.Add(namespaceURI)

    ' find the descendant
    While (Await reader.ReadAsync() And reader.Depth > parentDepth)
        If (reader.NodeType = XmlNodeType.Element And
           (CObj(localName) = CObj(reader.LocalName)) And
           (CObj(namespaceURI) = CObj(reader.NamespaceURI))) Then
            Return True
        End If
    End While

    Return False
End Function

Consideraciones sobre la seguridad

Tenga en cuenta lo siguiente al trabajar con la clase XmlReader :

  • Las excepciones producidas por el XmlReader pueden revelar información sobre la ruta de acceso que quizá no quiera que aparezca en su aplicación. La aplicación debe detectar excepciones y procesarlas correctamente.

  • No habilite el procesamiento de DTD si le preocupan los problemas de denegación de servicio o si trabaja con orígenes que no son de confianza. El procesamiento de DTD está deshabilitado de forma predeterminada para objetos XmlReader creados por el método Create.

    Si tiene habilitado el procesamiento de DTD, puede utilizar XmlSecureResolver para restringir los recursos a los que tiene acceso XmlReader. También puede diseñar su aplicación para que el procesamiento XML se realice con restricciones de memoria y tiempo. Por ejemplo, puede configurar límites de tiempo de espera en la aplicación ASP.NET.

  • Los datos XML pueden incluir referencias a recursos externos como, por ejemplo, un archivo de esquemas. De manera predeterminada, los recursos externos se resuelven utilizando un objeto XmlUrlResolver sin credenciales de usuario. Puede aumentar la protección aún más realizando cualquiera de las siguientes acciones:

  • Las marcas de validación ProcessInlineSchema y ProcessSchemaLocation de un objeto XmlReaderSettings no están establecidos de manera predeterminada. Esto ayuda a proteger el XmlReader contra ataques basados en esquemas cuando está procesando datos XML de un origen que no es de confianza. Cuando se establecen estas marcas, se utiliza el XmlResolver del objeto XmlReaderSettings para resolver las ubicaciones de esquemas que se encuentra en el documento de la instancia de XmlReader. Si la propiedad XmlResolver está establecida en null, las ubicaciones de esquema no se resuelven incluso si se establecen las marcas de validación de ProcessInlineSchema y ProcessSchemaLocation.

    Los esquemas agregados durante la validación agregan nuevos tipos y pueden cambiar el resultado de la validación del documento. Como consecuencia, los esquemas externos solo se deberían resolver desde orígenes de confianza.

    Se recomienda deshabilitar la marca ProcessIdentityConstraints al validar documentos XML de gran tamaño en escenarios de alta disponibilidad en un esquema que tenga restricciones de identidad en una gran parte del documento. Esta marca está habilitada de forma predeterminada.

  • Los datos XML pueden contener un gran número de atributos, declaraciones de espacios de nombres, elementos anidados, etc. cuyo procesamiento tarda una cantidad de tiempo importante. Para limitar el tamaño de la entrada que se envía al XmlReader, puede:

  • El método ReadValueChunk se puede usar para controlar grandes flujos de datos. Este método lee una pequeña cantidad de caracteres a la vez en lugar de asignar una única cadena para todo el valor.

  • Al leer un documento XML con numerosos nombres locales, espacios de nombres o prefijos únicos, puede producirse un problema. Si está utilizando una clase que se deriva de XmlReader, y llama a la propiedad LocalName, Prefix o NamespaceURI para cada elemento, la cadena devuelta se agrega a NameTable. La colección contenida por NameTable nunca disminuye de tamaño, creando una pérdida de memoria virtual de los identificadores de cadena. Una mitigación para esto es derivar de la clase NameTable y aplicar una cuota de tamaño máximo. (No hay ninguna manera de evitar el uso de un NameTable o cambiar el NameTable cuando está lleno). Otra solución es evitar el uso de las propiedades mencionadas y utilizar en su lugar el método MoveToAttribute con el método IsStartElement cuando sea posible; estos métodos no devuelven cadenas y, por tanto, evitan el problema de llenar demasiado la colección NameTable.

  • Los objetos XmlReaderSettings pueden contener información confidencial como, por ejemplo, credenciales de usuario. Un componente que no sea de confianza podría utilizar el objeto XmlReaderSettings y sus credenciales de usuario para crear objetos XmlReader para leer datos. Tenga cuidado al almacenar en caché objetos XmlReaderSettings o al pasar el objeto XmlReaderSettings de un componente a otro.

  • No admita componentes como, por ejemplo, objetos NameTable, XmlNamespaceManager y XmlResolver, de un origen que no sea de confianza.