Classe System.Xml.XmlReader

Cet article vous offre des remarques complémentaires à la documentation de référence pour cette API.

XmlReader fournit un accès en transfert seule et en lecture seule aux données XML dans un document ou un flux. Cette classe est conforme aux recommandations W3C Extensible Markup Language (XML) 1.0 (quatrième édition) et aux espaces de noms dans les XML 1.0 (troisième édition).

Les méthodes XmlReader vous permettent de parcourir les données XML et de lire le contenu d’un nœud. Les propriétés de la classe reflètent la valeur du nœud actuel, l’endroit d’emplacement du lecteur. La valeur ReadState de la propriété indique l’état actuel du lecteur XML. Par exemple, la propriété est définie à ReadState.Initial par la méthode XmlReader.Read et à ReadState.Closed par la méthode XmlReader.Close. XmlReader fournit également des vérifications et une validation de conformité des données sur un DTD ou un schéma.

XmlReader utilise un modèle d’extraction pour récupérer des données. Ce modèle :

  • Simplifie la gestion de l’état par un affinement procédural naturel et bas.
  • Prend en charge plusieurs flux d’entrée et la couche.
  • Permet au client de donner à l’analyseur une mémoire tampon dans laquelle la chaîne est directement écrite, et évite ainsi la nécessité d’une copie de chaîne supplémentaire.
  • Prise en charge du traitement sélectif. Le client peut ignorer les éléments et traiter ceux qui sont intéressants pour l’application. Vous pouvez également définir des propriétés à l’avance pour gérer la façon dont le flux XML est traité (par exemple, normalisation).

Créer un lecteur XML

Utilisez la méthode Create pour créer une instance XmlReader.

Bien que .NET fournisse des implémentations concrètes de la classe XmlReader, telles que les classes XmlTextReader, XmlNodeReaderet XmlValidatingReader, nous vous recommandons d’utiliser les classes spécialisées uniquement dans ces scénarios :

  • Lorsque vous souhaitez lire une sous-arborescence DOM XML à partir d’un objet XmlNode, utilisez la classe XmlNodeReader. (Toutefois, cette classe ne prend pas en charge la validation de schéma ou DTD.)
  • Si vous devez développer des entités à la demande, Il n’est pas intéressant que votre contenu texte soit normalisé ou que les attributs par défaut soient retournés. Pour régler cela, utilisez la classe XmlTextReader.

Pour spécifier l’ensemble de fonctionnalités que vous souhaitez activer sur le lecteur XML, transmettez un objet System.Xml.XmlReaderSettings à la méthode Create. Vous pouvez utiliser un seul objet System.Xml.XmlReaderSettings pour créer plusieurs lecteurs avec la même fonctionnalité, ou modifier l’objet System.Xml.XmlReaderSettings pour créer un lecteur avec un ensemble différent de fonctionnalités. Vous pouvez également ajouter facilement des fonctionnalités à un lecteur existant.

Si vous n’utilisez pas d’objet System.Xml.XmlReaderSettings, les paramètres par défaut sont utilisés. Consultez la page de référence Create pour en savoir plus.

XmlReader lève un XmlException sur les erreurs d’analyse XML. Une fois qu’une exception est levée, l’état du lecteur n’est pas prévisible. Par exemple, le type de nœud signalé peut être différent du type de nœud réel du nœud actuel. Utilisez la propriété ReadState pour vérifier si le lecteur est dans un état d’erreur.

Valider des données XML

Pour définir la structure d'un document XML et ses relations entre ses éléments, les types de données et les limites de contenu, vous devez utiliser une définition de type de document (DTD) ou un schéma de langage XSD (XML Schema Definition). Un document XML est considéré comme bien formé s’il répond à toutes les exigences syntactiques définies par la recommandation W3C XML 1.0. Il est considéré comme valide s’il est bien formé et est également conforme aux contraintes définies par son DTD ou son schéma. (Voir les recommandations W3C XML Schema Part 1 : structures et W3C XML Schema Part 2 : types de données.) Par conséquent, même si tous les documents XML valides sont bien formés, tous les documents XML bien formés ne sont pas valides.

Vous pouvez valider les données sur un DTD, un schéma XSD inline ou un schéma XSD stocké dans un objet XmlSchemaSet (un cache) ; ces scénarios sont décrits sur la page de référence Create. XmlReader ne prend pas en charge la validation de schéma XDR (XML-Data Reduced).

Vous utilisez les paramètres suivants sur la classe XmlReaderSettings pour spécifier le type de validation, le cas échéant, l’instance XmlReader prend en charge.

Utiliser ce membre XmlReaderSettings Pour spécifier
Propriété DtdProcessing Indique s’il faut autoriser le traitement DTD. Par défaut, le traitement DTD n'est pas autorisé.
Propriété ValidationType Indique si le lecteur doit valider les données et quel type de validation effectuer (DTD ou schéma). Par défaut, les données ne sont pas validées.
ÉvénementValidationEventHandler Un gestionnaire d'événements pour la réception d'informations sur les événements de validation. Si aucun gestionnaire d'événements n'est fourni, un objet XmlException est levé sur la première erreur de validation.
Propriété ValidationFlags Options de validation supplémentaires via les membres de l’énumération XmlSchemaValidationFlags :

- AllowXmlAttributes-- Autoriser les attributs XML (xml:*) dans les documents d’instance, même lorsqu’ils ne sont pas définis dans le schéma. Les attributs sont validés en fonction de leur type de données. Consultez la page de référence du paramètre XmlSchemaValidationFlags à utiliser dans des scénarios spécifiques. (Niveau désactivé par défaut).
- ProcessIdentityConstraints-- Traite les contraintes d'identité (xs:ID, xs:IDREF, xs:key, xs:keyref, xs:unique) rencontrées lors de la validation. (Activé par défaut.)
- ProcessSchemaLocation --Traiter les schémas spécifiés par l’attribut xsi:schemaLocation ou l’attribut xsi:noNamespaceSchemaLocation. (Activé par défaut.)
- ProcessInlineSchema-- Traiter les schémas XML inline lors de la validation. (Niveau désactivé par défaut).
- ReportValidationWarnings--Signaler les événements si un avertissement de validation se produit. Un avertissement est généralement émis lorsqu'un attribut ou élément particulier ne peut être validé par rapport à aucun schéma XML ou aucune DTD. Le ValidationEventHandler est utilisé pour les notifications. (Niveau désactivé par défaut).
Schemas XmlSchemaSet à utiliser pour la validation.
Propriété XmlResolver Le XmlResolver pour la résolution et l’accès aux ressources externes. Cela peut inclure des entités externes telles que DTD et des schémas, ainsi que tous les éléments xs:include ou xs:import dans le schéma XML. Si vous ne spécifiez pas d’informations d’identification utilisateur XmlResolver, le paramètre XmlReader utilise une valeur par défaut XmlUrlResolver sans informations d’identification utilisateur.

Conformité des données

Les lecteurs XML créés par la méthode Create répondent aux exigences de conformité suivantes par défaut :

  • Les nouvelles lignes et la valeur d’attribut sont normalisées conformément à la recommandation W3C XML 1.0.

  • Toutes les entités sont automatiquement développées.

  • Les attributs par défaut déclarés dans la définition de type de document sont toujours ajoutés même lorsque le lecteur ne valide pas.

  • La déclaration du préfixe XML mappé à l’URI d’espace de noms XML correct est autorisée.

  • Les noms de notation dans une déclaration d’attribut unique NotationType et NmTokens dans une seule déclaration d’attribut Enumeration sont distincts.

Utilisez ces propriétés XmlReaderSettings pour spécifier le type de vérification de conformité que vous souhaitez activer :

Utiliser cette propriété XmlReaderSettings À Par défaut
Propriété CheckCharacters Activez ou désactivez les vérifications suivantes :

- Les caractères se trouvent dans la plage de caractères XML juridiques, comme défini par la section 2.2 Caractères de la recommandation W3C XML 1.0.
- Tous les noms XML sont valides, comme défini par la section 2.3 Constructions syntactiques communes de la recommandation W3C XML 1.0.

Lorsque cette propriété est définie sur true (valeur par défaut), une exception est levée si le fichier XML contient des caractères non valides ou des noms XML non valides (par exemple, un nom d’élément XmlException commence par un nombre).
La vérification des caractères et des noms est activée.

Le paramètre CheckCharacters sur false désactive la vérification de caractères pour la recherche de références d'entité de caractère. Si le lecteur traite les données de texte, il vérifie toujours que les noms XML sont valides, quel que soit ce paramètre. Note : la recommandation XML 1.0 nécessite une conformité au niveau du document lorsqu'une DTD est présente. Par conséquent, si le lecteur est configuré pour prendre en charge ConformanceLevel.Fragment, mais que les données XML contiennent une définition de type de document (DTD), une valeur XmlException est levée.
Propriété ConformanceLevel Choisissez le niveau de conformité à appliquer :

- Document. Conforme aux règles d’un document XML 1.0 bien formé.
- Fragment. Conforme aux règles d’un fragment de document bien formé qui peut être consommé en tant qu’entité analysée externe.
- Auto. Conforme au niveau décidé par le lecteur.

Si les données ne sont pas conformes, une exception XmlException est levée.
Document

Le nœud actuel est le nœud XML sur lequel le lecteur XML est actuellement positionné. Toutes les méthodes XmlReader effectuent des opérations par rapport à ce nœud, et toutes les propriétés XmlReader reflètent la valeur du nœud actuel.

Les méthodes suivantes facilitent la navigation dans les nœuds et analysent les données.

Utiliser la méthode XmlReaderSettings À
Read Lisez le premier nœud et passez par le flux un à la fois. Ces appels sont généralement effectués à l’intérieur d’une boucle while.

Utilisez la propriété NodeType pour obtenir le type (par exemple, attribut, commentaire, élément, et ainsi de suite) du nœud actuel.
Skip Ignorez les enfants du nœud actuel et passez au nœud suivant.
MoveToContent et MoveToContentAsync Ignorez les nœuds sans contenu et passez au nœud de contenu suivant ou à la fin du fichier.

Les nœuds non-contenu incluent ProcessingInstruction, DocumentType, Comment, Whitespace etSignificantWhitespace.

Les nœuds de contenu incluent du texte d’espace non blanc, CDATA, EntityReference et EndEntity.
ReadSubtree Lisez un élément et tous ses enfants, puis retournez une nouvelle instance XmlReader définie sur ReadState.Initial.

Cette méthode est utile pour créer des limites autour des éléments XML ; par exemple, si vous souhaitez transmettre des données à un autre composant pour le traitement et que vous souhaitez limiter la quantité de vos données que le composant peut accéder.

Consultez la page de référence XmlReader.Read pour obtenir un exemple de navigation dans un flux de texte d’un nœud à la fois et d’affichage du type de chaque nœud.

Les sections suivantes décrivent comment vous pouvez lire des types de données spécifiques, tels que des éléments, des attributs et des données typées.

Lire des éléments XML

Le tableau suivant répertorie les méthodes et les propriétés que la classe XmlReader fournit pour le traitement des éléments. Une fois l'objet XmlReader positionné sur un élément, les propriétés du nœud, telles que Name, reflètent les valeurs de l'élément. Outre les membres décrits ci-dessous, toutes les propriétés et méthodes générales de la classe XmlReader peuvent également être utilisées pour le traitement des éléments. Par exemple, vous pouvez utiliser la méthode ReadInnerXml pour lire le contenu d'un élément.

Remarque

Consultez la section 3.1 de la recommandation W3C XML 1.0 pour les définitions des balises de début, des balises de fin et des balises d’élément vides.

Utiliser ce membre XmlReader À
Méthode IsStartElement Vérifiez si le nœud actuel est une balise de début ou d'élément vide.
Méthode ReadStartElement Vérifiez que le nœud actuel est un élément et faites avancer le lecteur vers le nœud suivant (appels IsStartElement suivis par Read).
Méthode ReadEndElement Vérifiez que le nœud actuel est une balise de fin et faites avancer le lecteur jusqu'au nœud suivant.
Méthode ReadElementString Lisez un élément texte uniquement.
Méthode ReadToDescendant Faites avancer le lecteur XML vers l’élément descendant (enfant) suivant qui a le nom spécifié.
Méthode ReadToNextSibling Faites avancer le lecteur XML vers l’élément frère suivant qui a le nom spécifié.
Propriété IsEmptyElement Vérifiez si l’élément actuel a une balise d’élément de fin. Par exemple :

- <item num="123"/> (IsEmptyElement est true).
- <item num="123"> </item> (IsEmptyElement est false, bien que le contenu de l’élément soit vide.)

Pour obtenir un exemple de lecture du contenu texte d’éléments, consultez la méthode ReadString. L’exemple suivant traite les éléments à l’aide d’une boucle 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

Lire les attributs XML

Les attributs XML sont les plus couramment trouvés sur les éléments, mais ils sont également autorisés sur les nœuds de déclaration XML et de type de document.

Lorsqu'elles sont positionnées sur un nœud d'élément, les méthodes MoveToAttribute vous permettent de parcourir la liste des attributs de l'élément. Notez qu’après l’appel de MoveToAttribute, les propriétés de nœud telles que Name, NamespaceURI et Prefix reflètent les propriétés de cet attribut, et non les propriétés de l’élément auquel appartient l’attribut.

La classe XmlReader fournit ces méthodes et propriétés pour lire et traiter des attributs sur des éléments.

Utilisez ce membre XmlReader À
Propriété HasAttributes Vérifiez si le nœud actuel a des attributs.
Propriété AttributeCount Obtient le nombre d'attributs de l’élément actuel.
Méthode MoveToFirstAttribute Accédez au premier attribut d’un élément.
Méthode MoveToNextAttribute Passez à l’attribut suivant dans un élément.
Méthode MoveToAttribute Passez à un attribut spécifié.
Méthode GetAttribute ou propriété Item[] Obtient la valeur d’un attribut spécifié.
Propriété IsDefault Vérifiez si le nœud actuel est un attribut qui a été généré à partir de la valeur par défaut définie dans la DTD ou le schéma.
Méthode MoveToElement Effectuez un déplacement vers l'élément qui contient l'attribut actuel. Utilisez cette méthode pour revenir à un élément après avoir parcouru ses attributs.
Méthode ReadAttributeValue Analysez la valeur d'attribut selon un ou plusieurs nœuds Text, EntityReference ou EndEntity.

Toutes les méthodes et propriétés XmlReader générales peuvent aussi être utilisées pour traiter des attributs. Par exemple, une fois que l'objet XmlReader a été positionné sur un attribut, les propriétés Name et Value reflètent les valeurs de cet attribut. Vous pouvez aussi utiliser les méthodes Read de contenu pour obtenir la valeur de l'attribut.

Cet exemple utilise la propriété AttributeCount pour parcourir tous les attributs d’un élément.

// 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

Cet exemple utilise la méthode MoveToNextAttribute dans une boucle while pour parcourir les attributs.

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

Lecture d’attributs sur des nœuds de déclaration XML

Lorsque le lecteur XML est positionné sur un nœud de déclaration XML, la propriété Value retourne les informations de version, autonomes et d’encodage sous forme de chaîne unique. Les objets XmlReader créés par la méthode Create, la classe XmlTextReader et la classe XmlValidatingReader exposent les éléments de version, autonomes et d’encodage en tant qu’attributs.

Lecture d’attributs sur les nœuds de type de document

Lorsque le lecteur XML est positionné sur un nœud de type de document, la méthode GetAttribute et la propriété Item[] peuvent être utilisées pour retourner les valeurs des littéraux SYSTEM et PUBLIC. Par exemple, un appel reader.GetAttribute("PUBLIC") retourne la valeur PUBLIC.

Lecture d’attributs sur les nœuds d’instruction de traitement

Lorsque l'objet XmlReader est positionné sur un n_œud d'instruction de traitement, la propriété Value retourne tout le contenu textuel. Les éléments contenus dans le nœud d'instruction de traitement ne sont pas traités comme des attributs. Ils ne peuvent pas être lus avec la méthode GetAttribute ou MoveToAttribute.

Lire du contenu XML

La classe XmlReader inclut les membres suivants qui lisent le contenu à partir d’un fichier XML et retournent le contenu sous forme de valeurs de chaîne. (Pour retourner des types CLR, consultez Convertir en types CLR).

Utilisez ce membre XmlReader À
Propriété Value Obtenez le contenu texte du nœud actuel. La valeur retournée dépend du type de nœud ; consultez la page de référence pour plus d’informations Value .
Méthode ReadString Obtenez le contenu d'un nœud d'élément ou de texte sous forme de chaîne. Cette méthode s'arrête aux instructions de traitement et commentaires.

Pour plus d’informations sur la façon dont cette méthode gère des types de nœuds spécifiques, consultez la page de référence ReadString.
Méthodes ReadInnerXml et ReadInnerXmlAsync Obtenez tout le contenu du nœud actuel, y compris le balisage, mais en ignorant les balises de début et de fin. Par exemple, pour :

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

ReadInnerXml retourne :

this<child id="123"/>
Méthodes ReadOuterXml et ReadOuterXmlAsync Obtenir tout le contenu du nœud actuel et de ses enfants, y compris les balises de balisage et de début/fin. Par exemple, pour :

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

ReadOuterXml retourne :

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

Convertir en types CLR

Vous pouvez utiliser les membres de la classe XmlReader (répertoriés dans le tableau suivant) pour lire des données XML et retourner des valeurs en tant que types CLR (Common Language Runtime) au lieu de chaînes. Ces membres vous permettent d’obtenir des valeurs dans la représentation qui convient le mieux à votre tâche de codage sans avoir à analyser ou convertir manuellement des valeurs de chaîne.

  • Les méthodes ReadElementContentAs ne peuvent être appelées que sur les types de nœuds d’élément. Elles peuvent être utilisées pour des éléments qui comportent des éléments enfants ou du contenu mixte. S’il est appelé, l’objet XmlReader lit l’étiquette de début et le contenu de l’élément, puis avance jusqu’après l’étiquette d’élément de fin. Les instructions de traitement et les commentaires sont ignorés et les entités sont développées.

  • Les méthodes ReadContentAs lisent le contenu du texte à la position actuelle du lecteur et, si les données XML n’ont pas de schéma ni d’informations de type de données associées, convertissez le contenu du texte en type de retour demandé. Le texte, les espaces blancs, les espaces blancs significatifs et les sections CDATA sont concaténés. Les commentaires et les instructions de traitement sont ignorés et les références d'entité sont automatiquement résolues.

La classe XmlReader utilise les règles définies par la recommandation du W3C sur le schéma XML Part 2: Datatypes.

Utiliser la méthode XmlReader Pour retourner ce type CLR
ReadContentAsBoolean et ReadElementContentAsBoolean Boolean
ReadContentAsDateTime et ReadElementContentAsDateTime DateTime
ReadContentAsDouble et ReadElementContentAsDouble Double
ReadContentAsLong et ReadElementContentAsLong Int64
ReadContentAsInt et ReadElementContentAsInt Int32
ReadContentAsString et ReadElementContentAsString String
ReadContentAs et ReadElementContentAs Type que vous spécifiez avec le paramètre returnType
ReadContentAsObject et ReadElementContentAsObject Type le plus approprié, tel que spécifié par la propriété XmlReader.ValueType. Consultez la prise en charge des types dans les classes System.Xml pour obtenir des informations de mappage.

Si un élément ne peut pas facilement être converti en type CLR en raison de son format, vous pouvez utiliser un mappage de schéma pour garantir une conversion réussie. L’exemple suivant utilise un fichier .xsd pour convertir l’élément hire-date en type xs:date, puis utilise la méthode ReadElementContentAsDateTime pour renvoyer l’élément en tant qu’objet DateTime.

Entrée (hireDate.xml) :

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

Schéma (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>

Code :

// 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

Sortie :

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

Programmation asynchrone

La plupart des méthodes XmlReader ont des équivalents asynchrones qui ont « Async » à la fin du nom de leurs méthodes. Par exemple, l’équivalent asynchrone de ReadContentAsObject est ReadContentAsObjectAsync.

Les méthodes suivantes peuvent être utilisées avec des appels de méthode asynchrones :

Les sections suivantes décrivent l’utilisation asynchrone des méthodes qui n’ont pas d’équivalents asynchrones.

Méthode 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éthode 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éthode 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éthode 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éthode 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

Considérations de sécurité

Tenez compte des éléments suivants lors de l’utilisation de la classe XmlReader :

  • Les exceptions levées à partir du XmlReader peuvent divulguer des informations de chemin que vous ne souhaiterez peut-être pas faire apparaître dans votre application. Vos applications doivent intercepter les exceptions et les traiter correctement.

  • Le traitement DTD ne doit pas être activé en cas de crainte concernant les problèmes de déni de service ou d'utilisation de sources non fiables. Le traitement DTD est désactivé par défaut pour les objets XmlReader créés par la méthode Create.

    Si le traitement DTD est activé, vous pouvez utiliser l'objet XmlSecureResolver pour limiter les ressources auxquelles l'objet XmlReader peut avoir accès. Vous pouvez également concevoir votre application afin que le traitement XML soit limité en termes de mémoire et de temps. Par exemple, vous pouvez configurer des limites de délai dans l'application ASP.NET.

  • Les données XML peuvent inclure des références à des ressources externes telles qu'un fichier de schéma. Par défaut, les ressources externes sont résolues en utilisant un objet XmlUrlResolver sans informations d'identification de l'utilisateur. Vous pouvez renforcer la sécurité en procédant comme suit :

  • Les indicateurs de validation ProcessInlineSchema et ProcessSchemaLocation d'un objet XmlReaderSettings ne sont pas activés par défaut. Cela contribue à protéger l'objet XmlReader contre les attaques basées sur des schémas lorsqu'il traite des données XML provenant d'une source non fiable. Lorsque ces indicateurs sont activés, la propriété XmlResolver de l'objet XmlReaderSettings est utilisée pour résoudre les emplacements de schéma rencontrés dans le document d'instance dans l'objet XmlReader. Si la propriété XmlResolver est définie sur null, les emplacements de schémas ne sont pas résolus, même si les indicateurs de validation ProcessInlineSchema et ProcessSchemaLocation sont activés.

    Les schémas ajoutés lors de la validation ajoutent de nouveaux types et peuvent changer le résultat de la validation du document en cours de validation. Par conséquent, les schémas externes ne devraient être résolus que s'ils proviennent de sources fiables.

    Nous recommandons de désactiver l'indicateur ProcessIdentityConstraintslors de la validation de documents XML volumineux non fiables dans des scénarios de haute disponibilité par rapport à un schéma qui dispose des contraintes d'identité sur une grande partie du document. Cet indicateur est activé par défaut.

  • Les données XML peuvent contenir un grand nombre d'attributs, de déclarations d'espaces de noms, d'éléments imbriqués, etc. exigeant un temps de traitement long. Pour limiter la taille de l’entrée envoyée au XmlReader, vous pouvez :

    • Limitez la taille du document en définissant la propriété MaxCharactersInDocument.

    • Limitez le nombre maximal de caractères résultant des entités développées en configurant la propriété MaxCharactersFromEntities.

    • Créez une implémentation personnalisée IStream pour le XmlReader.

  • La méthode ReadValueChunk peut être utilisée pour gérer de grands flux de données. Cette méthode lit un petit nombre de caractères à la fois au lieu d'allouer une seule chaîne à toute la valeur.

  • Lors de la lecture d'un document XML contenant un grand nombre de noms locaux uniques, d'espaces de noms ou de préfixes peut poser problème. Si vous utilisez une classe dérivée de XmlReader et que vous appelez la propriété LocalName, Prefix ou NamespaceURI pour chaque élément, la chaîne retournée est ajoutée à NameTable. La collection détenue par NameTable ne diminue jamais en taille et crée une fuite de mémoire virtuelle des handles de chaîne. Une atténuation pour cela consiste à dériver de la classe NameTable et à appliquer un quota de taille maximale. (Il n’existe aucun moyen d’empêcher l’utilisation d’un NameTable, ou de changer le moment NameTable où il est plein). Une autre atténuation est d’éviter l’emploi des propriétés mentionnées et utilisez plutôt la méthode MoveToAttribute avec la méthode IsStartElement dans la mesure du possible ; ces méthodes ne retournant pas de chaînes, la collection NameTable n'est pas saturée.

  • Les objets XmlReaderSettings peuvent contenir des informations confidentielles telles que des informations d'identification de l'utilisateur. Un composant non fiable pourrait utiliser l'objet XmlReaderSettings et ses informations d'identification pour créer des objets XmlReader afin de lire des données. Soyez prudent lorsque vous mettez en cache des objets XmlReaderSettings ou que vous transmettez l'objet XmlReaderSettings d'un composant à un autre.

  • N'acceptez pas les composants de prise en charge, tels que les objets NameTable, XmlNamespaceManager et XmlResolver provenant d'une source non fiable.