Доступ к данным |Доступ к XML и реляционным данным | 2. Чтение и запись Xml Дальше »
2. Чтение и запись Xml
2.1. Чтение Xml с помощью XmlTextReader
 2.1.1. Проверка правильности Типов данных с помощью XmlTextReader
 2.1.2. Почему используется Pull-модель чтения Xml?
 2.1.3. Обработка необходимого свободного пространства в XmlTextReader
 2.1.4. Редактирование свойств XmlTextReader
 2.1.5. Матрица возможных сценариев для XmlTextReader
2.2. Запись Xml средствами XmlTextWriter
 2.2.1. Как XmlTextWriter генерирует хорошо сформированный (Well Formed) XML
 2.2.2. Работа с пространствами имён средствами XmlTextWriter

2. Чтение и запись Xml

Абстрактные классы System.Xml классифицируют поддержку XmlReader и XmlWriter, которые осуществляют чтение и запись XML. XmlReader обеспечивает быструю, non-cached отправку исключительно только потоков доступа к XML данным. XmlWriter обеспечивает быстрый, non-cached, forward-only путь генерации XML потоков, содержащих XML документы, которые соответствуют спецификации W3C Extensible Markup Language (XML) 1.0 и пространству имён спецификации XML. XmlTextReader и XmlTextWriter - конкретная реализация XmlReader и XmlWriter в пространстве имён System.Xml.

2.1. Чтение Xml с помощью XmlTextReader

Класс XmlTextReader получает XML данные (используя механизм forward-only) от объекта поток, объекта TextReader класс или URL (который идентифицирует Web сайт или локальный файл).
XmlTextReader имеет следующие методы и свойства:

· Чтение Xml контента, когда содержание доступно полностью, как в случае текстового Xml файла.
· Чтение Xml контента, поскольку он стал доступен (например, открылся поток на активную выдачу последних изменений).
· Чтение индивидуальных компонент Xml текста, основанное на типе данных этих компонент. Например, есть строго типизированные методы, которые читают: 16/32/64 битные целые числа, символы, boolean, даты, валюты, и другие типы.
· Чтение атрибут узла.
· Перемещение по входному тексту или потоку.
· Тэги заголовка, пространства имён, и объекты.
· Исполнение схем и DTD проверок правильности ввода.

2.1.1. Проверка правильности Типов данных с помощью XmlTextReader

Проверка правильности типов данных выполняется в течение синтаксического анализа XDR или XSD схем, а также для DTD. Если это доступно, используется XmlUrlResolver, чтобы загрузить внешний DTD или схемы, которые требуются для такой проверки.
DTD или схема могут определять значения по умолчанию для атрибутов. Например:

<!ATTLIST e a CDATA "123">

Если атрибут "a" у элемента "e" не определен в Xml потоке, то ему нужно дать значение по умолчанию "123". Заданные по умолчанию атрибуты возвращаются так же, как и обычные атрибуты с тем отличием, что являющийся заданным по умолчанию атрибут возвратит "true" из свойства IsDefault.

2.1.2. Почему используется Pull-модель чтения Xml?

XmlReader использует "pull" модель для чтения XML. "Pull" представляет "Simple API for XML" (SAX) или event-driven модель, которая также является наиболее типичной в применении.
Синтаксический анализатор, использующий push-модель, размещает события прикладной программы, определяющие наименование элементов, атрибут, комментарии и так далее. Если синтаксический анализатор использует pull-модель, прикладная программа перемещает узлы механизма чтения, аналогично чтению потока. Pull-модель обеспечивает следующие преимущества:

Характеристика Описание
Упрощенное управление состоянием (Simplified state management) Обработчик контента Push-model должны применять очень сложное состояние своего механизма, которое при использовании Pull-model очень упрощается, за счёт управления состоянием естественным, сверху вниз, путём исполнения процедур.
Множественные входные потоки (Multiple input streams) Pull-model предоставляет возможность пользователю соединять вместе множественные входные потоки. Выполнение этого в Push-model почти невозможно.
Тест иерархического представления (Layering test) Push-model легко реализуется синтаксическим анализатором Pull-model, но не наоборот.
Подсказки клиента (Hints from client) Может быть разработан такой Pull-model API, который предоставит возможность пользователю давать подсказки синтаксическому анализатору о том, что его ожидает на следующем шаге, и давать возможность синтаксическому анализатору оптимизировать это шаг. Может быть добавлена поддержка типов данных тогда, когда пользователь знает, например, что следующая строка является целым числом, синтаксический анализатор сможет анализировать целое число из его буфера, вместо возвращения строки, которая впоследствии будет отброшена, что замедлит скорость исполнения прикладной программы (обработка мусора).
Предотвращение появления дополнительных копий (Avoids extra copy) Pull-model дает возможность пользователю обеспечить синтаксический анализатор буфером для записи строк. Это позволяет избегает дополнительных копий из буфера синтаксического анализатора в объект строки, который будет, в этом случае, помещен в буфер пользователя.
Пропустит что-либо (Skipping things) Push-model должна разместить на всякий случай всё, что Вы могли бы запросить, включая все атрибуты, комментарии, текст, незаполненное пространство, и т.д. В Pull-model, пользователь перемещает только то, что требуется. Если пользователь, например, не читает атрибуты, то значения атрибут не должны быть расширением сущности, строковыми значениями, именованными составляющими. Это позволяет строить высоко эффективные прикладные программы уровня передачи Xml сообщений.

2.1.3. Обработка необходимого свободного пространства в XmlTextReader

Свободное, не заполненное пространство (пробелы, символы табуляции, новые и пустые строки) между элементами классифицируются двумя способами:
- Необходимое, не заполненное пространство - любое не заполненное пространство, которое должно быть сохранено в конечном документе.
- Не значащее, не заполненное пространство - незаполненное пространство, не предполагаемое для сохранения в конечном документе (часто, включаемое для повышения удобочитаемости).

Следующий ниже пример представляет необходимое, не заполненное пространство как звездочки (*), а не значащее, не заполненное пространство как точки (.), что бы продемонстрировать их отличие. Символы newline также иллюстрированы соответственно как звездочки или точки.

<!DOCTYPE test [
<!ELEMENT test (item|bar)*>   <-- element content model -->
<!ELEMENT item (item*)>   <-- element content model -->
<!ATTLIST item xml:space (default|preserve) #IMPLIED>
<!ELEMENT bar (#PCDATA|b|i)*>   <-- mixed content model -->
<!ELEMENT b (#PCDATA)>   <-- mixed content model -->
<!ELEMENT i (#PCDATA)>   <-- mixed content model -->
]>.
<test>.
....<item>.
........<item xml:space="preserve">*
************<item/>*
********</item>.
....</item>.
....<bar>*
********<b>This<b>*
********<i>is</i>*
********<b>a test</b>*
****</bar>.
</test>.

Необходимое, не заполненное пространство возвращается, как тип узла "SignificantWhitespace", принимая во внимание, что не значащее, незаполненное пространство возвращается только, как "Whitespace". Для получения дополнительной информации, см. раздел № 2.10 в спецификации W3C Extensible Markup Language (Xml) 1.0 (http://www.w3.org/TR/1998/REC-xml-19980210#sec-white-space).

2.1.4. Редактирование свойств XmlTextReader

Представленная ниже таблица показывает, как правильно устанавливать свойства перед запуском на исполнение операции чтения. Единственное свойство, которое не может быть отредактировано после первой операции чтения, это свойство Namespace (пространство имён). XmlReader разработан так, чтобы бы исключить зависимость от установленных свойств, и что бы не было никаких зависимостей между свойствами. Вы выбираете комбинацию параметров настройки свойств, которая лучше всего соответствует вашим прикладным требованиям. Например, если Validation (проверка правильности) установлена в 'Auto' и Entity handling (обработка сущности) установлена в 'Ignore', в следствии чего подразумевается, что сущности не проверяются. Это только означает, что механизм чтения будет генерировать выходной поток сущностей, не раскрывая его и т.д., но ошибки, вследствие проверок правильности, всё же удут выдаваться.

Свойство Возможность установки значения
после операции чтения
Когда это значение будет учтено
Whitespace Да После следующей операции чтения
Validation Да После следующей операции чтения
EntityHandling Да После следующей операции чтения
Normalization Да После следующей операции чтения
Namespaces Нет Нет данных.
XmlResolver Да Эффективно после следующей операции чтения

Если EntityHandling установлено в 'IgnoreEntites', и Normalization установлено в 'true', то установка EntityHandling имеет приоритет относительно сущностей атрибут символа. Сущность атрибут символа никогда не раскрывается, если EntityHandling - 'IgnoreEntites'.

2.1.5. Матрица возможных сценариев для XmlTextReader

Представленная ниже таблица показывает, как различные свойства XmlTextReader могут использоваться для реализации различных сценариев.

Сценарии Validation Callback URIResolver Normalization
Самый быстрый - не полностью управляемый режим None null null false
Удовлетворяющий W3C
(только внутренний)1
None Не применим null true
Удовлетворяющий W3C
(внутренний и внешний)2
None Не применим Непустой указатель и все внешние сущности должны быть раскрыты true
Удовлетворяющий и согласованный
с DTD Auto или DTD
Не применим 3 Непустой указатель и все внешние сущности должны быть раскрыты true  
Хорошо сформированный и включающий проверку правильности схемы Auto (и не DTD) или Schema Не применим 3 Непустой указатель и все внешние сущности должны быть раскрыты true

1. Обеспечивает заданные по умолчанию атрибуты и сущности, но только из внутреннего подмножества, не выбирает никакие внешние сущности.
2. Обеспечивает заданные по умолчанию атрибуты и сущности из внутреннего подмножества, а также из внешнего DTD и сущностей.
3. Если возвращается не нулевое значение, все ошибки проверки правильности возвращаются через callback. Если возвращается нулевое значение, первые ошибки по результатам проверки правильности будут в XmlException. Это активирует состояние ошибки, после чего синтаксический анализ XmlTextReader дальше не сможет продолжаться.

2.2. Запись Xml средствами XmlTextWriter

Класс XmlTextWriter определяет методы, которые пишут XML данные non-cached и forward-only способом в потоки, файлы и объекты TextWriter. Класс XmlTextWriter расширяет абстрактный класс XmlWriter. Объект XmlWriter помогает составлять XML документы, которые соответствуют спецификации W3C Extensible Markup Language (http://www.w3.org/TR/1998/REC-xml-19980210) и пространству имён из спецификации XML (http://www.w3.org/TR/REC-xml-names/).
XmlTextWriter имеет следующие методы и свойства:
- Запись синтаксически правильного Xml, как-то: декларации и номера версий, типы документа, специфические метки начала и конца с обрамлением пространства имён, комментарии, атрибуты, CDATA, обработка команд, сущности и ссылки объектов, строки текста, необработанный - маркированный текст (полезный при отправке по неправильному адресу сегментов Xml).
- Кодировка текста из 64-битног и шестнадцатеричного в соответствующие ESC символы.
- Управление выводом, включая средства оповещения о состоянии вывода, записи множественных документов в один выходной поток, и очистки или закрытия вывода.
- Сообщает текущий префикс пространства имён, язык, или контекст пространства имён.
- Запись правильных имён, составных имён, и названий лексем.
- Запись значений или атрибут с определенными типами данных, например, булевы значения, дата и время, десятичные числа, единичной и двойной точности с плавающей запятой, и 16-битные, 32-битные или 64-битные целые числа.
- Полное копирования ввода в вывод.
- Определение состояния или форматирование, кодирование, выравнивание или конвертация типов данных в метки.

2.2.1. Как XmlTextWriter генерирует хорошо сформированный (Well Formed) XML

Рассмотрим, какую функциональность предоставляет XmlTextWriter для помощи в генерации well-formed XML документов и обеспечения соответствия спецификации W3C Extensible Markup Language (XML) 1.0 (http://www.w3.org/TR/1998/REC-xml-19980210):
- Для WriteAttribute, если используются двойные кавычки, XmlTextWriter заменит двойных кавычки в тексте (контенте) значениями атрибут &quot;. Если используются одинарные кавычки, они будут заменены на значения атрибут &apos;.
- Для WriteString, XmlTextWriter вычленяет специальные символы, заменяя их на &amp; &lt; &gt; и на сущности цифровых символов, когда это требуется. Если запрос находится в контексте значений атрибут, то также будут выводиться &apos; и &quot;. Символьные значения 0x-0x1F закодированы как сущности цифр от &#0; и до &#x1f;, кроме символов незаполненного пространства 0x9, 0x10 и 0x13.
- Для WriteBase64, XmlTextWriter так кодирует эти base64 значения, что бы они могли быть прочитаны с использованием ReadBinary для XmlReader.
- Генерация префикса пространства имён и генерация декларации xmlns (см. Namespace Handling by XmlTextWriter).
- Гарантирует, что элементы xml написаны в правильном порядке. Например, не допускает существование атрибут вне элемента, блока CDATA внутри атрибута, или существование нескольких корневых элементов. Также гарантируется, что декларация - Значения и формат атрибута xml:space проверены. Следующий пример верен:
w.WriteAttribute("xml:space", "", "preserve");
Допустимые значения - "default" и "preserve". Если параметр - не принимает ни одно из этих значений, ArgumentException будет сброшен.
- Формат атрибута xml:lang проверен. Следующий пример не верен:
w.WriteAttribute("xml:lang", "", "U.S.A.");
В этом случае ArgumentException будет сброшен, потому что значение. "U.S.A" не соответствует BNF для идентификаторов языка как определено в IETF RFC 1766. BNF должны быть следующие:
Language-Tag = Primary-tag ( "-" Subtag )*
Primary-tag = 1*8ALPHA
Subtag = 1*8ALPHA
ALPHA = любые ASCII алфавитно-цифровые значения в диапазонах 65-90 и 97-122.
Здесь подразумевается одна первичная метка и ноль или большее количество вторичных меток, разделённых символом "-", где первичная метка и вторичные метки могут иметь от 1 до 8 символов ALPHA ASCII. Фактически, до сих пор коды языков и значения кодов стран/областей не утверждены. Чтобы определить код языка, поддерживаемый вашей системой, используйте класс System.Globalization.CultureInfo.
- Если Close() даёт в результате недопустимый xml документ, InvalidOperationException будет сброшен.

XmlWriter не проверяет следующее:

- Недопустимые элементы и имена атрибут символов.
- Символы Unicode, которые не соответствуют кодировке, не проявившиеся как символьные сущности.
- Дубли атрибут не могут быть обнаружены.
- Символы в DOCTYPE pubid или sysid не проверяются.
- Newlines в значении атрибут записываются, как и &#A;, так что они сохраняются в соответствии с принятыми в W3C значениями атрибут, нормализующими синтаксический анализатор, на подобии XmlTextReader.

2.2.2. Работа с пространствами имён средствами XmlTextWriter

XmlTextWriter поддерживает стек пространства имён, соответствующий всем пространствам имён, определенных текущим стеком элемента. Например:

XmlTextWriter w = new XmlTextWriter(Console.Out);
w.WriteStartElement("root","urn:1");
w.WriteStartElement("item","urn:1");
w.WriteEndElement();
w.WriteEndElement();
w.Close();

В результате получим следующее:

<root xmlns="urn:1"><item/></root>

Обратите внимание, что декларация пространства имён для вложенного элемента item не выполняется повторно.

Генерация префиксов

Если атрибутам установлена связь с пространством имён URI, то они должны иметь префикс, соответствующий "Namespace Defaulting" (http://www.w3.org/TR/1999/REC-xml-names-19990114/defaulting) в пространствах имён W3C спецификации Xml, что соответствует следующему коду:

XmlTextWriter w = new XmlTextWriter(Console.Out);
w.WriteStartElement("root");
w.WriteAttribute("foo","urn:1", "123");
w.WriteEndElement();
w.Close();

В результате получим следующее:

<root n1:foo="123" xmlns:n1="urn:1"/>

Примечание: Это справедливо, даже если корневой элемент связан с заданным по умолчанию пространством имён "URN:1". Префиксы именованы, как n{i}, где i начинается с 1. Индекс запускается для каждого следующего элемента, так что, если вложенный, порождённый элемент также нуждается в сгенерированном префиксе, "n1" будут использоваться повторно. Такая организация помогает автору генерировать канонический Xml, соответствующий "W3C Canonical XML Version 1.0 specification". (http://www.w3.org/TR/sec-namespaces).

Описание деклараций пространства имён вручную

Вы также можете включить код декларации пространства имён вручную. Это полезно, если Вы знаете, как лучше оптимизировать число деклараций пространства имён. Делается это следующим образом:

w.WriteStartElement("root");
w.WriteAttribute("xmlns", "x", null, "urn:1");
    w.WriteStartElement("item","urn:1");
    w.WriteEndElement();
    w.WriteStartElement("item","urn:1");
    w.WriteEndElement();
w.WriteEndElement();

В результате получим следующее:

<root xmlns:x="urn:1">
    <x:item/>
    <x:item/>
</x:root>

В этом примере, декларация пространства имён сдвигается к корневому элементу, чтобы избежать дублирования для двух порожденных элементов. Элементы также приобретает префикс от декларации пространства имён.

Отмена деклараций пространства имён

Вы можете вручную отменять пространство имён, связанное с данным префиксом следующим образом:

w.WriteStartElement("x","node","123");
w.WriteAttribute("xmlns","x",null,"bar");

В результате получим следующее:

<x:node xmlns:x="bar"/>

Заметьте, что "bar" отменяет первоначальное пространство имён URI "123". Это добавляет гибкости для распределённых приложений.

Определение префиксов

Вы можете передавать префикс для использования. Для этого существует два способа. Первый, явно использует методы, которые вызывают префикс:

XmlTextWriter w = new XmlTextWriter(Console.Out);
w.WriteStartElement("x","root","urn:1");
    w.WriteStartElement("y","item","urn:1");
    w.WriteEndElement();
w.WriteEndElement();
w.Close();

В результате получим следующее:

<x:root xmlns:x="urn:1"><y:item xmlns:y="urn:1"/></x:root>

Заметьте, что оба префикса "x" и "y" сохранились.

Обратите внимание: Определение префикса и пустого пространства имён URI нарушает Section 2 W3C пространства имён в спецификации Xml (http://www.w3.org/TR/1999/REC-xml-names-19990114/ns-decl).

Множественные декларации пространств имён

Когда есть множественные декларации пространства имён, отображающие различные префиксы одному и тому же URN, XmlWriter выбирает самый близкий стек деклараций пространства имён следующим образом:

XmlTextWriter w = new XmlTextWriter(Console.Out);
w.WriteStartElement("x","root","urn:1");
    w.WriteStartElement("y","item","urn:1");
        w.WriteAttribute("foo","urn:1","bar");
    w.WriteEndElement();
w.WriteEndElement();
w.Close();

В этом случае, запрос WriteAttribute не определил никакой префикс (так что Вы можете выбирать любые префиксы). XmlWriter находит сначала префикс "y" и использует его, чтобы воспроизвести следующее:

<x:root xmlns:x="urn:1">
    <y:item y:foo="bar" xmlns:y="urn:1"/>
</x:root>

Возможности разрешения конфликтов

Любая из предшествующих процедур может порождать конфликты, для разрешения которых XmlWriter генерирует дополнительные префиксы. В следующем примере атрибут будет иметь тот же самый префикс, что и элемент, но пространства имён будут отличаться:

w.WriteStartElement("x","root","urn:1");
    w.WriteAttribute("x","foo","urn:2", "123");
w.WriteEndElement();

Атрибуту "foo" присваивается новый префикс следующим образом:

<x:root n1:foo="123" xmlns:n1="urn:2" xmlns:x="urn:1"/>

Эти конфликты могут случаться только в атрибутах. Для вложенных элементов, новая декларация пространства имён может просто переопределяться, как у двойных префиксные областей. Например, рассмотрим следующий код:

w.WriteStartElement("x","root","urn:1");
    w.WriteStartElement("x","item","urn:2");
    w.WriteEndElement();
w.WriteEndElement();

В результате получим следующее:

<x:root xmlns:x="urn:1">
    <x:item xmlns:x="urn:2"/>

Доступ к данным |Доступ к XML и реляционным данным | 2. Чтение и запись Xml Дальше »
Скачать электронную карту Ангарска бесплатно
Сайт управляется системой uCoz