Classe System.Xml.XmlReader

Este artigo fornece observações complementares à documentação de referência para essa API.

XmlReader fornece acesso somente encaminhamento e somente leitura a dados XML em um documento ou fluxo. Essa classe se adequa às recomendações de Linguagem XML 1.0 (quarta edição) e de Namespaces em XML 1.0 (terceira edição) do W3C.

Os métodos XmlReader permitem que você transite entre os dados XML e leia o conteúdo de um nó. As propriedades da classe refletem o valor do nó atual, que é onde o leitor está posicionado. O valor da propriedade ReadState indica o estado atual do leitor XML. Por exemplo, a propriedade é definida como ReadState.Initial pelo método XmlReader.Read e ReadState.Closed pelo método XmlReader.Close. XmlReader também fornece verificações de conformidade de dados e validação em relação a uma DTD ou esquema.

XmlReader usa um modelo de pull para recuperar dados. Este modelo:

  • Simplifica o gerenciamento de estado por um refinamento de procedimento natural de cima para baixo.
  • Suporta vários fluxos de entrada e camadas.
  • Permite que o cliente forneça ao analisador um buffer no qual a cadeia de caracteres é gravada diretamente e, assim, evita a necessidade de uma cópia de cadeia de caracteres adicional.
  • Suporta o processamento seletivo. O cliente pode ignorar itens e processar aqueles que são de interesse para o aplicativo. Você também pode definir propriedades com antecedência para gerenciar como o fluxo XML é processado (por exemplo, normalização).

Criar um leitor de XML

Use o método Create para criar uma instância XmlReader.

Embora o .NET forneça implementações concretas da classe XmlReader, como as classes XmlTextReader, XmlNodeReader e XmlValidatingReader, recomendamos que você use as classes especializadas somente nestes cenários:

  • Quando você deseja ler uma subárvore DOM XML de um objeto XmlNode, use a classe XmlNodeReader. (No entanto, essa classe não oferece suporte à DTD ou validação de esquema.)
  • Se você precisar expandir entidades sob solicitação, e não quiser que seu conteúdo de texto seja normalizado ou que os atributos padrão sejam retornados, use a classe XmlTextReader.

Para especificar o conjunto de recursos que você deseja habilitar no leitor de XML, passe um objeto System.Xml.XmlReaderSettings para o método Create. Você pode usar um único objeto System.Xml.XmlReaderSettings para criar vários leitores com a mesma funcionalidade ou modificar o objeto System.Xml.XmlReaderSettings para criar um novo leitor com um conjunto diferente de recursos. Você também pode adicionar facilmente recursos a um leitor existente.

Se você não usar um objeto System.Xml.XmlReaderSettings, as configurações padrão serão usadas. Para obter detalhes, consulte a página de referência Create.

XmlReader gera um XmlException em erros de análise de XML. Depois que uma exceção é gerada, o estado do leitor não é previsível. Por exemplo, o tipo de nó informado pode ser diferente do tipo de nó real do nó atual. Use a propriedade ReadState para verificar se o leitor está em estado de erro.

Validar dados XML

Para definir a estrutura de um documento XML e os relacionamentos de seus elementos, tipos de dados e restrições de conteúdo, você usa uma DTD (definição de tipo de documento) ou um esquema XSD (linguagem de definição de esquema XML). Um documento XML é considerado bem formado se atender a todos os requisitos sintáticos definidos pela Recomendação XML 1.0 do W3C. Ele é considerado válido se estiver bem formado e também estiver em conformidade com as restrições definidas por sua DTD ou esquema. (Consulte as recomendações Parte 1 do Esquema XML do W3C: estruturas e Parte 2 do Esquema XML do W3C: tipos de dados.) Portanto, embora todos os documentos XML válidos sejam bem-formados, nem todos os documentos XML bem-formados são válidos.

Você pode validar os dados em relação a uma DTD, um esquema XSD embutido ou um esquema XSD armazenado em um objeto XmlSchemaSet (um cache), esses cenários são descritos na página de referência Create. XmlReader não oferece suporte à validação de esquema XDR (XML – reduzido a dados).

Use as configurações a seguir na classe XmlReaderSettings para especificar que tipo de validação, se houver, a instância XmlReader suporta.

Use este membro XmlReaderSettings Para especificar
Propriedade DtdProcessing Se permitir o processamento de DTD. O padrão é não permitir o processamento de DTD.
Propriedade ValidationType Se o leitor deve validar os dados e que tipo de validação executar (DTD ou esquema). A opção não é possível validação de dados.
Evento ValidationEventHandler Um manipulador de eventos para receber informações sobre eventos de validação. Se um manipulador de eventos não for fornecido, XmlException será apresentada no primeiro erro de validação.
Propriedade ValidationFlags Opções de validação adicionais por meio dos membros de enumeração XmlSchemaValidationFlags:

- AllowXmlAttributes-Permite atributos XML (xml:*) em documentos de instância, mesmo quando eles não estiverem definidos no esquema. Os atributos são validados com base no tipo de dados. Consulte a página de referência XmlSchemaValidationFlags para a configuração a ser usada em cenários específicos. (Desabilitado por padrão.)
- - restrições de identidade de processo (ProcessIdentityConstraints, xs:ID, xs:IDREF, xs:key, xs:keyref) encontrados durante a validação. (Habilitado por padrão.)
- ProcessSchemaLocation – Esquemas de processo especificados pelo atributo xsi:schemaLocation ou xsi:noNamespaceSchemaLocation. (Habilitado por padrão.)
- ProcessInlineSchema– Processe embutido esquemas XML durante a validação. (Desabilitado por padrão.)
- ReportValidationWarnings– Relatar eventos se ocorrer um aviso de validação. Um aviso é emitida normalmente quando não há nenhum DTD ou esquema XML para validar um elemento ou atributo específico contra. ValidationEventHandler é usado para notificação. (Desabilitado por padrão.)
Schemas O XmlSchemaSet a ser usado para validação.
Propriedade XmlResolver O XmlResolver para resolver e acessar recursos externos. Isso pode incluir entidades externas, como o DTD e esquemas e qualquer xs:include ou xs:import elementos contidos no esquema XML. Se você não especificar um XmlResolver, o XmlReader usa um padrão XmlUrlResolver sem credenciais do usuário.

Compatibilidade de dados

Os leitores XML que são criados pelo Create método cumprir os seguintes requisitos de conformidade por padrão:

  • Novas linhas e o valor de atributo são normalizados de acordo com o W3C recomendação XML 1.0.

  • Todas as entidades são expandidas automaticamente.

  • Os atributos padrão declarados na definição do tipo de documento são sempre adicionados mesmo quando o leitor não valida.

  • A declaração do prefixo XML mapeado para o URI de namespace XML correto é permitida.

  • Os nomes de notação em uma única NotationType declaração de atributo e NmTokens em uma única Enumeration declaração de atributo são diferentes.

Use estas propriedades XmlReaderSettings para especificar o tipo de verificações de conformidade que você deseja habilitar:

Use esta XmlReaderSettings propriedade Para Default
Propriedade CheckCharacters Habilite ou desabilite as verificações para o seguinte:

– Caracteres que estão dentro do intervalo de caracteres XML legais, como definidos na seção 2.2 Caracteres da Recomendação XML 1.0 do W3C.
-Todos os nomes XML são válidos, conforme definido pela 2.3 comuns sintática constrói seção recomendação W3C XML 1.0.

Quando essa propriedade é definida como true (padrão), um XmlException exceção será lançada se o arquivo XML contém caracteres inválidos ou nomes XML inválidos (por exemplo, um nome de elemento inicia com um número).
A verificação de caracteres e nomes está habilitada.

A definição de CheckCharacters como false desativa a verificação de caracteres em referências de entidade de caracteres. Se o leitor estiver processando dados de texto, ele sempre verificará se os nomes XML são válidos, independentemente dessa configuração. Observação: a recomendação XML 1.0 requer compatibilidade no nível do documento quando uma DTD estiver presente. Portanto, se o leitor está configurado para suportar ConformanceLevel.Fragment, mas os dados XML contêm um document type definition (DTD), um XmlException é gerada.
Propriedade ConformanceLevel Escolha o nível de conformidade a ser aplicado:

- Document. Está em conformidade com as regras para um documento XML bem formado 1,0.
- Fragment. Está em conformidade com as regras para um fragmento de documento bem formado que pode ser consumido como uma entidade analisada externa.
- Auto. Está de acordo com o nível decidido pelo leitor.

Se os dados não estiverem em conformidade, um XmlException exceção é lançada.
Document

O nó atual é o nó XML em que o leitor de XML está posicionado no momento. Todos os XmlReader métodos executam operações em relação a esse nó e todos os XmlReader propriedades refletem o valor do nó atual.

Os métodos a seguir facilitam a navegação pelos nós e a análise de dados.

Use esta XmlReaderSettings método Para
Read Leia o primeiro nó e avance pelo fluxo, um nó de cada vez. Essas chamadas são normalmente executadas dentro uma while loop.

Use o NodeType propriedade para obter o tipo (por exemplo, atributo, comentário, elemento e assim por diante) do nó atual.
Skip Ignore os filhos do nó atual e vá para o próximo nó.
MoveToContent e MoveToContentAsync Ignore nós que não sejam de conteúdo e avance para o próximo nó de conteúdo ou para o final do arquivo.

Os nós de conteúdo não incluem ProcessingInstruction, DocumentType, Comment, Whitespace, e SignificantWhitespace.

Nós de conteúdo incluem texto não seja espaço em branco, CDATA, EntityReference , e EndEntity.
ReadSubtree Ler um elemento e todos os seus filhos e retornar uma nova XmlReader instância definida como ReadState.Initial.

Esse método é útil para criar limites em torno de elementos XML. Por exemplo, se você deseja passar dados para outro componente para processamento e deseja limitar a quantidade de dados que o componente pode acessar.

Consulte o XmlReader.Read página de referência para obter um exemplo de navegar por meio de um nó de um de fluxo de texto por vez e exibir o tipo de cada nó.

As seções a seguir descrevem como você pode ler tipos específicos de dados, como elementos, atributos e dados digitados.

Ler elementos XML

A tabela a seguir lista os métodos e propriedades que o XmlReader classe fornece para processar elementos. Depois que XmlReader é posicionada em um elemento, as propriedades de nó, como Name, refletem os valores do elemento. Além dos membros descritos a seguir, alguns dos métodos e das propriedades gerais da classe XmlReader também podem ser usados para processar elementos. Por exemplo, é possível usar o método ReadInnerXml para ler o conteúdo de um elemento.

Observação

Consulte a seção 3.1 do recomendação do W3C XML 1.0 para definições de marcas de início, término marcas e marcas de elemento vazio.

Use este membro XmlReader Para
Método IsStartElement Verifique se o nó atual é uma marca inicial ou uma marca de elemento vazia.
Método ReadStartElement Verifique se o nó atual é um elemento e avança o leitor para o próximo nó (chamadas IsStartElement seguido por Read).
Método ReadEndElement Verifique se o nó atual é uma marca de fim e avance o leitor para o próximo nó.
Método ReadElementString Leia um elemento somente texto.
Método ReadToDescendant Avance o leitor XML para o próximo elemento descendente (filho) que tem o nome especificado.
Método ReadToNextSibling Avance o leitor XML para o próximo elemento irmão que tem o nome especificado.
Propriedade IsEmptyElement Verifique se o elemento atual tem uma marca de elemento final. Por exemplo:

- <item num="123"/> (IsEmptyElement é true.)
- <item num="123"> </item> (IsEmptyElement é false, embora o conteúdo do elemento esteja vazio.)

Para obter um exemplo de leitura do conteúdo de texto de elementos, consulte o método ReadString. O exemplo a seguir processa elementos usando um loop 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

Ler atributos XML

Os atributos XML são mais encontrados em elementos, mas também são permitidos em nós de declaração XML e tipo de documento.

Quando posicionados em um nó de elemento, os métodos MoveToAttribute permitem que você percorra a lista de atributos do elemento. Observe que depois que MoveToAttribute foi chamado, as propriedades do nó, como Name, NamespaceURI e Prefix refletem as propriedades desse atributo, não as propriedades do elemento ao qual o atributo pertence.

A classe XmlReader fornece esses métodos e propriedades para ler e processar atributos em elementos.

Use este membro XmlReader Para
Propriedade HasAttributes Verifique se o nó atual tem algum atributo.
Propriedade AttributeCount Obtenha o número de atributos no elemento atual.
Método MoveToFirstAttribute Mova para o primeiro atributo em um elemento.
Método MoveToNextAttribute Mova para o primeiro atributo em um elemento.
Método MoveToAttribute Mova para um atributo especificado.
Método GetAttribute ou propriedade Item[] Obtenha o valor de um atributo especificado.
Propriedade IsDefault Verifique se o nó atual é um atributo que foi gerado do valor padrão definido na DTD ou esquema.
Método MoveToElement Mova para o elemento que possui o atributo atual. Use esse método para retornar a um elemento depois de navegar por seus atributos.
Método ReadAttributeValue Analise o valor do atributo em um ou mais nós Text, EntityReference ou EndEntity.

Alguns dos métodos e propriedades gerais de XmlReader também podem ser usados para processar atributos. Por exemplo, depois que XmlReader é posicionado em um atributo, as propriedades Name e Value refletem os valores do atributo. Você também pode usar qualquer um dos métodos de conteúdo de Read para obter o valor do atributo.

Este exemplo usa a propriedade AttributeCount para navegar por todos os atributos em um 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

Este exemplo usa o método MoveToNextAttribute em um loop while para navegar pelos 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

Atributos de leitura em nós de declaração XML

Quando o leitor de XML é posicionado em um nó de declaração XML, a propriedade Value retorna as informações de versão, autônomas e de codificação como uma única cadeia de caracteres. Os objetos XmlReader criados pelo método Create, as classes XmlTextReader e XmlValidatingReader, expõem os itens de versão, os autônomos e de codificação como atributos.

Atributos de leitura em nós de tipo de documento

Quando o leitor de XML é posicionado em um nó de tipo de documento, o método GetAttribute e a propriedade Item[] podem ser usados para retornar os valores para os literais SYSTEM e PUBLIC. Por exemplo, a chamada de reader.GetAttribute("PUBLIC") retorna o valor PUBLIC.

Atributos de leitura em nós de instrução de processamento

Quando o XmlReader é posicionado em um nó de instrução de processamento, a propriedade Value retorna todo o conteúdo de texto. Os itens no nó de instrução de processamento não são tratados como atributos. Eles não podem ser lidos com os métodos GetAttribute ou MoveToAttribute.

Ler conteúdo XML

A classe XmlReader inclui os seguintes membros que leem o conteúdo de um arquivo XML e retornam o conteúdo como valores de cadeia de caracteres. (Para retornar tipos CLR, consulte Converter em tipos CLR.)

Use este membro XmlReader Para
Propriedade Value Obtenha o valor de texto do nó atual. O valor retornado depende do tipo de nó. Consulte a página de referência Value para obter detalhes.
Método ReadString Obtenha o conteúdo de um elemento ou nó de texto como uma cadeia de caracteres. Este método para nos comentários e nas instruções de processamento.

Para obter detalhes sobre como esse método manipula tipos de nó específicos, consulte a página de referência ReadString.
Métodos ReadInnerXml e ReadInnerXmlAsync Obtenha todo o conteúdo do nó atual, incluindo a marcação, mas excluindo as marcas de início e de fim. Por exemplo, para:

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

ReadInnerXml retorna:

this<child id="123"/>
Métodos ReadOuterXml e ReadOuterXmlAsync Obtenha todo o conteúdo do nó atual e seus filhos, incluindo marcação e marcas de início e de fim. Por exemplo, para:

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

ReadOuterXml retorna:

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

Converter para tipos CLR

Você pode usar os membros da classe XmlReader (listados na tabela a seguir) para ler dados XML e retornar valores como tipos CLR (Common Language Runtime) em vez de cadeias de caracteres. Esses membros permitem que você obtenha valores na representação mais apropriada para sua tarefa de codificação sem precisar analisar ou converter manualmente valores de cadeia de caracteres.

  • Os métodos ReadElementContentAs só podem ser chamados em tipos de nó de elemento. Esses métodos não podem ser usados em elementos que contêm os elementos filho ou o conteúdo misturado. Quando chamado, o objeto de XmlReader ler a tag de início, lê o conteúdo do elemento, e então move após a marca do elemento de extremidade. Instruções de processamento e comentários são ignorados e as entidades são expandidas.

  • Os métodos ReadContentAs leem o conteúdo do texto na posição atual do leitor e, se os dados XML não tiverem nenhuma informação de esquema ou tipo de dados associada a eles, convertem o conteúdo do texto no tipo de retorno solicitado. Texto, o espaço em branco, o espaço em branco significativo e seções CDATA são concatenados. Comentários e instruções de processamento são ignorados e referências a entidades são resolvidas automaticamente.

A classe XmlReader usa as regras definidas pela recomendação Parte 2 do Esquema XML do W3C: tipos de dados.

Use esta XmlReader método Para retornar esse tipo de CLR
ReadContentAsBoolean e ReadElementContentAsBoolean Boolean
ReadContentAsDateTime e ReadElementContentAsDateTime DateTime
ReadContentAsDouble e ReadElementContentAsDouble Double
ReadContentAsLong e ReadElementContentAsLong Int64
ReadContentAsInt e ReadElementContentAsInt Int32
ReadContentAsString e ReadElementContentAsString String
ReadContentAs e ReadElementContentAs O tipo especificado com o parâmetro returnType
ReadContentAsObject e ReadElementContentAsObject O tipo mais apropriado, conforme especificado pela propriedade XmlReader.ValueType. Consulte Suporte a tipos nas classes System.Xml para obter informações de mapeamento.

Se um elemento não puder ser facilmente convertido em um tipo CLR devido ao seu formato, você poderá usar um mapeamento de esquema para garantir uma conversão bem-sucedida. O exemplo a seguir usa um arquivo .xsd para converter o elemento hire-date para o tipo xs:date e, em seguida, usa o método ReadElementContentAsDateTime para retornar o elemento como um 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

Saída:

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

Programação assíncrona

A maioria dos métodos XmlReader tem contrapartes assíncronas que têm "Async" no final dos nomes dos métodos. Por exemplo, o equivalente assíncrono de ReadContentAsObject é ReadContentAsObjectAsync.

Os seguintes métodos podem ser usados com chamadas de método assíncrono:

As seções a seguir descrevem o uso assíncrono para métodos que não têm contrapartes assíncronas.

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

Considerações de segurança

Considere o seguinte ao trabalhar com a classe XmlReader:

  • As exceções geradas pelo XmlReader podem revelar informações do caminho que você não deseja que sejam propagadas para seu aplicativo. Seu aplicativo deve capturar exceções e processá-las adequadamente.

  • Não habilite o processamento de DTD se você estiver preocupado sobre problemas de negação de serviço ou se você estiver lidando com fontes não confiáveis. O processamento de DTD é desabilitado por padrão para objetos XmlReader criados pelo método Create.

    Se você tiver o processamento de DTD ativado, você pode usar XmlSecureResolver para restringir os recursos que XmlReader pode acessar. Você também pode criar seu aplicativo para que o processamento de XML tenha limitação de memória e tempo. Por exemplo, você pode configurar limites de tempo limite no seu aplicativo ASP.NET.

  • Os dados XML podem incluir referências a recursos externos como um arquivo de esquema. Os recursos externos são determinados por padrão usando um objeto XmlUrlResolver sem credenciais do usuário. Você pode proteger este adicional seguindo um destes procedimentos:

  • Os sinalizadores de validação ProcessInlineSchema e ProcessSchemaLocation de um objeto XmlReaderSettings não são definidos por padrão. Isso ajuda a proteger contra ataques XmlReader baseados esquema- quando está processando dados de uma fonte não confiável. Quando esses sinalizadores são definidos, XmlResolver do objeto de XmlReaderSettings é usado para resolver os locais de esquema encontrados no documento de instância em XmlReader. Se a propriedade XmlResolver for definida como null, os locais de esquema não são resolvidos mesmo se os sinalizadores de validação ProcessInlineSchema e ProcessSchemaLocation forem definidos.

    Os esquemas adicionados durante a validação adicionar novos tipos e podem alterar o resultado de validação de documento que está sendo validada. Como resultado, os esquemas externos só devem ser resolvidos de fontes confiáveis.

    Recomendamos desativar o sinalizador ProcessIdentityConstraints ao validar documentos XML não confiáveis e grandes em cenários de alta disponibilidade com um esquema com restrições de identidade sobre uma grande parte do documento. O sinalizador é habilitado por padrão.

  • Os dados XML podem conter um grande número de declarações de atributos, namespace, elementos aninhados e assim por diante que exigem um montante considerável de tempo de processamento. Para limitar o tamanho da entrada enviada ao XmlReader, você pode:

  • O método ReadValueChunk pode ser utilizado para lidar com grandes fluxos de dados. Este método lê um pequeno número de caracteres de cada vez em vez de atribuir uma única cadeia de caracteres para o valor inteiro.

  • Um problema pode ocorrer ao ler um documento XML com um grande número de nomes locais exclusivos, namespaces ou prefixos. Se você estiver usando uma classe que deriva de XmlReader e chamar a propriedade LocalName, Prefix ou NamespaceURI para cada item, a cadeia de caracteres retornada será adicionada a um NameTable. A coleção mantida por NameTable nunca diminui de tamanho, criando uma perda de memória virtual de identificadores de cadeia de caracteres. Uma mitigação disso é derivar da classe NameTable e impor uma cota de tamanho máximo. (Não há como impedir o uso de um NameTable, ou trocar o NameTable quando ele estiver cheio). Outra mitigação é evitar usar as propriedades mencionadas e, em vez disso, usar o método MoveToAttribute com o método IsStartElement sempre que possível. Esses métodos não retornam cadeias de caracteres e, portanto, evitam o problema de sobrecarregar a coleção NameTable.

  • os objetos deXmlReaderSettings podem conter informações sigilosas como credenciais do usuário. Um componente não confiável pode usar o objeto de XmlReaderSettings e suas credenciais de usuário para criar objetos de XmlReader para ler dados. Tenha cuidado ao armazenar em cache objetos XmlReaderSettings, ou ao passar o objeto XmlReaderSettings de um componente para outro.

  • Aceitar componentes de suporte, como NameTable, XmlNamespaceManager, e objetos de XmlResolver , de uma fonte não confiável.