次の方法で共有


System.Xml.XmlReader クラス

この記事では、この API のリファレンス ドキュメントに補足的な解説を提供します。

XmlReader は、ドキュメントまたはストリーム内の XML データに対する前方専用の読み取り専用アクセスを提供します。 このクラスは、W3C 拡張マークアップ言語 (XML) 1.0 (第 4 版) および XML 1.0 (第 3 版) の名前空間 に関する推奨事項に準拠しています。

XmlReader メソッドを使用すると、XML データ間を移動し、ノードの内容を読み取ります。 クラスのプロパティには、リーダーが配置されている現在のノードの値が反映されます。 ReadState プロパティの値は、XML リーダーの現在の状態を示します。 たとえば、プロパティは XmlReader.Read メソッドによってReadState.Initialに設定され、XmlReader.Close メソッドによってReadState.Closedされます。 XmlReader では、DTD またはスキーマに対するデータ準拠チェックと検証も提供されます。

XmlReader では、プル モデルを使用してデータを取得します。 このモデル:

  • 自然なトップダウン手続き型の絞り込みによって、状態管理を簡略化します。
  • 複数の入力ストリームと階層化をサポートします。
  • クライアントがパーサーに、文字列が直接書き込まれるバッファーを提供できるようにします。そのため、余分な文字列コピーが不要になります。
  • 選択的処理をサポートします。 クライアントは、項目をスキップし、アプリケーションに関心のある項目を処理できます。 また、プロパティを事前に設定して、XML ストリームの処理方法 (正規化など) を管理することもできます。

XML リーダーを作成する

XmlReader インスタンスを作成するには、Create メソッドを使用します。

.NET には、XmlTextReaderXmlNodeReaderXmlValidatingReader クラスなど、XmlReader クラスの具体的な実装が用意されていますが、特殊なクラスは次のシナリオでのみ使用することをお勧めします。

  • XmlNode オブジェクトから XML DOM サブツリーを読み取る場合は、XmlNodeReader クラスを使用します。 (ただし、このクラスは DTD またはスキーマの検証をサポートしていません)。
  • 要求に応じてエンティティを展開する必要がある場合、テキスト コンテンツを正規化したくない場合、または既定の属性を返したくない場合は、 XmlTextReader クラスを使用します。

XML リーダーで有効にする機能のセットを指定するには、 System.Xml.XmlReaderSettings オブジェクトを Create メソッドに渡します。 1 つの System.Xml.XmlReaderSettings オブジェクトを使用して、同じ機能を持つ複数のリーダーを作成したり、 System.Xml.XmlReaderSettings オブジェクトを変更して、異なる機能セットを持つ新しいリーダーを作成したりできます。 既存のリーダーに機能を簡単に追加することもできます。

System.Xml.XmlReaderSettings オブジェクトを使用しない場合は、既定の設定が使用されます。 詳細については、 Create リファレンス ページを参照してください。

XmlReader は、XML 解析時のエラーの際に XmlException を投げます。 例外がスローされた後、リーダーの状態は予測できません。 たとえば、報告されるノードタイプは、現在のノードの実際のノードタイプと異なる場合があります。 ReadState プロパティを使用して、リーダーがエラー状態であるかどうかを確認します。

XML データの検証

XML ドキュメントの構造とその要素リレーションシップ、データ型、およびコンテンツ制約を定義するには、ドキュメント型定義 (DTD) または XML スキーマ定義言語 (XSD) スキーマを使用します。 XML ドキュメントは、 W3C XML 1.0 Recommendation で定義されているすべての構文要件を満たしている場合、整形式であると見なされます。 整形式であり、DTD またはスキーマによって定義された制約にも準拠している場合は、有効と見なされます。 ( W3C XML スキーマ パート 1: 構造体W3C XML スキーマパート 2: データ型の 推奨事項を参照してください)。したがって、すべての有効な XML ドキュメントは整形式ですが、すべての整形式 XML ドキュメントが有効なわけではありません。

DTD、インライン XSD スキーマ、または XmlSchemaSet オブジェクト (キャッシュ) に格納されている XSD スキーマに対してデータを検証できます。これらのシナリオについては、 Create リファレンス ページで説明します。 XmlReader では、XML-Data 削減 (XDR) スキーマの検証はサポートされていません。

XmlReaderSettings クラスで次の設定を使用して、XmlReader インスタンスがサポートする検証の種類 (存在する場合) を指定します。

この XmlReaderSettings メンバーを使用する を指定するには
DtdProcessing プロパティ DTD 処理を許可するかどうか。 既定では、DTD 処理は許可されません。
ValidationType プロパティ リーダーがデータを検証するかどうか、および実行する検証の種類 (DTD またはスキーマ)。 既定値はデータ検証なしです。
ValidationEventHandler 出来事 検証イベントに関する情報を受信するためのイベント ハンドラー。 イベント ハンドラーが指定されていない場合は、最初の検証エラーで XmlException がスローされます。
ValidationFlags プロパティ XmlSchemaValidationFlags列挙メンバーを使用した追加の検証オプション:

- AllowXmlAttributes-- スキーマで定義されていない場合でも、インスタンス ドキュメントで XML 属性 (xml:*) を許可します。 属性は、データ型に基づいて検証されます。 特定のシナリオで使用する設定については、 XmlSchemaValidationFlags リファレンス ページを参照してください。 (既定では無効です)。
- ProcessIdentityConstraints --検証中に発生した ID 制約 (xs:IDxs:IDREFxs:keyxs:keyrefxs:unique) を処理します。 (既定で有効)。
- ProcessSchemaLocation -- xsi:schemaLocation または xsi:noNamespaceSchemaLocation 属性で指定されたスキーマを処理します。 (既定で有効)。
- ProcessInlineSchema-- 検証中にインライン XML スキーマを処理します。 (既定では無効です)。
- ReportValidationWarnings--検証の警告が発生した場合にイベントを報告します。 通常、警告は、特定の要素または属性を検証する DTD または XML スキーマがない場合に発行されます。 ValidationEventHandlerは通知に使用されます。 (既定では無効です)。
Schemas 検証に使用する XmlSchemaSet
XmlResolver プロパティ 外部リソースを解決してアクセスするための XmlResolver 。 これには、DTD やスキーマなどの外部エンティティ、および XML スキーマに含まれる任意の xs:include または xs:import 要素を含めることができます。 XmlResolverを指定しない場合、XmlReaderはユーザー資格情報のない既定のXmlUrlResolverを使用します。

データの準拠

Create メソッドによって作成された XML リーダーは、既定で次のコンプライアンス要件を満たしています。

  • 新しい行と属性値は、W3C XML 1.0 の推奨事項に従って正規化されます。

  • すべてのエンティティが自動的に展開されます。

  • ドキュメント型定義で宣言された既定の属性は、リーダーが検証しない場合でも常に追加されます。

  • 正しい XML 名前空間 URI にマップされた XML プレフィックスの宣言が許可されます。

  • 単一のNotationType属性宣言の表記名と、単一のEnumeration属性宣言内のNmTokensは異なります。

有効にする準拠チェックの種類を指定するには、次の XmlReaderSettings プロパティを使用します。

この XmlReaderSettings プロパティを使用する 移行先 既定値
CheckCharacters プロパティ 次のチェックを有効または無効にします。

- 文字は、W3C XML 1.0 Recommendation の 2.2 文字 セクションで定義されている有効な XML 文字の範囲内にあります。
- W3C XML 1.0 の推奨事項の 2.3 共通構文コンストラクト セクションで定義されているように、すべての XML 名が有効です。

このプロパティを true (既定値) に設定すると、XML ファイルに無効な文字または無効な XML 名 (要素名が数値で始まるなど) が含まれている場合、 XmlException 例外がスローされます。
文字と名前のチェックが有効になっています。

CheckCharactersfalseに設定すると、文字エンティティ参照の文字チェックがオフになります。 リーダーがテキスト データを処理している場合、この設定に関係なく、XML 名が有効であることが常に確認されます。 手記: XML 1.0 の推奨事項では、DTD が存在する場合にドキュメント レベルの準拠が必要です。 したがって、リーダーが ConformanceLevel.Fragmentをサポートするように構成されているが、XML データにドキュメント型定義 (DTD) が含まれている場合は、 XmlException がスローされます。
ConformanceLevel プロパティ 適用する準拠レベルを選択します。

- Document整形式の XML 1.0 ドキュメントの規則に準拠しています。
- Fragment外部解析されたエンティティとして使用できる整形式のドキュメント フラグメントの規則に準拠します。
- Auto.リーダーによって決定されたレベルに準拠します。

データが準拠していない場合は、 XmlException 例外がスローされます。
Document

現在のノードは、XML リーダーが現在配置されている XML ノードです。 すべての XmlReader メソッドは、このノードに対して操作を実行し、すべての XmlReader プロパティに現在のノードの値が反映されます。

次のメソッドを使用すると、ノード間を簡単に移動し、データを解析できます。

この XmlReaderSettings メソッドを使用する 移行先
Read 最初のノードを読み取り、ストリームを 1 ノードずつ進みます。 このような呼び出しは、通常、 while ループ内で実行されます。

現在のノードの型 (属性、コメント、要素など) を取得するには、 NodeType プロパティを使用します。
Skip 現在のノードの子をスキップし、次のノードに移動します。
MoveToContentMoveToContentAsync 非コンテンツ ノードをスキップし、次のコンテンツ ノードまたはファイルの末尾に移動します。

非コンテンツ ノードには、 ProcessingInstructionDocumentTypeCommentWhitespace、および SignificantWhitespaceが含まれます。

コンテンツ ノードには、空白以外のテキスト、 CDATAEntityReferenceEndEntityが含まれます。
ReadSubtree 要素とそのすべての子を読み取り、ReadState.Initialに設定された新しいXmlReaderインスタンスを返します。

このメソッドは、XML 要素の周囲に境界を作成する場合に便利です。たとえば、処理のためにデータを別のコンポーネントに渡し、コンポーネントがアクセスできるデータの量を制限する場合などです。

テキスト ストリーム内を一度に 1 ノードずつ移動し、各ノードの種類を表示する例については、 XmlReader.Read リファレンス ページを参照してください。

次のセクションでは、要素、属性、型指定されたデータなど、特定の種類のデータを読み取る方法について説明します。

XML 要素の読み取り

次の表に、 XmlReader クラスが要素を処理するために提供するメソッドとプロパティを示します。 XmlReaderが要素に配置されると、Nameなどのノード プロパティに要素の値が反映されます。 以下で説明するメンバーに加えて、 XmlReader クラスの一般的なメソッドとプロパティを使用して要素を処理することもできます。 たとえば、 ReadInnerXml メソッドを使用して要素の内容を読み取ることができます。

開始タグ、終了タグ、および空の要素タグの定義については、 W3C XML 1.0 の推奨事項のセクション 3.1 を参照してください。

この XmlReader メンバーを使用する 移行先
IsStartElement メソッド 現在のノードが開始タグか空の要素タグかどうかを確認します。
ReadStartElement メソッド 現在のノードが要素であることを確認し、リーダーを次のノードに進めます ( IsStartElement 呼び出しの後に Read が続きます)。
ReadEndElement メソッド 現在のノードが終了タグであることを確認し、リーダーを次のノードに進めます。
ReadElementString メソッド テキストのみの要素を読み取る。
ReadToDescendant メソッド 指定した名前を持つ次の子孫 (子) 要素に XML リーダーを進めます。
ReadToNextSibling メソッド 指定した名前を持つ次の兄弟要素に XML リーダーを進めます。
IsEmptyElement プロパティ 現在の要素に終了要素タグがあるかどうかを確認します。 例えば次が挙げられます。

- <item num="123"/> (IsEmptyElementtrueです)。
- <item num="123"> </item> (IsEmptyElementfalseですが、要素のコンテンツは空です)。

要素のテキスト コンテンツを読み取る例については、 ReadString メソッドを参照してください。 次の例では、 while ループを使用して要素を処理します。

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

XML 属性の読み取り

XML 属性は要素で最も一般的に見られますが、XML 宣言ノードとドキュメント型ノードでも使用できます。

要素ノードに配置すると、 MoveToAttribute メソッドを使用して、要素の属性リストを確認できます。 MoveToAttributeが呼び出された後、NameNamespaceURIPrefixなどのノード プロパティには、属性が属する要素のプロパティではなく、その属性のプロパティが反映されることに注意してください。

XmlReader クラスは、要素の属性を読み取って処理するために、これらのメソッドとプロパティを提供します。

この XmlReader メンバーを使用する 移行先
HasAttributes プロパティ 現在のノードに属性があるかどうかを確認します。
AttributeCount プロパティ 現在の要素の属性の数を取得します。
MoveToFirstAttribute メソッド 要素の最初の属性に移動します。
MoveToNextAttribute メソッド 要素内の次の属性に移動します。
MoveToAttribute メソッド 指定した属性に移動します。
GetAttribute メソッドまたは Item[] プロパティ 指定した属性の値を取得します。
IsDefault プロパティ 現在のノードが、DTD またはスキーマで定義されている既定値から生成された属性であるかどうかを確認します。
MoveToElement メソッド 現在の属性を所有する要素に移動します。 このメソッドを使用して、属性内を移動した後に要素に戻ります。
ReadAttributeValue メソッド 属性値を 1 つ以上の TextEntityReference、または EndEntity ノードに解析します。

属性の処理には、一般的な XmlReader メソッドとプロパティを使用することもできます。 たとえば、 XmlReader を属性に配置した後、 Name プロパティと Value プロパティは属性の値を反映します。 また、任意のコンテンツ Read メソッドを使用して、属性の値を取得することもできます。

この例では、 AttributeCount プロパティを使用して、要素のすべての属性間を移動します。

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

この例では、while ループ内の MoveToNextAttribute メソッドを使用して、属性内を移動します。

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

XML 宣言ノードでの属性の読み取り

XML リーダーが XML 宣言ノードに配置されている場合、 Value プロパティはバージョン、スタンドアロン、エンコードの情報を 1 つの文字列として返します。 XmlReader Create メソッド、XmlTextReader クラス、および XmlValidatingReader クラスによって作成されたオブジェクトは、バージョン、スタンドアロン、およびエンコード項目を属性として公開します。

ドキュメントの種類のノードでの属性の読み取り

XML リーダーがドキュメント型ノードに配置されている場合、 GetAttribute メソッドと Item[] プロパティを使用して、SYSTEM リテラルと PUBLIC リテラルの値を返すことができます。 たとえば、 reader.GetAttribute("PUBLIC") を呼び出すと PUBLIC 値が返されます。

処理命令ノードでの属性の読み取り

XmlReaderが処理命令ノードに配置されると、Value プロパティはテキスト コンテンツ全体を返します。 処理命令ノード内の項目は属性として扱われません。 GetAttributeメソッドまたは MoveToAttribute メソッドでは読み取ることはできません。

XML コンテンツの読み取り

XmlReader クラスには、XML ファイルからコンテンツを読み取り、その内容を文字列値として返す次のメンバーが含まれています。 (CLR 型を返すには、「 CLR 型への変換」を参照してください)。

この XmlReader メンバーを使用する 移行先
Value プロパティ 現在のノードのテキスト コンテンツを取得します。 返される値はノードの種類によって異なります。詳細については、 Value リファレンス ページを参照してください。
ReadString メソッド 要素またはテキスト ノードの内容を文字列として取得します。 このメソッドは、命令とコメントの処理を停止します。

このメソッドが特定のノードの種類を処理する方法の詳細については、 ReadString リファレンス ページを参照してください。
ReadInnerXml および ReadInnerXmlAsync メソッド。 マークアップを含め、現在のノードのすべてのコンテンツを取得しますが、開始タグと終了タグは除きます。 たとえば、次のようになります。

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

ReadInnerXml が次のように返します。

this<child id="123"/>
ReadOuterXml および ReadOuterXmlAsync メソッド。 マークアップタグや開始/終了タグなど、現在のノードとその子のすべてのコンテンツを取得します。 たとえば、次のようになります。

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

ReadOuterXml が次のように返します。

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

CLR 型への変換

XmlReader クラスのメンバー (次の表に示す) を使用すると、XML データを読み取り、文字列ではなく共通言語ランタイム (CLR) 型として値を返すことができます。 これらのメンバーを使用すると、手動で文字列値を解析または変換することなく、コーディング タスクに最適な値を表現で取得できます。

  • ReadElementContentAs メソッドは、要素ノード型でのみ呼び出すことができます。 これらのメソッドは、子要素または混合コンテンツを含む要素では使用できません。 呼び出されると、 XmlReader オブジェクトは開始タグを読み取り、要素の内容を読み取り、終了要素タグの後に移動します。 処理命令とコメントは無視され、エンティティが展開されます。

  • ReadContentAs メソッドは、現在のリーダー位置でテキスト コンテンツを読み取ります。XML データにスキーマまたはデータ型の情報が関連付けられていない場合は、テキスト コンテンツを要求された戻り値の型に変換します。 テキスト、空白、重要な空白、および CDATA セクションが連結されます。 コメントと処理命令はスキップされ、エンティティ参照は自動的に解決されます。

XmlReader クラスは、W3C XML スキーマ パート 2: Datatypes に関する推奨事項で定義されている規則を使用します。

この XmlReader メソッドを使用する この CLR 型を返すには
ReadContentAsBooleanReadElementContentAsBoolean Boolean
ReadContentAsDateTimeReadElementContentAsDateTime DateTime
ReadContentAsDoubleReadElementContentAsDouble Double
ReadContentAsLongReadElementContentAsLong Int64
ReadContentAsIntReadElementContentAsInt Int32
ReadContentAsStringReadElementContentAsString String
ReadContentAsReadElementContentAs returnType パラメーターで指定する型
ReadContentAsObjectReadElementContentAsObject XmlReader.ValueType プロパティで指定された最も適切な型。 マッピング情報については 、System.Xml クラスの型のサポート を参照してください。

要素の形式が原因で CLR 型に簡単に変換できない場合は、スキーマ マッピングを使用して変換を成功させることができます。 次の例では、.xsd ファイルを使用して hire-date 要素を xs:date 型に変換し、 ReadElementContentAsDateTime メソッドを使用して要素を DateTime オブジェクトとして返します。

入力 (hireDate.xml):

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

スキーマ (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>

コード:

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

アウトプット:

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

非同期プログラミング

ほとんどの XmlReader メソッドには、メソッド名の末尾に "Async" を持つ非同期メソッドがあります。 たとえば、非同期の同等の ReadContentAsObjectReadContentAsObjectAsync

非同期メソッド呼び出しでは、次のメソッドを使用できます。

次のセクションでは、対応する非同期メソッドがないメソッドの非同期の使用方法について説明します。

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

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

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

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

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

セキュリティに関する考慮事項

XmlReader クラスを使用する場合は、次の点を考慮してください。

  • XmlReaderからスローされた例外は、アプリにバブルアップしたくない可能性があるパス情報を開示できます。 アプリで例外をキャッチし、適切に処理する必要があります。

  • サービス拒否の問題が懸念される場合、または信頼されていないソースを処理している場合は、DTD 処理を有効にしないでください。 Create メソッドによって作成されたXmlReader オブジェクトでは、DTD 処理が既定で無効になっています。

    DTD 処理を有効にしている場合は、 XmlSecureResolver を使用して、 XmlReader がアクセスできるリソースを制限できます。 また、XML 処理がメモリと時間に制約されるようにアプリを設計することもできます。 たとえば、ASP.NET アプリでタイムアウト制限を構成できます。

  • XML データには、スキーマ ファイルなどの外部リソースへの参照を含めることができます。 既定では、外部リソースは、ユーザー資格情報のない XmlUrlResolver オブジェクトを使用して解決されます。 これをさらにセキュリティで保護するために、次のいずれかの操作を行います。

  • XmlReaderSettings オブジェクトのProcessInlineSchemaおよびProcessSchemaLocation検証フラグは、既定では設定されません。 これは、信頼されていないソースから XML データを処理するときに、スキーマベースの攻撃から XmlReader を保護するのに役立ちます。 これらのフラグを設定すると、XmlResolver オブジェクトのXmlReaderSettingsを使用して、XmlReaderのインスタンス ドキュメントで検出されたスキーマの場所を解決します。 XmlResolver プロパティが null に設定されている場合、ProcessInlineSchemaおよびProcessSchemaLocation検証フラグが設定されている場合でも、スキーマの場所は解決されません。

    検証中に追加されたスキーマは新しい型を追加し、検証されるドキュメントの検証結果を変更できます。 その結果、外部スキーマは信頼できるソースからのみ解決する必要があります。

    ドキュメントの大部分に対して ID 制約があるスキーマに対して高可用性シナリオで信頼されていない大きな XML ドキュメントを検証する場合は、 ProcessIdentityConstraints フラグを無効にすることをお勧めします。 このフラグは既定で有効になっています。

  • XML データには、大量の属性、名前空間宣言、入れ子になった要素などを含めることができます。そのため、処理にかなりの時間が必要です。 XmlReaderに送信される入力のサイズを制限するには、次の手順を実行します。

    • MaxCharactersInDocument プロパティを設定して、ドキュメントのサイズを制限します。

    • MaxCharactersFromEntities プロパティを設定して、エンティティを展開した結果の文字数を制限します。

    • XmlReaderのカスタム IStream実装を作成します。

  • ReadValueChunk メソッドを使用して、大規模なデータ ストリームを処理できます。 このメソッドは、値全体に 1 つの文字列を割り当てるのではなく、一度に少数の文字を読み取ります。

  • 一意のローカル名、名前空間、またはプレフィックスが多数含まれる XML ドキュメントを読み取ると、問題が発生する可能性があります。 XmlReaderから派生したクラスを使用していて、各項目のLocalNamePrefix、またはNamespaceURIプロパティを呼び出すと、返された文字列がNameTableに追加されます。 NameTableが保持するコレクションのサイズが小さくなり、文字列ハンドルの仮想メモリ リークが発生することはありません。 これに対する軽減策の 1 つは、 NameTable クラスから派生し、最大サイズ クォータを適用することです。 ( NameTableの使用を防いだり、満杯になったときに NameTable を切り替えたりする方法はありません)。 もう 1 つの軽減策は、前述のプロパティの使用を回避し、可能な場合は IsStartElement メソッドで MoveToAttribute メソッドを使用することです。これらのメソッドは文字列を返さないため、NameTable コレクションをオーバーフィルする問題を回避します。

  • XmlReaderSettings オブジェクトには、ユーザー資格情報などの機密情報を含めることができます。 信頼されていないコンポーネントは、 XmlReaderSettings オブジェクトとそのユーザー資格情報を使用して、データを読み取る XmlReader オブジェクトを作成できます。 XmlReaderSettingsオブジェクトをキャッシュするとき、またはコンポーネント間でXmlReaderSettings オブジェクトを渡すときは注意してください。

  • 信頼されていないソースからの NameTableXmlNamespaceManagerXmlResolver オブジェクトなどのサポート コンポーネントを受け入れないでください。