Поделиться через


Класс System.Xml.XmlReader

В этой статье приводятся дополнительные замечания к справочной документации по этому API.

XmlReader предоставляет доступ только для чтения к XML-данным в документе или потоке. Этот класс соответствует рекомендациям W3C Extensible Markup Language (XML) 1.0 (четвертый выпуск) и пространства имен в XML 1.0 (третьем выпуске ).

XmlReader методы позволяют перемещаться по XML-данным и читать содержимое узла. Свойства класса отражают значение текущего узла, которое находится в расположении средства чтения. Значение ReadState свойства указывает текущее состояние средства чтения XML. Например, свойство устанавливается ReadState.Initial методом XmlReader.Read и ReadState.Closed методом XmlReader.Close . XmlReaderтакже обеспечивает соответствие данным проверка и проверку на основе DTD или схемы.

XmlReader использует модель извлечения для получения данных. Эта модель:

  • Упрощает управление состоянием естественным, сверху вниз процедурным уточнением.
  • Поддерживает несколько входных потоков и слоев.
  • Позволяет клиенту предоставить средство синтаксического анализа буферу, в который строка записывается напрямую, и поэтому не требуется дополнительная копия строки.
  • Поддерживает выборочную обработку. Клиент может пропускать элементы и обрабатывать интересующие приложения элементы. Вы также можете заранее задать свойства для управления процессом обработки XML-потока (например, нормализация).

Создание средства чтения XML

Create Используйте метод для создания экземпляраXmlReader.

Хотя .NET предоставляет конкретные реализации класса, такие как XmlTextReaderXmlNodeReader, и XmlValidatingReader классы, рекомендуется использовать специализированные классы XmlReader только в следующих сценариях:

  • Если вы хотите считывать поддерев XML DOM из XmlNode объекта, используйте XmlNodeReader класс. (Однако этот класс не поддерживает проверку DTD или схемы.)
  • Если необходимо развернуть сущности по запросу, вы не хотите нормализованное текстовое содержимое или не хотите возвращать атрибуты по умолчанию, используйте XmlTextReader класс.

Чтобы указать набор функций, которые необходимо включить в средстве чтения XML, передайте System.Xml.XmlReaderSettings объект в Create метод. Можно использовать один System.Xml.XmlReaderSettings объект для создания нескольких читателей с одной и той же функциональностью или изменения System.Xml.XmlReaderSettings объекта для создания нового средства чтения с другим набором функций. Вы также можете легко добавлять функции в существующее средство чтения.

Если вы не используете System.Xml.XmlReaderSettings объект, используются параметры по умолчанию. Дополнительные сведения см. на Create странице справки.

XmlReader вызывает XmlException ошибки синтаксического анализа XML. После возникновения исключения состояние средства чтения не предсказуемо. Например, тип сообщаемого узла может отличаться от фактического типа узла текущего узла. ReadState Используйте свойство, чтобы проверка, находится ли средство чтения в состоянии ошибки.

Проверка XML-данных

Чтобы определить структуру XML-документа и его связей элементов, типов данных и ограничений содержимого, используйте схему определения типа документа (DTD) или языка определения схемы XML (XSD). Xml-документ считается хорошо сформированным, если он соответствует всем синтаксическим требованиям, определенным рекомендацией W3C XML 1.0. Считается допустимым, если он хорошо сформирован, а также соответствует ограничениям, определенным его DTD или схемой. (См. раздел Часть 1 схемы W3C XML: структуры и часть 2 схемы W3C XML: рекомендации по типам данных.) Поэтому, хотя все допустимые XML-документы хорошо сформированы, не все хорошо сформированные XML-документы являются допустимыми.

Данные можно проверить на основе DTD, встроенной схемы XSD или схемы XSD, хранящейся в XmlSchemaSet объекте (кэше); эти сценарии описаны на эталонной Create странице. XmlReader не поддерживает проверку схемы XML-Data Reduced (XDR).

В классе используются следующие параметры XmlReaderSettings , чтобы указать, какой тип проверки поддерживается XmlReader экземпляром.

Использование этого XmlReaderSettings элемента Чтобы указать
Свойство DtdProcessing Разрешить обработку DTD. По умолчанию обработка определения DTD не разрешается.
Свойство ValidationType Следует ли читателю проверять данные и какой тип проверки выполнять (DTD или схема). По умолчанию проверка данных не выполняется.
Событие ValidationEventHandler Обработчик событий для получения сведений о событиях проверки. Если обработчик события не предоставлен, при первой ошибке проверки вызывается исключение XmlException.
Свойство ValidationFlags Дополнительные параметры проверки с помощью XmlSchemaValidationFlags элементов перечисления:

- AllowXmlAttributes- Разрешить XML-атрибуты (xml:*) в документах экземпляров, даже если они не определены в схеме. Атрибуты проверяются на основе их типов данных. См. справочную XmlSchemaValidationFlags страницу для параметра, используемого в определенных сценариях. (Отключено по умолчанию.)
- ProcessIdentityConstraints --Обработка ограничений удостоверений (xs:ID, xs:IDREF, xs:key, xs:keyref) xs:uniqueобнаружена во время проверки. (Включено по умолчанию.)
- ProcessSchemaLocation--Process schemas, заданные атрибутом или xsi:noNamespaceSchemaLocation атрибутомxsi:schemaLocation. (Включено по умолчанию.)
- ProcessInlineSchema- Обработка встроенных XML-схем во время проверки. (Отключено по умолчанию.)
- ReportValidationWarnings--Отчет о событиях, если возникает предупреждение проверки. Предупреждение обычно формируется при отсутствии определения DTD или схемы XML для проверки конкретного элемента или атрибута. Параметр ValidationEventHandler используется для уведомления. (Отключено по умолчанию.)
Schemas XmlSchemaSet, используемый при проверке данных.
Свойство XmlResolver Разрешение XmlResolver и доступ к внешним ресурсам. Это может включать внешние сущности, такие как DTD и схемы, и любые xs:include или xs:import элементы, содержащиеся в схеме XML. Если вы не указываете, XmlResolverXmlReader использует значение по умолчанию XmlUrlResolver без учетных данных пользователя.

Соответствие данным

Средства чтения XML, созданным Create метод следующие предварительные требования соответствия по умолчанию:

  • Новые строки и значение атрибута нормализуются в соответствии с рекомендацией W3C XML 1.0.

  • Все сущности автоматически развернуты.

  • Атрибуты по умолчанию, объявленные в определении типа документа, всегда добавляются, даже если средство чтения не проверяет.

  • Объявление префикса XML, сопоставленного с правильным URI пространства имен XML, разрешено.

  • Имена нотаций в одном NotationType объявление атрибута и NmTokens в одном Enumeration объявление атрибута отличаются.

Используйте эти XmlReaderSettings свойства, чтобы указать тип соответствия проверка, которые требуется включить:

Использование этого XmlReaderSettings свойства По По умолчанию
Свойство CheckCharacters Включите или отключите проверка для следующих компонентов:

— Символы находятся в диапазоне юридических XML-символов, как определено в разделе 2.2 Символов рекомендации W3C XML 1.0.
— Все имена XML допустимы, как определено разделом 2.3 Common Syntactic Constructs в рекомендации W3C XML 1.0.

Если для этого свойства задано значение true (по умолчанию), исключение возникает, XmlException если XML-файл содержит недопустимые символы или недопустимые XML-имена (например, имя элемента начинается с числа).
Включено проверка символов и имен.

false Параметр CheckCharacters отключения проверка символов для ссылок на сущности символов. Если средство чтения обрабатывает текстовые данные, всегда проверка допустимые имена 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 Считывает первый узел и перемещает поток по одному узлу за раз. Такие вызовы обычно выполняются внутри while цикла.

NodeType Используйте свойство, чтобы получить тип (например, атрибут, комментарий, элемент и т. д.) текущего узла.
Skip Пропустите дочерние элементы текущего узла и перейдите к следующему узлу.
MoveToContent и MoveToContentAsync. Пропустите узлы, отличные от содержимого, и перейдите к следующему узлу содержимого или к концу файла.

Узлы, отличные от содержимого, включают ProcessingInstruction, DocumentType, CommentWhitespaceи SignificantWhitespace.

Узлы содержимого включают текст, отличный от пробелов, CDATAEntityReference иEndEntity.
ReadSubtree Считывает элемент и все его дочерние элементы и возвращает новый XmlReader набор ReadState.Initialэкземпляров.

Этот метод полезен для создания границ вокруг XML-элементов; Например, если вы хотите передать данные другому компоненту для обработки, и вы хотите ограничить объем данных, к которым может получить доступ компонент.

См. XmlReader.Read справочную страницу для примера перехода по текстовому потоку по одному узлу за раз и отображения типа каждого узла.

В следующих разделах описывается, как считывать определенные типы данных, такие как элементы, атрибуты и типизированные данные.

Чтение XML-элементов

В следующей таблице перечислены методы и свойства, предоставляемые классом XmlReader для обработки элементов. После того, как объект XmlReader позиционируется на элементе, свойства узла, например Name, отражают значения этого элемента. Кроме описанных ниже членов для обработки элементов процесса могут также использоваться любые методы и свойства класса XmlReader. Например, для чтения содержимого элемента используется метод ReadInnerXml.

Примечание.

См. раздел 3.1 рекомендации W3C XML 1.0 по определениям начальных тегов, конечных тегов и пустых тегов элементов.

Использование этого XmlReader элемента По
IsStartElementМетод Проверьте, является ли текущий узел тегом запуска или пустым тегом элемента.
ReadStartElementМетод Убедитесь, что текущий узел является элементом и перемещает средство чтения на следующий узел (вызовы IsStartElementRead, за которыми следует).
ReadEndElementМетод Убедитесь, что текущий узел является конечным тегом и перенаследуйте читателя к следующему узлу.
ReadElementStringМетод Чтение элемента только для текста.
ReadToDescendantМетод Переведите средство чтения XML на следующий дочерний элемент, имеющий указанное имя.
ReadToNextSiblingМетод Переведите средство чтения XML на следующий элемент с общим значением, который имеет указанное имя.
Свойство IsEmptyElement Проверьте, имеет ли текущий элемент тег конечного элемента. Например:

- <item num="123"/> (IsEmptyElement имеет trueзначение .)
- <item num="123"> </item> ( имеетIsEmptyElementfalseзначение , хотя содержимое элемента пусто.)

Пример чтения текстового содержимого элементов см. в методе ReadString . В следующем примере элементы обрабатываются с помощью 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

Чтение XML-атрибутов

Атрибуты XML чаще всего находятся в элементах, но они также разрешены в объявлениях XML и узлах типов документов.

При расположении на узле MoveToAttribute элемента метод позволяет просматривать список атрибутов элемента. Обратите внимание, что после MoveToAttribute вызова свойства узла, такие как Name, NamespaceURIи Prefix отражают свойства этого атрибута, а не свойства элемента, к которому принадлежит атрибут.

Класс XmlReader предоставляет эти методы и свойства для чтения и обработки атрибутов элементов.

Использование этого XmlReader элемента По
Свойство HasAttributes Проверьте, имеет ли текущий узел какие-либо атрибуты.
Свойство AttributeCount Получите количество атрибутов текущего элемента.
MoveToFirstAttributeМетод Перейдите к первому атрибуту в элементе.
MoveToNextAttributeМетод Перейдите к следующему атрибуту в элементе.
MoveToAttributeМетод Перейдите к указанному атрибуту.
GetAttribute метод или Item[] свойство Получите значение указанного атрибута.
Свойство IsDefault Проверьте, является ли текущий узел атрибутом, созданным из значения по умолчанию, определенного в DTD или схеме.
MoveToElementМетод Перейдите к элементу, которому принадлежит текущий атрибут. Используйте этот метод, чтобы вернуться к элементу после перехода по его атрибутам.
ReadAttributeValueМетод Синтаксический анализ значения атрибута на один или несколько 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("  {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

В этом примере метод в цикле while используется MoveToNextAttribute для перехода по атрибутам.

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

Чтение атрибутов на узлах объявления XML

При расположении средства чтения XML на узле Value объявления XML свойство возвращает версию, автономную и кодировку в виде одной строки. XmlReaderобъекты, созданные методомCreate, классом и XmlValidatingReader классом, предоставляют версию, XmlTextReader автономные и кодирующие элементы в виде атрибутов.

Чтение атрибутов на узлах типа документа

При расположении средства чтения 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 использует правила, определенные рекомендацией по схеме XML W3C 2.

Использование этого XmlReader метода Возврат этого типа СРЕДЫ CLR
ReadContentAsBoolean и ReadElementContentAsBoolean Boolean
ReadContentAsDateTime и ReadElementContentAsDateTime DateTime
ReadContentAsDouble и ReadElementContentAsDouble Double
ReadContentAsLong и ReadElementContentAsLong Int64
ReadContentAsInt и ReadElementContentAsInt Int32
ReadContentAsString и ReadElementContentAsString String
ReadContentAs и ReadElementContentAs Тип, указанный с параметром returnType
ReadContentAsObject и ReadElementContentAsObject. Наиболее подходящий тип, указанный свойством 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: {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

Выходные данные:

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

Асинхронное программирование

XmlReader Большинство методов имеют асинхронные аналоги, имеющие Async в конце их имен методов. Например, асинхронный эквивалент ReadContentAsObject равен ReadContentAsObjectAsync.

Следующие методы можно использовать с асинхронными вызовами методов:

В следующих разделах описано асинхронное использование методов, которые не имеют асинхронных аналогов.

Метод 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, если вас беспокоит проблема с отказом в обслуживании или если вы работаете с ненадежными источниками. Обработка DTD отключена по умолчанию для XmlReader объектов, созданных методом Create .

    Если обработка DTD включена, то с помощью класса XmlSecureResolver можно ограничить ресурсы, доступные для объекта XmlReader. Вы также можете разработать приложение, чтобы обработка XML была ограниченной памятью и временем. Например, можно настроить ограничения времени ожидания в приложении ASP.NET.

  • XML-данные могут содержать ссылки на внешние ресурсы, например файл схемы. По умолчанию внешние ресурсы разрешаются с помощью XmlUrlResolver объекта без учетных данных пользователя. Это можно сделать еще более безопасным, выполнив одно из следующих действий.

  • Флаги ProcessInlineSchemaXmlReaderSettings проверки ProcessSchemaLocation объекта не задаются по умолчанию. Это позволяет защитить объект XmlReader от атак на основе схем при обработке XML-данных из ненадежного источника. Если эти флаги установлены, для разрешения расположения схем, обнаруженных в экземпляре документа в объекте XmlResolver, используется арбитр XmlReaderSettings объекта XmlReader. XmlResolver Если для свойства задано nullзначение, расположения схемы не разрешаются, даже если ProcessInlineSchema заданы флаги проверки.ProcessSchemaLocation

    Схемы, добавленные во время проверки, добавляют новые типы и могут изменить результат проверки документа. Поэтому следует разрешать только внешние схемы из доверенных источников.

    Мы рекомендуем отключить ProcessIdentityConstraints флаг при проверке недоверенных, больших XML-документов в сценариях высокой доступности для схемы с ограничениями удостоверений в значительной части документа. Этот флаг включен по умолчанию.

  • XML-данные могут содержать большое количество атрибутов, деклараций пространств имен, вложенных элементов и так далее, на обработку которых требуется значительное время. Чтобы ограничить размер входных данных, отправляемых в нее XmlReader, можно:

    • Ограничить размер документа, задав MaxCharactersInDocument свойство.

    • Ограничить количество символов, которые приводят к расширению сущностей, задав MaxCharactersFromEntities свойство.

    • Создайте пользовательскую IStream реализацию для объекта XmlReader.

  • Этот ReadValueChunk метод можно использовать для обработки больших потоков данных. Этот метод за раз считывает небольшое число символов, а не выделяет одну строку для всего значения.

  • При чтении XML-документа с большим количеством уникальных локальных имен, пространств имен или префиксов может возникнуть проблема. Если вы используете класс, производный от XmlReader, и вызываете LocalNamePrefixсвойство , или NamespaceURI свойство для каждого элемента, возвращаемая строка добавляется в NameTable. Коллекция, удерживаемая NameTable никогда не уменьшается, создавая утечку виртуальной памяти дескрипторов строк. Одним из способов устранения этой проблемы является наследование класса NameTable и применение максимальной квоты размера. (Нет способа предотвратить использование NameTableили переключиться, NameTable когда оно заполнено). Другое решение заключается в том, чтобы избежать использования свойств, упоминание и вместо этого использовать MoveToAttribute метод с IsStartElement методом, где это возможно; эти методы не возвращают строки и таким образом избежать проблемы переполнения NameTable коллекции.

  • Объекты XmlReaderSettings могут содержать конфиденциальные сведения, например учетные данные пользователей. Ненадежный компонент может использовать объект XmlReaderSettings и его учетные данные пользователя, чтобы создавать объекты XmlReader для считывания данных. Будьте осторожны при кэшировании XmlReaderSettings объектов или при передаче XmlReaderSettings объекта из одного компонента в другой.

  • Не следует принимать вспомогательные компоненты, например объекты NameTable, XmlNamespaceManager и XmlResolver, из ненадежных источников.