Compartilhar via


Classe System.Xml.XmlReader

Este artigo fornece comentários complementares à documentação de referência para esta API.

XmlReader fornece acesso somente encaminhamento e somente leitura a dados XML em um documento ou fluxo. Essa classe está em conformidade com a Linguagem de Marcação Extensível (XML) 1.0 W3C (quarta edição) e com as recomendações de Namespaces em XML 1.0 (terceira edição).

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 ReadState valor da propriedade indica o estado atual do leitor XML. Por exemplo, a propriedade é definida ReadState.Initial pelo XmlReader.Read método e ReadState.Closed pelo XmlReader.Close método. XmlReader também fornece verificações de conformidade de dados e validação contra um DTD ou esquema.

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

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

Criar um leitor XML

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

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

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

Para especificar o conjunto de recursos que você deseja habilitar no leitor XML, passe um System.Xml.XmlReaderSettings objeto para o Create método. Você pode usar um único System.Xml.XmlReaderSettings objeto para criar vários leitores com a mesma funcionalidade ou modificar o System.Xml.XmlReaderSettings objeto 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 System.Xml.XmlReaderSettings objeto, as configurações padrão serão usadas. Consulte a Create página de referência para obter detalhes.

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 ReadState propriedade para verificar se o leitor está no estado de erro.

Validar dados XML

Para definir a estrutura de um documento XML e suas relações de elemento, tipos de dados e restrições de conteúdo, use um esquema de DTD (definição de tipo de documento) ou XSD (linguagem de definição de esquema XML). Um documento XML será considerado bem formado se atender a todos os requisitos sintáticos definidos pela Recomendação W3C XML 1.0. Ele é considerado válido se estiver bem formado e também estiver em conformidade com as restrições definidas por seu DTD ou esquema. (Consulte o esquema XML W3C parte 1: estruturas e o esquema XML W3C Parte 2: recomendações de 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 contra um DTD, um esquema XSD embutido ou um esquema XSD armazenado em um XmlSchemaSet objeto (um cache); esses cenários são descritos na página de referência Create. XmlReader não dá suporte à validação de esquema XML-Data Reduzido (XDR).

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

Use este membro XmlReaderSettings Para especificar
Propriedade DtdProcessing Se deseja permitir o processamento de DTD. O padrão é não permitir o processamento de DTD.
Propriedade ValidationType Se o leitor deve validar dados e que tipo de validação executar (DTD ou esquema). O padrão não é nenhuma 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, um XmlException será gerado no primeiro erro de validação.
Propriedade ValidationFlags Opções de validação adicionais por meio dos membros de enumeração XmlSchemaValidationFlags:

- AllowXmlAttributes-- Permitir atributos XML (xml:*) em documentos de instância mesmo quando eles não estiverem definidos no esquema. Os atributos são validados com base em seu tipo de dados. Consulte a XmlSchemaValidationFlags página de referência para a configuração a ser usada em cenários específicos. (Desabilitado por padrão.)
- ProcessIdentityConstraints--Restrições de identidade de processo (xs:ID, , xs:IDREF, xs:keyxs:keyref, , xs:unique) encontradas 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 esquemas XML embutidos durante a validação. (Desabilitado por padrão.)
- ReportValidationWarnings--Relate eventos caso ocorra um aviso de validação. Normalmente, um aviso é emitido quando não há esquema DTD ou XML para validar um determinado elemento ou atributo. O 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 DTD e esquemas, e quaisquer elementos xs:include ou xs:import contidos no esquema XML. Se você não especificar um XmlResolver, o XmlReader usará um XmlUrlResolver padrão sem credenciais de usuário.

Conformidade de dados

Os leitores XML criados pelo Create método atendem aos seguintes requisitos de conformidade por padrão:

  • As novas linhas e o valor do atributo são normalizados de acordo com a recomendação W3C XML 1.0.

  • Todas as entidades são expandidas automaticamente.

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

  • A declaração de prefixo XML mapeada para o URI do 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 distintos.

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

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

- Os caracteres estão dentro do intervalo de caracteres XML legais, conforme definido pela seção 2.2 Caracteres da Recomendação W3C XML 1.0.
- Todos os nomes XML são válidos, conforme definido pela seção 2.3 Common Syntactic Constructs da Recomendação W3C XML 1.0.

Quando essa propriedade é definida true como (padrão), uma exceção XmlException é gerada se o arquivo XML contém caracteres ilegais ou nomes XML inválidos (por exemplo, um nome de elemento começa 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. Nota: A recomendação XML 1.0 requer conformidade no nível do documento quando um DTD está presente. Portanto, se o leitor estiver configurado para dar suporte ConformanceLevel.Fragment, mas os dados XML contiverem uma DTD (definição de tipo de documento), um XmlException será gerado.
Propriedade ConformanceLevel Escolha o nível de conformidade a ser aplicado:

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

Se os dados não estiverem em conformidade, uma exceção XmlException será gerada.
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 todas as XmlReader propriedades refletem o valor do nó atual.

Os métodos a seguir tornam fácil a navegação através dos nós e a análise de dados.

Use este XmlReaderSettings método Para
Read Leia o primeiro nó e avance pelo fluxo, um nó de cada vez. Essas chamadas normalmente são executadas dentro de um 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 que não são de conteúdo incluem ProcessingInstruction, DocumentType, Comment, Whitespacee SignificantWhitespace.

Os nós de conteúdo incluem texto de espaço não branco, CDATAEntityReference e EndEntity.
ReadSubtree Leia um elemento e todos os seus filhos, e retorne uma nova instância de XmlReader configurada para ReadState.Initial.

Esse método é útil para criar limites em torno de elementos XML; por exemplo, se você quiser passar dados para outro componente para processamento e quiser 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 as propriedades que a XmlReader classe fornece para elementos de processamento. Depois que XmlReader é posicionada em um elemento, as propriedades de nó, como Name, refletem os valores do elemento. Além dos membros descritos abaixo, qualquer um dos métodos gerais e propriedades da XmlReader classe também pode ser usado para processar elementos. Por exemplo, você pode usar o ReadInnerXml método para ler o conteúdo de um elemento.

Observação

Consulte a seção 3.1 da Recomendação W3C XML 1.0 para obter definições de marcas de início, marcas de fim e marcas de elemento vazias.

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 dos elementos, consulte o ReadString método. O exemplo a seguir processa elementos usando um while loop.

while (reader.Read()) {
  if (reader.IsStartElement()) {
    if (reader.IsEmptyElement)
                {
                    Console.WriteLine($"<{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 comumente encontrados em elementos, mas também são permitidos nos nós de declaração XML e de tipo de documento.

Quando posicionado em um nó de elemento, o método MoveToAttribute permite percorrer 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 do respectivo atributo, e não as propriedades do elemento ao qual esse atributo pertence.

A XmlReader classe 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 próximo atributo em um elemento.
método MoveToAttribute Mover para um atributo especificado.
GetAttribute método ou Item[] propriedade 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.

Qualquer um dos métodos e propriedades gerais XmlReader também pode ser usado para processar atributos. Por exemplo, depois que o 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 Read para obter o valor do atributo.

Este exemplo usa a AttributeCount propriedade 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($"  {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 MoveToNextAttribute método em um while loop para navegar pelos atributos.

if (reader.HasAttributes) {
  Console.WriteLine("Attributes of <" + reader.Name + ">");
  while (reader.MoveToNextAttribute()) {
    Console.WriteLine($" {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

Lendo atributos em nós de declaração XML

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

Atributos de leitura em nós de tipo de documento

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

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

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

Ler conteúdo XML

A classe XmlReader inclui os seguintes membros que leem 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. Esse método interrompe o processamento de instruções e comentários.

Para obter detalhes sobre como esse método lida com tipos de nó específicos, consulte a ReadString página de referência.
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 XmlReader classe (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 valores de cadeia de caracteres manualmente.

  • 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 XmlReader objeto lê a marca inicial, lê o conteúdo do elemento e, em seguida, passa pela marca do elemento final. As instruções de processamento e os 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 informações de tipo de dados ou esquema associadas a ele, converta 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. Os comentários e as instruções de processamento são ignorados, e as referências às entidades são resolvidas automaticamente.

A XmlReader classe usa as regras definidas pela recomendação W3C XML Schema Part 2: Datatypes .

Use este 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 que você especifica com o parâmetro returnType
ReadContentAsObject e ReadElementContentAsObject O tipo mais apropriado, conforme especificado pela XmlReader.ValueType propriedade. Consulte o suporte a tipos nas classes System.Xml para obter informações de mapeamento.

Se um elemento não puder ser convertido facilmente 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 hire-date elemento no xs:date tipo e, em seguida, usa o ReadElementContentAsDateTime método para retornar o elemento como um DateTime objeto.

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: {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 XmlReader métodos tem equivalentes assíncronos que têm "Async" no final de seus nomes de método. Por exemplo, o equivalente ReadContentAsObject assíncrono é ReadContentAsObjectAsync.

Os métodos a seguir 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 equivalentes assíncronos.

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 XmlReader classe:

  • 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 com problemas de negação de serviço ou se estiver lidando com fontes não confiáveis. O processamento de DTD é desabilitado por padrão para XmlReader objetos criados pelo Create método.

    Se você tiver o processamento de DTD habilitado, poderá usar o XmlSecureResolver para restringir os recursos que o XmlReader pode acessar. Você também pode projetar seu aplicativo para que o processamento XML seja de memória e tempo restritos. Por exemplo, você pode configurar limites de tempo de espera em seu aplicativo ASP.NET.

  • Os dados XML podem incluir referências a recursos externos, como um arquivo de esquema. Por padrão, os recursos externos são resolvidos usando um XmlUrlResolver objeto sem credenciais de usuário. Você pode proteger isso ainda mais fazendo um dos seguintes 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 o XmlReader contra ataques baseados em esquema ao processar dados XML 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 estiver definida como null, os locais de esquema não serão resolvidos mesmo se os sinalizadores ProcessInlineSchema e ProcessSchemaLocation de validação estiverem definidos.

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

    Recomendamos desativar a ProcessIdentityConstraints flag ao validar documentos XML grandes e não confiáveis em cenários de alta disponibilidade, quando um esquema possui restrições de identidade sobre uma grande parte do documento. Esse sinalizador está habilitado por padrão.

  • Os dados XML podem conter um grande número de atributos, declarações de namespace, elementos aninhados e assim por diante que exigem uma quantidade substancial de tempo para processar. Para limitar o tamanho da entrada que é enviada para o XmlReader, você pode:

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

  • Ao ler um documento XML com um grande número de nomes locais exclusivos, namespaces ou prefixos, um problema pode ocorrer. Se você estiver usando uma classe que deriva de XmlReader, e você chamar a propriedade LocalName, Prefix ou NamespaceURI para cada item, a string 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 para isso é derivar da NameTable classe e impor uma cota de tamanho máximo. (Não há como impedir o uso de um NameTable, nem mudar o NameTable quando ele estiver cheio). Outra mitigação é evitar o uso das propriedades mencionadas e, em vez disso, usar o MoveToAttribute método com o IsStartElement método sempre que possível; esses métodos não retornam cadeias de caracteres e, portanto, evitam o problema de preenchimento excessivo da NameTable coleção.

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

  • Não aceite componentes de suporte, como NameTable, XmlNamespaceManagere XmlResolver objetos, de uma fonte não confiável.