Работа с XML в .NET - Чтение документов с XmlValidatingReader
ОГЛАВЛЕНИЕ
Чтение документов с XmlValidatingReader
XmlValidatingReader обеспечивает проверку допустимости XML-документов на основе трех схем: XML Schema definition language (XSD), XML-Data Reduced (XDR) schema и DTD. XmlValidatingReader наследован от класса XmlReader и используется объекты класса XmlTextReader для получения XML-документа. Тип схемы устанавливается значением свойства ValidationType. Если же передать этому свойству значение ValidationType.None, то проверка производится не будет. По умолчанию значение свойства ValidationType равно ValidationType.Auto и тип схемы определяется автоматически.
В нашем примере мы используем схему XSD. Для ее создания мы загрузили в Visual Studio .NET XML файл с заказами, выбрали в контекстном меню пункты Create Schema, отметили как обязательные атрибуты дату и адрес для заказа и цену и название для товара и убрали значение из атрибута для целевого пространства имен. В итоге получился следующий XSD-файл.
<?xml version="1.0" ?>
<xs:schema id="Заказы" xmlns:mstns="http://tempuri.org/заказы.xsd"
xmlns="http://tempuri.org/заказы.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
attributeFormDefault="qualified" elementFormDefault="qualified">
<xs:element name="Заказы" msdata:IsDataSet="true" msdata:Locale="ru-RU" msdata:EnforceConstraints="False">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="Заказ">
<xs:complexType>
<xs:sequence>
<xs:element name="Товар" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="Название" form="unqualified" type="xs:string" use="required" />
<xs:attribute name="Цена" form="unqualified" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Адрес" form="unqualified" type="xs:string" use="required" />
<xs:attribute name="Дата" form="unqualified" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
Рассмотрим функцию, выполняющую проверку допустимости XML-документа с заказами на основе XSD-схемы.
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Файлы XML (*.xml)|*.xml";
if (dlg.ShowDialog() != DialogResult.OK)
return;
string file = dlg.FileName;
// получаем имя файла со схемой
dlg.Filter = "Файлы XSD (*.xsd)|*.xsd";
if (dlg.ShowDialog() != DialogResult.OK)
return;
string schema = dlg.FileName;
XmlValidatingReader readerVal = null;
orders.Clear();
try
{
XmlTextReader reader = new XmlTextReader(file);
reader.WhitespaceHandling = WhitespaceHandling.None; // пропускаем пустые узлы
readerVal = new XmlValidatingReader(reader);
readerVal.Schemas.Add("", schema);
readerVal.ValidationType = ValidationType.Schema;
readerVal.ValidationEventHandler += new ValidationEventHandler(ValidationEventHandle);
while (readerVal.Read())
if (readerVal.NodeType == XmlNodeType.Element)
if (readerVal.Name == "Заказ")
{
Order order = new Order(readerVal.GetAttribute("Адрес"), DateTime.Parse(readerVal.GetAttribute("Дата")));
// получаем товары в заказе
while (readerVal.Read() && readerVal.Name == "Товар")
order.AddGood(readerVal.GetAttribute("Название"), float.Parse(readerVal.GetAttribute("Цена")));
orders.Add(order);
}
ShowOrders();
}
catch (XmlException ex)
{
MessageBox.Show(ex.Message);
}
catch (Exception ex)
{
MessageBox.Show("Ошибка: " + ex.Message);
}
finally
{
if (readerVal != null)
readerVal.Close();
}
Вначале создаем объект XmlTextReader и передаем ему имя файла, указанное пользователем. Затем создаем XmlValidatingReader, который и будет отвечать за проверку допустимости документа. Затем добавляем XSD-схему из файла, указанного пользователем. Первым параметром в функции Add идет пространство имен (у нас передана пустая строка). Если же в вашем случае задано пространство имен, то его нужно определять из XSD-файла, получив значение атрибута targetNamespace у тега schema. Затем мы указываем тип схемы и определяем обработчик ValidationEventHandle события, который будет вызываться в случае возникновения ошибок или предупреждений. Тип события (ошибка или предупреждение) можно определить с помощью значения ValidationEventArgs.Severity, передаваемого обработчику. Также с помощью атрибутов можно получить дополнительную информацию об ошибке (ValidationEventArgs.Exception) и текстовое описание ошибки (alidationEventArgs.Message). Если мы не определим обработчик, то в случае определения недопустимости XML-документа будет возникать исключение XmlException, а предупреждения будут игнорироваться. На рисунке приведен диалог с сообщением об ошибке.
Как и в случае в XmlTextReader мы в цикле вызываем метод Read для перебора всех узлов документа. Сам процес разбора документа так же ни чем не будет отличать от работы с XmlTextReader.