C xmldocument: XmlDocument Класс (System.Xml) | Microsoft Docs

Содержание

C# и .NET | Работа с XML

XML-документы

Последнее обновление: 14.10.2019

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

Прежде чем перейти непосредственно к работе с XML-файлами, сначала рассмотрим, что представляет собой xml-документ и как он может хранить объекты, используемые в программе на c#.

Например, у нас есть следующий класс:


class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Company { get; set; }
}

В программе на C# мы можем создать список объектов класса User:


User user1 = new User { Name = "Bill Gates", Age = 48, Company = "Microsoft" };
User user2 = new User { Name = "Larry Page", Age = 42, Company = "Google" };
List<User> users = new List<User> { user1, user2 };

Чтобы сохранить список в формате xml мы могли бы использовать следующий xml-файл:


<?xml version="1. 0" encoding="utf-8" ?>
<users>
  <user name="Bill Gates">
    <company>Microsoft</company>
    <age>48</age>
  </user>
  <user name="Larry Page">
    <company>Google</company>
    <age>48</age>
  </user>
</users>

XML-документ объявляет строка <?xml version="1.0" encoding="utf-8" ?>. Она задает версию (1.0) и кодировку (utf-8) xml. Далее идет
собственно содержимое документа.

XML-документ должен иметь один единственный корневой элемент, внутрь которого помещаются все остальные элементы. В данном случае таким элементом является
элемент <users>. Внутри корневого элемента <users> задан набор элементов <user>. Вне корневого элемента
мы не можем разместить элементы user.

Каждый элемент определяется с помощью открывающего и закрывающего тегов, например, <user> и </user>, внутри которых
помещается значение или содержимое элементов. Также элемент может иметь сокращенное объявление: <user /> — в конце элемента помещается слеш.

Элемент может иметь вложенные элементы и атрибуты. В данном случае каждый элемент user имеет два вложенных элемента company и
age и атрибут name.

Атрибуты определяются в теле элемента и имеют следующую форму: название="значение". Например, <user name="Bill Gates">,
в данном случае атрибут называется name и имеет значение Bill Gates

Внутри простых элементов помещается их значение. Например, <company>Google</company> — элемент company имеет значение
Google.

Названия элементов являются регистрозависимыми, поэтому <company> и <COMPANY> будут представлять разные элементы.

Таким образом, весь список Users из кода C# сопоставляется с корневым элементом <users>, каждый объект User — с элементом <user>,
а каждое свойство объекта User — с атрибутом или вложенным элементом элемента <user>

Что использовать для свойств — вложенные элементы или атрибуты? Это вопрос предпочтений — мы можем использовать как атрибуты, так и вложенные элементы.
Так, в предыдущем примере вполне можно использовать вместо атрибута вложенный элемент:


<?xml version="1.0" encoding="utf-8" ?>
<users>
  <user>
	<name>Bill Gates</name>
    <company>Microsoft</company>
    <age>48</age>
  </user>
  <user>
	<name>Larry Page</name>
    <company>Google</company>
    <age>48</age>
  </user>
</users>

Теперь рассмотрим основные подходы для работы с XML, которые имеются в C#.

Прямая и обратная обработка XML — Руководства Web-разработчика

Иногда возникает необходимость в обработке XML и в последующей конвертации в древо DOM. Или наоборот, необходимо перевести древо DOM в XML. В этой статье рассмотрим объекты платформы web для обработки XML.

XMLSerializer
Сериализует деревья DOM, преобразуя их в строки, содержащие XML.
DOMParser
Создаёт дерево DOM, анализируя строку, содержащую XML, возвращая XMLDocument (en-US) или Document в зависимости от входящих данных.
XMLHttpRequest
Загружает контент из URL-адреса; Содержимое XML возвращается как объект XML Document с деревом DOM, построенным из самого XML.
XPath
Технология создания строк, содержащих адреса для определённых частей документа XML, и поиска узлов XML на основе этих адресов.

Использование одного из следующих подходов для создания XML-документа (который является экземпляром Document.

Parsing строк в дерево DOM

В этом примере фрагмент XML в строке преобразуется в дерево DOM с помощью DOMParser:

var sMyString = '<a><b>hey!</b></a>';
var oParser = new DOMParser();
var oDOM = oParser.parseFromString(sMyString, "application/xml");

console. log(oDOM.documentElement.nodeName == "parsererror" ? "error while parsing" : oDOM.documentElement.nodeName);

Parsing URL-addressable ресурсов в дерево DOM

Использование XMLHttpRequest

Вот пример кода, который считывает и анализирует XML-файл с URL-адресом в дереве DOM:

var xhr = new XMLHttpRequest();
xhr.onload = function() {
  dump(xhr.responseXML.documentElement.nodeName);
}
xhr.onerror = function() {
  dump("Error while getting XML.");
}
xhr.open("GET", "example.xml");
xhr.responseType = "document";
xhr.send();

Значение, возвращаемое в поле responseXML объекта xhr, является Document, созданным путём синтаксического анализа XML.

Если документ представляет собой HTML, приведённый выше код вернёт Document. Если документ XML, результирующий объект на самом деле является XMLDocument (en-US). Эти два типа по существу одинаковы; разница в основном историческая, хотя дифференциация имеет также некоторые практические преимущества.

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

Имея Document, вы можете сериализовать дерево DOM документа обратно в XML с помощью метода XMLSerializer.serializeToString ().

Используйте следующие подходы для сериализации содержимого XML-документа, созданного в предыдущем разделе.

Serializing DOM trees to strings

Сначала создайте дерево DOM, как описано в разделе Как создать дерево DOM. В качестве альтернативы используйте дерево DOM, полученное из XMLHttpRequest.

Чтобы сериализовать документ дерева DOM в текст XML, вызовите XMLSerializer.serializeToString ():

var oSerializer = new XMLSerializer();
var sXML = oSerializer.serializeToString(doc);

Serializing HTML documents

Если у вас есть модель DOM в виде HTML-документа, вы можете сериализовать её с помощью serializeToString (), но есть более простой вариант: просто используйте свойство Element. innerHTML (если вам нужны только потомки указанный узел) или свойство Element.outerHTML, если вам нужен узел и все его потомки.

var docHTML = document.documentElement.innerHTML;

В результате docHTML представляет собой DOMString, содержащий HTML-код содержимого документа; то есть содержимое элемента <body>.

Вы можете получить HTML, соответствующий <body> и его потомкам, с помощью этого кода:

var docHTML = document.documentElement.outerHTML;

PostgreSQL : Документация: 9.6: 8.13. Тип XML : Компания Postgres Professional

Тип xml предназначен для хранения XML-данных. Его преимущество по сравнению с обычным типом text в том, что он проверяет вводимые значения на допустимость по правилам XML и для работы с ним есть типобезопасные функции; см. Раздел 9.14. Для использования этого типа дистрибутив должен быть скомпилирован в конфигурации configure --with-libxml.

Тип xml может сохранять правильно оформленные «документы», в соответствии со стандартом XML, а также фрагменты «содержимого», определяемые как менее ограниченные «узлы документа» в модели данных XQuery и XPath. Другими словами, это означает, что во фрагментах содержимого может быть несколько элементов верхнего уровня или текстовых узлов. Является ли некоторое значение типа xml полным документом или фрагментом содержимого, позволяет определить выражение xml-значение IS DOCUMENT.

8.13.1. Создание XML-значений

Чтобы получить значение типа xml из текстовой строки, используйте функцию xmlparse:

XMLPARSE ( { DOCUMENT | CONTENT } value)

Примеры:

XMLPARSE (DOCUMENT '<?xml version="1.0"?><book><title>Manual</title><chapter>...</chapter></book>')
XMLPARSE (CONTENT 'abc<foo>bar</foo><bar>foo</bar>')

Хотя в стандарте SQL описан только один способ преобразования текстовых строк в XML-значения, специфический синтаксис PostgreSQL:

xml '<foo>bar</foo>'
'<foo>bar</foo>'::xml

тоже допустим.

Тип xml не проверяет вводимые значения по схеме DTD (Document Type Declaration, Объявления типа документа), даже если в них присутствуют ссылка на DTD. В настоящее время в PostgreSQL также нет встроенной поддержки других разновидностей схем, например XML Schema.

Обратная операция, получение текстовой строки из xml, выполняется с помощью функции xmlserialize:

XMLSERIALIZE ( { DOCUMENT | CONTENT } значение AS тип )

Здесь допустимый типcharacter, character varying или text (или их псевдонимы). И в данном случае стандарт SQL предусматривает только один способ преобразования xml в тип текстовых строк, но PostgreSQL позволяет просто привести значение к нужному типу.

При преобразовании текстовой строки в тип xml или наоборот без использования функций XMLPARSE и XMLSERIALIZE, выбор режима DOCUMENT или CONTENT определяется параметром конфигурации сеанса «XML option», установить который можно следующей стандартной командой:

SET XML OPTION { DOCUMENT | CONTENT };

или такой командой в духе PostgreSQL:

SET xmloption TO { DOCUMENT | CONTENT };

По умолчанию этот параметр имеет значение CONTENT, так что допускаются все формы XML-данных.

8.13.2. Обработка кодировки

Если на стороне сервера и клиента и в XML-данных используются разные кодировки символов, с этим могут возникать проблемы. Когда запросы передаются на сервер, а их результаты возвращаются клиенту в обычном текстовом режиме, PostgreSQL преобразует все передаваемые текстовые данные в кодировку для соответствующей стороны; см. Раздел 23.3. В том числе это происходит и со строковыми представлениями XML-данных, подобными тем, что показаны в предыдущих примерах. Обычно это означает, что объявления кодировки, содержащиеся в XML-данных, могут не соответствовать действительности, когда текстовая строка преобразуется из одной кодировки в другую при передаче данных между клиентом и сервером, так как подобные включённые в данные объявления не будут изменены автоматически. Для решения этой проблемы объявления кодировки, содержащиеся в текстовых строках, вводимых в тип xml, просто игнорируются и предполагается, что XML-содержимое представлено в текущей кодировке сервера. Как следствие, для правильной обработки таких строк с XML-данными клиент должен передавать их в своей текущей кодировке. Для сервера не важно, будет ли клиент для этого преобразовывать документы в свою кодировку, или изменит её, прежде чем передавать ему данные. При выводе значения типа xml не содержат объявления кодировки, а клиент должен предполагать, что все данные поступают в его текущей кодировке.

Если параметры запроса передаются на сервер и он возвращает результаты клиенту в двоичном режиме, кодировка символов не преобразуется, так что возникает другая ситуация. В этом случае объявление кодировки в XML принимается во внимание, а если его нет, то предполагается, что данные закодированы в UTF-8 (это соответствует стандарту XML; заметьте, что PostgreSQL не поддерживает UTF-16). При выводе в данные будет добавлено объявление кодировки, выбранной на стороне клиента (но если это UTF-8, объявление будет опущено).

Само собой, XML-данные в PostgreSQL будут обрабатываться гораздо эффективнее, когда и в XML-данных, и на стороне клиента, и на стороне сервера используется одна кодировка. Так как внутри XML-данные представляются в UTF-8, оптимальный вариант, когда на сервере также выбрана кодировка UTF-8.

Внимание

Некоторые XML-функции способны работать исключительно с ASCII-данными, если кодировка сервера не UTF-8. В частности, это известная особенность функции xpath().

8.13.3. Обращение к XML-значениям

Тип xml отличается от других тем, что для него не определены никакие операторы сравнения, так как чётко определённого и универсального алгоритма сравнения XML-данных не существует. Одно из следствий этого — нельзя отфильтровать строки таблицы, сравнив столбец xml с искомым значением. Поэтому обычно XML-значения должны дополняться отдельным ключевым полем, например ID. Можно также сравнивать XML-значения, преобразовав их сначала в текстовые строки, но заметьте, что с учётом специфики XML-данных этот метод практически бесполезен.

Из-за отсутствия операторов сравнения для типа xml, для столбца этого типа также нельзя создать индекс. Поэтому, когда требуется быстрый поиск в XML данных, обойти это ограничение можно, приведя данные к типу текстовой строки и проиндексировав эти строки, либо проиндексировав выражение XPath. Конечно сам запрос при этом следует изменить, чтобы поиск выполнялся по индексированному выражению.

Для ускорения поиска в XML-данных также можно использовать функции полнотекстового поиска в PostgreSQL. Однако это требует определённой подготовки данных, что дистрибутив PostgreSQL пока не поддерживает.

Файл import.xml





























































<КоммерческаяИнформация> Нет Главный элемент XML, которому подчинены все остальные. Хранит атрибуты с информацией о пространстве имен, версии схемы («ВерсияСхемы»), атрибуты даты формирования («ДатаФормирования») и служебной информации.
<Классификатор> <КоммерческаяИнформация> Элемент содержит информацию о группах, свойствах, типах цен, складах, единицах измерения. У него может быть один атрибут «СодержитТолькоИзменения», который в новой схеме обмена не используется, т. к. он бесполезен при пакетном обмене.
<Ид> <Классификатор> Элемент содержит информацию, о том, к какому инфоблоку относится информация этого классификатора.
<Наименование> <Классификатор> Элемент содержит информацию о наименовании инфоблока, к которому относится классификатор.
 
<Группы> <Классификатор> Элемент содержит информацию о группах (разделах) товаров.
<Группа> <Группы> Элемент содержит описание группы элемента.
<Ид> <Группа> Уникальный идентификатор группы (раздела).
<НомерВерсии> <Группа> Номер версии элемента группы (раздела).
<ПометкаУдаления> <Группа> Признак того, что элемент должен быть деактивирован.
<Наименование> <Группа> Наименование группы (раздела).
<Группы> <Группа> Подчиненный элемент, который хранит информацию о подчиненных группах. Структура элемента такая же, как <Группы> у <Классификатор>.
 
<Свойства> <Классификатор> Элемент содержит информацию о свойствах товаров.
<Свойство> <Свойства> Элемент содержит описание свойства элемента.
<Ид> <Свойство> Уникальный идентификатор свойства.
<НомерВерсии> <Свойство> Номер версии свойства.
<ПометкаУдаления> <Свойство> Признак того, что элемент должен быть деактивирован.
<Наименование> <Свойство> Наименование свойства.
<Внешний> <Свойство> Признак того, что свойство должно хранится в справочнике (highload-блоке). Если свойство хранит картинку, то признак должен принимать значение true.
<ТипЗначений> <Свойство> Тип значения свойства. Тип значения может быть: Строка, Число, Справочник.
<ВариантыЗначений> <Свойство> Элемент содержит информацию о вариантах значений, если тип свойства Справочник.
<Справочник> <ВариантыЗначений> Элемент содержит описание варианта значений свойства.
<ИдЗначения> <Справочник> Идентификатор варианта значения свойства.
<Значение> <Справочник> Значение варианта значения свойства.
<Картинка> <Справочник> Адрес картинки, если значение свойства хранит картинку.
<КодГруппыТоваров> <Предложение> Элемент содержит информацию о коде группы товаров, подлежащих обязательной

маркировке.


В РФ в соответствии с Федеральным законом от 31 декабря 2017 г. № 487-ФЗ товары подлежат обязательной маркировке, согласно утвержденному перечню.

Подробнее…



<Ширина> <Предложение> Элемент содержит информацию о ширине товара.
<Длина> <Предложение> Элемент содержит информацию о длине товара.
<Высота> <Предложение> Элемент содержит информацию о высоте товара.
 
<ТипыЦен> <Классификатор> Элемент содержит информацию о типах цен товаров.
<ТипЦены> <ТипыЦен> Элемент содержит описание типа цены элемента.
<Ид> <ТипЦены> Уникальный идентификатор типа цены.
<НомерВерсии> <ТипЦены> Номер версии типа цены.
<ПометкаУдаления> <ТипЦены> Признак того, что элемент должен быть деактивирован.
<Наименование> <ТипЦены> Наименование типа цены. Наименование типа цены должно быть уникально, иначе новое не добавится.
<Валюта> <ТипЦены> Валюта типа цены.
<Налог> <ТипЦены> Описание налогов для типа цены.
<Наименование> <Налог> Наименование налога.
<УчтеноВСумме> <Налог> Признак того, включен ли налог в стоимость товара.
 
<Склады> <Классификатор> Элемент содержит информацию о складах товаров.
<Склад> <Склады> Элемент содержит описание склада элемента.
<Ид> <Склад> Уникальный идентификатор склада.
<НомерВерсии> <Склад> Номер версии склада.
<ПометкаУдаления> <Склад> Признак того, что элемент должен быть деактивирован.
<Наименование> <Склад> Наименование склада.
 
<Каталог> <КоммерческаяИнформация> Элемент содержит информацию о товарах. У него может быть один атрибут «СодержитТолькоИзменения», который в новой схеме обмена не используется, т.к. он бесполезен при пакетном обмене.
<ИдКлассификатора> <Каталог> Идентификатор каталога.
<Ид> <Каталог> Идентификатор каталога.
<Наименование> <Каталог> Наименование каталога.
<Товары> <Каталог> Элемент содержит информацию о товарах.
<Товар> <Товары> Элемент содержит описание товара.
<Ид> <Товар> Уникальный идентификатор товара.
<НомерВерсии> <Товар> Номер версии товара.
<ПометкаУдаления> <Товар> Признак того, что элемент должен быть деактивирован.
<Артикул> <Товар> Артикул товара.
<Наименование> <Товар> Наименование товара.
<Описание> <Товар> Описание товара, попадающее в подробное описание товара.
<Картинка> <Товар> Элемент содержит информацию о картинках товара. Первый элемент является основной картинкой.
<БазоваяЕдиница> <Товар> Единица измерения товара.
<Группы> <Товар> Элемент содержит информацию о группах (разделах), в которых товар находится.
<Ид> <Группы> Идентификатор группы (раздела) товара.
<Изготовитель> <Товар> Элемент содержит информацию о изготовителе товара.
<Вес> <Товар> Вес товара.
<Ид> <Изготовитель> Идентификатор изготовителя.
<Наименование> <Изготовитель> Наименование производителя.
<ОфициальноеНаименование> <Изготовитель> Официальное наименование производителя.
<ЗначенияСвойств> <Товар> Элемент содержит информацию о свойствах товаров.
<ЗначенияСвойства> <ЗначенияСвойств> Элемент содержит описание свойства товара.
<Ид> <ЗначенияСвойства> Идентификатор свойства.
<Значение> <ЗначенияСвойства> Значение свойства.
<СтавкиНалогов> <Товар> Элемент содержит информацию о налогах товаров.
<СтавкаНалога> <СтавкиНалогов> Элемент содержит описание налога товара.
<Наименование> <СтавкаНалога> Наименование налога.
<Ставка> <СтавкаНалога> Ставка налога.
<ЗначенияРеквизитов> <Товар> Элемент содержит информацию о дополнительных данных товара. Есть предопределенные значения:

  • Файл — содержит информацию о местонахождении приложенного файла;
  • ОписаниеФайла — описание файла или картинки. Формат: <адрес картинки>#<описание>;
  • Вес — вес товара;
  • ОписаниеВФорматеHTML — содержит описание товара в формате HTML;
  • Полное наименование — информация о анонсе товара.
<ЗначениеРеквизита> <ЗначенияРеквизитов> Элемент содержит описание дополнительной информации товара.
<Наименование> <ЗначениеРеквизита> Наименование реквизита.
<Значение> <ЗначениеРеквизита> Значение реквизита.

Форматирование XML или Pretty Print XML в Java — Программирование на Java, Android

import org.w3c.dom.Document;

import org. w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.InputSource;

import org.xml.sax.SAXException;

 

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

import javax.xml.transform.OutputKeys;

import javax.xml.transform.Transformer;

import javax.xml.transform.TransformerFactory;

import javax.xml.transform.dom.DOMSource;

import javax.xml.transform.stream.StreamResult;

import javax.xml.xpath.XPath;

import javax.xml.xpath.XPathConstants;

import javax.xml.xpath.XPathFactory;

import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.io.StringWriter;

 

public class XmlStringFormatter {

    

    public static void main(String args[]) {

        // какая-то строка с неформатированным XML содержимым

        String xmlString = «<?xml version=\»1.0\» encoding=\»UTF-8\» standalone=\»yes\»?>» +

                «\n<Developer id=\»1\»>\n» +

                «<name>Andrew</name><age>25</age><position>Middle</position>» +

                «<language>Java</language></Developer>»;

 

        Document document = convertStringToDocument(xmlString);

 

        // обычно используют indent = 4, но посмотрим пример с 6

        System. out.println(toPrettyXmlString(6, document));

    }

 

    // в переменной indent указываем уровень(величину) отступа

    public static String toPrettyXmlString(int indent, Document document) {

        try {

            // удаляем пробелы

            XPath xPath = XPathFactory.newInstance().newXPath();

            NodeList nodeList = (NodeList) xPath.evaluate(

                    «//text()[normalize-space()=»]»,

                    document,

                    XPathConstants.NODESET

            );

 

            for (int i = 0; i < nodeList.getLength(); i++) {

                Node node = nodeList.item(i);

                node.getParentNode().removeChild(node);

            }

 

            // устанавливаем настройки для красивого форматирования

            TransformerFactory transformerFactory = TransformerFactory.newInstance();

            transformerFactory.setAttribute(«indent-number», indent);

            Transformer transformer = transformerFactory. newTransformer();

            transformer.setOutputProperty(OutputKeys.ENCODING, «UTF-8»);

            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, «yes»);

            transformer.setOutputProperty(OutputKeys.INDENT, «yes»);

 

            // форматируем XML

            StringWriter stringWriter = new StringWriter();

            transformer.transform(new DOMSource(document), new StreamResult(stringWriter));

 

            // возвращаем строку с отформатированным XML

            return stringWriter.toString();

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }

 

    // метод для конвертации строки с XML разметкой в объект Document

    private static Document convertStringToDocument(String xml) {

        try {

            return DocumentBuilderFactory.newInstance()

                    .newDocumentBuilder()

                    . parse(new InputSource(new ByteArrayInputStream(xml.getBytes(«utf-8»))));

        } catch (SAXException | IOException | ParserConfigurationException e) {

            e.printStackTrace();

        }

        return null;

    }

 

}

Создание, Редактирование и Парсинг XML файла

Python содержит встроенные XML инструменты для парсинга, к которым вы можете получить доступ при помощи модуля xml. В данной статье мы рассмотрим два подмодуля xml:

Мы начнем с minidom по той причине, что де-факто он используется в качестве метода парсинга XML. После этого, мы взглянем на то, как использовать ElementTree для этих целей.

Работаем с minidom

Для начала, нам нужен XML для парсинга. Давайте взглянем на следующий небольшой пример XML:

<?xml version=»1.0″ ?>
<zAppointments reminder=»15″>
<appointment>
<begin>1181251680</begin>
<uid>040000008200E000</uid>
<alarmTime>1181572063</alarmTime>
<state></state>
<location></location>
<duration>1800</duration>
<subject>Bring pizza home</subject>
</appointment>
</zAppointments>

<?xml version=»1.0″ ?>

<zAppointments reminder=»15″>

    <appointment>

        <begin>1181251680</begin>

        <uid>040000008200E000</uid>

        <alarmTime>1181572063</alarmTime>

        <state></state>

        <location></location>

        <duration>1800</duration>

        <subject>Bring pizza home</subject>

    </appointment>

</zAppointments>

Это типичный XML и читается он вполне интуитивно. В будущем вы, скорее всего, столкнетесь с более сложным примером XML, так что в нашем случае мы работаем с очень удобным материалом. В любом случае, сохраните описанный выше код XML под следующим названием: appt.xml

Давайте уделим больше времени на то, чтобы поближе познакомиться с парсингом данного файла в Python при помощи модуля minidom. Это достаточно длинный кусок кода, так что подготовьтесь:

# -*- coding: utf-8 -*-
import xml.dom.minidom
import urllib.request

class ApptParser(object):

def __init__(self, url, flag=’url’):
self.list = []
self.appt_list = []
self.flag = flag
self.rem_value = 0
xml = self.getXml(url)
self.handleXml(xml)

def getXml(self, url):
try:
print(url)
f = urllib.request.urlopen(url)
except:
f = url

doc = xml.dom.minidom.parse(f)
node = doc.documentElement
if node.nodeType == xml.dom.Node.ELEMENT_NODE:
print(‘Элемент: %s’ % node.nodeName)
for (name, value) in node.attributes.items():
print(‘ Attr — имя: %s значение: %s’ % (name, value))

return node

def handleXml(self, xml):
rem = xml.getElementsByTagName(‘zAppointments’)
appointments = xml.getElementsByTagName(«appointment»)
self.handleAppts(appointments)

def getElement(self, element):
return self.getText(element.childNodes)

def handleAppts(self, appts):
for appt in appts:
self.handleAppt(appt)
self.list = []

def handleAppt(self, appt):
begin = self.getElement(appt.getElementsByTagName(«begin»)[0])
duration = self.getElement(appt.getElementsByTagName(«duration»)[0])
subject = self.getElement(appt.getElementsByTagName(«subject»)[0])
location = self.getElement(appt.getElementsByTagName(«location»)[0])
uid = self.getElement(appt.getElementsByTagName(«uid»)[0])

self.list.append(begin)
self.list.append(duration)
self.list.append(subject)
self.list.append(location)
self.list.append(uid)

if self.flag == ‘file’:
try:
state = self.getElement(appt.getElementsByTagName(«state»)[0])
self.list.append(state)
alarm = self.getElement(appt.getElementsByTagName(«alarmTime»)[0])
self.list.append(alarm)
except Exception as e:
print(e)

self.appt_list.append(self.list)

def getText(self, nodelist):
rc = «»
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc = rc + node.data
return rc

if __name__ == «__main__»:
appt = ApptParser(«appt.xml»)
print(appt.appt_list)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

# -*- coding: utf-8 -*-

import xml.dom.minidom

import urllib.request

 

class ApptParser(object):

    

    def __init__(self, url, flag=’url’):

    self.list = []

    self.appt_list = []

    self.flag = flag

    self.rem_value = 0

    xml = self.getXml(url)

    self.handleXml(xml)

 

    def getXml(self, url):

        try:

            print(url)

            f = urllib.request.urlopen(url)

        except:

            f = url

 

        doc = xml.dom.minidom.parse(f)

        node = doc.documentElement

        if node.nodeType == xml.dom.Node.ELEMENT_NODE:

            print(‘Элемент: %s’ % node.nodeName)

            for (name, value) in node.attributes.items():

                print(‘ Attr — имя: %s значение: %s’ % (name, value))

        

        return node

    

    def handleXml(self, xml):

        rem = xml.getElementsByTagName(‘zAppointments’)

        appointments = xml.getElementsByTagName(«appointment»)

        self.handleAppts(appointments)

 

    def getElement(self, element):

        return self.getText(element.childNodes)

 

    def handleAppts(self, appts):

        for appt in appts:

        self.handleAppt(appt)

        self.list = []

    

    def handleAppt(self, appt):

        begin = self.getElement(appt.getElementsByTagName(«begin»)[0])

        duration = self.getElement(appt.getElementsByTagName(«duration»)[0])

        subject = self.getElement(appt.getElementsByTagName(«subject»)[0])

        location = self.getElement(appt.getElementsByTagName(«location»)[0])

        uid = self.getElement(appt.getElementsByTagName(«uid»)[0])

        

        self.list.append(begin)

        self.list.append(duration)

        self.list.append(subject)

        self.list.append(location)

        self.list.append(uid)

        

        if self.flag == ‘file’:

            try:

                state = self.getElement(appt.getElementsByTagName(«state»)[0])

                self.list.append(state)

                alarm = self.getElement(appt.getElementsByTagName(«alarmTime»)[0])

                self.list.append(alarm)

            except Exception as e:

                print(e)

 

        self.appt_list.append(self.list)

 

    def getText(self, nodelist):

        rc = «»

        for node in nodelist:

            if node.nodeType == node.TEXT_NODE:

                rc = rc + node.data

        return rc

 

if __name__ == «__main__»:

    appt = ApptParser(«appt.xml»)

    print(appt.appt_list)

Этот код основан на примере из документации Python и стоит отметить, что, на мой взгляд, он немного уродливый. Давайте его разберем по кусочкам. Параметр url, который мы видим в классе ApptParser, может быть как url так и файлом. В методе getXml, мы используем обработчик исключений для того, чтобы попробовать открыть url. Если это привело к ошибке, значит url – это путь к файлу. Далее мы используем метод парсинга для парсинга XML. Далее мы изымаем node из XML. Мы опустим все условия, так как в данной статье это не принципиально. Наконец, мы возвращаем объект node. Технически, node является объектом XML, и мы передаем его методу handleXml. Чтобы получить все назначения в XML, мы делаем следующее:

xml.getElementsByTagName(«appointment»)

xml.getElementsByTagName(«appointment»)

После этого, мы передаем эту информацию методу handleAppts. Это большой объем информации. Хорошей идеей будет небольшой рефакторинг этого кода для этой цели, вместо передачи всей этой информации целиком, таким образом мы просто настраиваем переменные класса, после чего вызываем следующий метод без каких-либо аргументов. Я оставлю это в качестве упражнения для читателей. В любом случае, метод handleAppts только создает цикл в каждом назначении и вызывает метод handleAppt, чтобы вытянуть кое-какую дополнительную информации, добавляет данные в список и добавляет этот список в другой список. Идея в том, чтобы закончить со списком списков, которые содержат все соответствующие данные о встречах.

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Обратите внимание на то, что метод handleAppt вызывает метод getElement, который, в свою очередь вызывает метод getText. Технически, вы можете пропустить вызов getElement и вызвать getText напрямую. С другой стороны, вам может понадобиться добавить дополнительную обработку в getElement для конвертации текста, или чего-то другого перед возвратом. Например, вам может понадобиться конвертировать целые числа, числа с запятыми или объекты decimal.Decimal. Давайте попробуем еще один пример с minidom, перед тем как двигаться дальше. Мы используем пример XML с сайта MSDN Майкрософт: http://msdn.microsoft.com/en-us/library/ms762271%28VS.85%29.aspx . Сохраните следующий код под названием example.xml

<?xml version=»1.0″?>
<catalog>
<book>
<author>Gambardella, Matthew</author>
<title>XML Developer’s Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book>
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
<book>
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
<description>After the collapse of a nanotechnology
society in England, the young survivors lay the
foundation for a new society.</description>
</book>
</catalog>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

<?xml version=»1.0″?>

<catalog>

   <book>

      <author>Gambardella, Matthew</author>

      <title>XML Developer’s Guide</title>

      <genre>Computer</genre>

      <price>44.95</price>

      <publish_date>2000-10-01</publish_date>

      <description>An in-depth look at creating applications

      with XML.</description>

   </book>

   <book>

      <author>Ralls, Kim</author>

      <title>Midnight Rain</title>

      <genre>Fantasy</genre>

      <price>5.95</price>

      <publish_date>2000-12-16</publish_date>

      <description>A former architect battles corporate zombies,

      an evil sorceress, and her own childhood to become queen

      of the world.</description>

   </book>

   <book>

      <author>Corets, Eva</author>

      <title>Maeve Ascendant</title>

      <genre>Fantasy</genre>

      <price>5.95</price>

      <publish_date>2000-11-17</publish_date>

      <description>After the collapse of a nanotechnology

      society in England, the young survivors lay the

      foundation for a new society.</description>

   </book>

</catalog>

В этом примере мы выполнили парсинг XML, извлекли заголовки книги и вывели их в stdout. Давайте взглянем на код:

# -*- coding: utf-8 -*-
import xml.dom.minidom as minidom

def getTitles(xml):
«»»
Выводим все заголовки из xml.
«»»
doc = minidom.parse(xml)
node = doc.documentElement
books = doc.getElementsByTagName(«book»)

titles = []
for book in books:
titleObj = book.getElementsByTagName(«title»)[0]
titles.append(titleObj)

for title in titles:
nodes = title.childNodes
for node in nodes:
if node.nodeType == node.TEXT_NODE:
print(node.data)

if __name__ == «__main__»:
document = ‘example.xml’
getTitles(document)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

# -*- coding: utf-8 -*-

import xml.dom.minidom as minidom

 

def getTitles(xml):

    «»»

    Выводим все заголовки из xml.

    «»»

    doc = minidom.parse(xml)

    node = doc.documentElement

    books = doc.getElementsByTagName(«book»)

    

    titles = []

    for book in books:

        titleObj = book.getElementsByTagName(«title»)[0]

        titles.append(titleObj)

    

    for title in titles:

        nodes = title.childNodes

        for node in nodes:

            if node.nodeType == node.TEXT_NODE:

                print(node.data)

 

if __name__ == «__main__»:

    document = ‘example.xml’

    getTitles(document)

Данный код – это только одна короткая функция, которая принимает один аргумент, который является файлом XML. Мы импортируем модуль minidom и даем ему такое же название, чтобы упростить отсылки к нему. Далее мы выполняем парсинг XML. Первые две строки функции очень похожи на те, что были в предыдущем примере. Мы используем метод getElementsByTagName чтобы собрать нужные нам части XML, после чего выполнить итерацию над результатом и извлечь заголовки книги. Так, мы извлекаем объекты заголовков, так что нужно выполнить итерацию этих данных в том числе, а также вытащить обычный текст, по этой причине мы используем вложенные данные цикла. Давайте уделим немного времени на унаследованный модуль xml под названием ElementTree.

Парсинг с ElementTree

В данном разделе, мы научимся создавать XML файлы, редактировать и выполнять парсинг при помощи ElementTree. Для сравнения, мы используем тот же XML, который мы использовали в предыдущем разделе для того, чтобы продемонстрировать разницу в использовании minidom и ElementTree. Вот наш код:

<?xml version=»1.0″ ?>
<zAppointments reminder=»15″>
<appointment>
<begin>1181251680</begin>
<uid>040000008200E000</uid>
<alarmTime>1181572063</alarmTime>
<state></state>
<location></location>
<duration>1800</duration>
<subject>Bring pizza home</subject>
</appointment>
</zAppointments>

<?xml version=»1.0″ ?>

<zAppointments reminder=»15″>

    <appointment>

        <begin>1181251680</begin>

        <uid>040000008200E000</uid>

        <alarmTime>1181572063</alarmTime>

        <state></state>

        <location></location>

        <duration>1800</duration>

        <subject>Bring pizza home</subject>

    </appointment>

</zAppointments>

Давайте начнем с изучения того, как создавать такую XML структуру при помощи Python

Как создавать XML при помощи ElementTree

Создание XML при помощи ElementTree – это очень просто. В данном разделе, мы попытаемся создать написанный выше XML в Python. Давайте посмотрим на код:

# -*- coding: utf-8 -*-
import xml.etree.ElementTree as xml

def createXML(filename):
«»»
Создаем XML файл.
«»»
root = xml.Element(«zAppointments»)
appt = xml.Element(«appointment»)
root.append(appt)

# создаем дочерний суб-элемент.
begin = xml.SubElement(appt, «begin»)
begin.text = «1181251680»

uid = xml.SubElement(appt, «uid»)
uid.text = «040000008200E000»

alarmTime = xml.SubElement(appt, «alarmTime»)
alarmTime.text = «1181572063»

state = xml.SubElement(appt, «state»)

location = xml.SubElement(appt, «location»)

duration = xml.SubElement(appt, «duration»)
duration.text = «1800»

subject = xml.SubElement(appt, «subject»)

tree = xml.ElementTree(root)
with open(filename, «w») as fh:
tree.write(fh)

if __name__ == «__main__»:
createXML(«appt.xml»)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

# -*- coding: utf-8 -*-

import xml.etree.ElementTree as xml

 

def createXML(filename):

    «»»

    Создаем XML файл.

    «»»

    root = xml.Element(«zAppointments»)

    appt = xml.Element(«appointment»)

    root.append(appt)

    

    # создаем дочерний суб-элемент.

    begin = xml.SubElement(appt, «begin»)

    begin.text = «1181251680»

    

    uid = xml.SubElement(appt, «uid»)

    uid.text = «040000008200E000»

    

    alarmTime = xml.SubElement(appt, «alarmTime»)

    alarmTime.text = «1181572063»

    

    state = xml.SubElement(appt, «state»)

    

    location = xml.SubElement(appt, «location»)

    

    duration = xml.SubElement(appt, «duration»)

    duration.text = «1800»

    

    subject = xml.SubElement(appt, «subject»)

    

    tree = xml.ElementTree(root)

    with open(filename, «w») as fh:

        tree.write(fh)

 

if __name__ == «__main__»:

    createXML(«appt.xml»)

Если вы запустите этот код, вы должны получить что-то вроде нижеизложенного (возможно в одной строке):

<?xml version=»1.0″ ?>
<zAppointments reminder=»15″>
<appointment>
<begin>1181251680</begin>
<uid>040000008200E000</uid>
<alarmTime>1181572063</alarmTime>
<state />
<location />
<duration>1800</duration>
<subject />
</appointment>
</zAppointments>

<?xml version=»1.0″ ?>

<zAppointments reminder=»15″>

    <appointment>

        <begin>1181251680</begin>

        <uid>040000008200E000</uid>

        <alarmTime>1181572063</alarmTime>

        <state />

        <location />

        <duration>1800</duration>

        <subject />

    </appointment>

</zAppointments>

Это очень похоже на исходный код и это, безусловно, действенный XML. Само собой, наши коды отличаются, но весьма похожи. Давайте уделим время для разбора кода и убедиться в том, что мы его хорошо понимаем. Для начала мы создаем корневой элемент при помощи функции Element модуля ElementTree. Далее, мы создаем элемент назначения и добавляем его к root. Далее, мы создаем SubElements, выполнив парсинг назначения объекта Element (appt) в SubElement наряду с именем, например, begin. Далее, для каждого SubElement, мы назначаем их текстовые свойства, для передачи значения. В конце скрипта мы создаем ElementTree и используем его для написания XML в файле. Теперь мы готовы к тому, чтобы научиться редактировать файл!

Как редактировать XML при помощи ElementTree

Редактирование XML при помощи ElementTree это также очень просто. Чтобы все было немного интереснее, мы добавим другой блок назначения в XML:

<?xml version=»1.0″ ?>
<zAppointments reminder=»15″>
<appointment>
<begin>1181251680</begin>
<uid>040000008200E000</uid>
<alarmTime>1181572063</alarmTime>
<state></state>
<location></location>
<duration>1800</duration>
<subject>Bring pizza home</subject>
</appointment>
<appointment>
<begin>1181253977</begin>
<uid>sdlkjlkadhdakhdfd</uid>
<alarmTime>1181588888</alarmTime>
<state>TX</state>
<location>Dallas</location>
<duration>1800</duration>
<subject>Bring pizza home</subject>
</appointment>
</zAppointments>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

<?xml version=»1.0″ ?>

<zAppointments reminder=»15″>

    <appointment>

        <begin>1181251680</begin>

        <uid>040000008200E000</uid>

        <alarmTime>1181572063</alarmTime>

        <state></state>

        <location></location>

        <duration>1800</duration>

        <subject>Bring pizza home</subject>

    </appointment>

    <appointment>

        <begin>1181253977</begin>

        <uid>sdlkjlkadhdakhdfd</uid>

        <alarmTime>1181588888</alarmTime>

        <state>TX</state>

        <location>Dallas</location>

        <duration>1800</duration>

        <subject>Bring pizza home</subject>

    </appointment>

</zAppointments>

Теперь мы напишем код для того, чтобы изменить каждое значение тега begin от секунд, начиная с эпохи на что-нибудь более читабельное. Мы используем модуль time python, чтобы облегчить себе жизнь:

# -*- coding: utf-8 -*-
import time
import xml.etree.cElementTree as ET

def editXML(filename):
«»»
Редактируем XML файл.
«»»
tree = ET.ElementTree(file=filename)
root = tree.getroot()

for begin_time in root.iter(«begin»):
begin_time.text = time.ctime(int(begin_time.text))

tree = ET.ElementTree(root)
with open(«updated.xml», «w») as f:
tree.write(f)

if __name__ == «__main__»:
editXML(«original_appt.xml»)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

# -*- coding: utf-8 -*-

import time

import xml.etree.cElementTree as ET

 

def editXML(filename):

    «»»

    Редактируем XML файл.

    «»»

    tree = ET.ElementTree(file=filename)

    root = tree.getroot()

    

    for begin_time in root.iter(«begin»):

        begin_time.text = time.ctime(int(begin_time.text))

    

    tree = ET.ElementTree(root)

    with open(«updated.xml», «w») as f:

        tree.write(f)

 

if __name__ == «__main__»:

    editXML(«original_appt.xml»)

Здесь мы создаем объект ElementTree под названием tree и извлечем из него root. Далее мы используем метод iter() чтобы найти все теги, помеченные “begin”. Обратите внимание на то, что метод iter() был добавлен в Python 2.7. В наем цикле for, мы указываем текстовое содержимое каждого объекта, чтобы получить более читабельный временной формат при помощи метода time.ctime(). Вы также можете обратить внимание на то, что нам нужно конвертировать строку для целых чисел, при передаче их к ctime. Результат будет выглядеть примерно следующим образом:

<zAppointments reminder=»15″>
<appointment>
<begin>Thu Jun 07 16:28:00 2007</begin>
<uid>040000008200E000</uid>
<alarmTime>1181572063</alarmTime>
<state />
<location />
<duration>1800</duration>
<subject>Bring pizza home</subject>
</appointment>
<appointment>
<begin>Thu Jun 07 17:06:17 2007</begin>
<uid>sdlkjlkadhdakhdfd</uid>
<alarmTime>1181588888</alarmTime>
<state>TX</state>
<location>Dallas</location>
<duration>1800</duration>
<subject>Bring pizza home</subject>
</appointment>
</zAppointments>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<zAppointments reminder=»15″>

    <appointment>

        <begin>Thu Jun 07 16:28:00 2007</begin>

        <uid>040000008200E000</uid>

        <alarmTime>1181572063</alarmTime>

        <state />

        <location />

        <duration>1800</duration>

        <subject>Bring pizza home</subject>

    </appointment>

    <appointment>

        <begin>Thu Jun 07 17:06:17 2007</begin>

        <uid>sdlkjlkadhdakhdfd</uid>

        <alarmTime>1181588888</alarmTime>

        <state>TX</state>

        <location>Dallas</location>

        <duration>1800</duration>

        <subject>Bring pizza home</subject>

    </appointment>

</zAppointments>

Вы также можете использовать методы ElementTree, такие как find() или findall() для поиска конкретных тегов в вашем XML. Метод find() найдет только первый пример, в то время как findall() найдет каждый тег с указанной отметкой. Это очень полезно при решении задач, возникших при редактировании или при парсинге, что является темой нашего следующего раздела!

Парсинг и ElementTree

Сейчас мы научимся тому, как выполнять базовый парсинг при помощи ElementTree. Сначала, мы пройдемся по коду в целом, затем разберем его кирпичик за кирпичиком, чтобы понять, как это работает. Обратите внимание на то, что этот код основан на оригинальном примере, и должен работать также и на втором примере.

# -*- coding: utf-8 -*-
import xml.etree.cElementTree as ET

def parseXML(xml_file):
«»»
Парсинг XML используя ElementTree
«»»
tree = ET.ElementTree(file=xml_file)
print(tree.getroot())
root = tree.getroot()
print(«tag=%s, attrib=%s» % (root.tag, root.attrib))

for child in root:
print(child.tag, child.attrib)
if child.tag == «appointment»:
for step_child in child:
print(step_child.tag)

# Парсинг всей XML структуры.
print(«-» * 40)
print(«Iterating using a tree iterator»)
print(«-» * 40)
iter_ = tree.getiterator()

for elem in iter_:
print(elem.tag)

# получаем данные используя дочерние элементы.
print(«-» * 40)
print(«Обрабатываем дочерние жлменты getchildren()»)
print(«-» * 40)
appointments = root.getchildren()

for appointment in appointments:
appt_children = appointment.getchildren()
for appt_child in appt_children:
print(«%s=%s» % (appt_child.tag, appt_child.text))

if __name__ == «__main__»:
parseXML(«appt.xml»)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

# -*- coding: utf-8 -*-

import xml.etree.cElementTree as ET

 

def parseXML(xml_file):

    «»»

    Парсинг XML используя ElementTree

    «»»

    tree = ET.ElementTree(file=xml_file)

    print(tree.getroot())

    root = tree.getroot()

    print(«tag=%s, attrib=%s» % (root.tag, root.attrib))

    

    for child in root:

        print(child.tag, child.attrib)

        if child.tag == «appointment»:

            for step_child in child:

                print(step_child.tag)

 

    # Парсинг всей XML структуры.

    print(«-» * 40)

    print(«Iterating using a tree iterator»)

    print(«-» * 40)

    iter_ = tree.getiterator()

    

    for elem in iter_:

        print(elem.tag)

 

    # получаем данные используя дочерние элементы.

    print(«-» * 40)

    print(«Обрабатываем дочерние жлменты getchildren()»)

    print(«-» * 40)

    appointments = root.getchildren()

    

    for appointment in appointments:

        appt_children = appointment.getchildren()

        for appt_child in appt_children:

            print(«%s=%s» % (appt_child.tag, appt_child.text))

 

if __name__ == «__main__»:

    parseXML(«appt.xml»)

Вы уже должны понять, что и как работает, но в этом примере и предыдущем мы импортируем cElementTree вместо обычного ElementTree. Разница между этими двумя в том, что cElementTree основан на С, а не на Python, так что он намного быстрее. В любом случае, мы снова создаем объект ElementTree и извлекаем root из него. Обратите внимание на то, что мы выводим root, его тег и атрибуты. Далее мы покажем несколько способов итерации тегов. Первый цикл просто итерирует XML, дочку за дочкой. Таким образом выведется только дочерний код (назначение) с наивысшим уровнем , так что мы добавили оператор if, чтобы проверить дочерний код и выполнить его итерацию. Далее мы берем итератор из объекта tree и также итерируем его. В итоге мы получим ту же информацию, но без дополнительных ступеней, как в первом примере. Третий метод использует корневую функцию getchildren(). Так что нам снова понадобится применить внутренний цикл, чтобы получить все теги дочернего кода и назначения. В последнем примере используется корневой метод iter() для цикла всех тегов, соответствующих строке “begin”.

Как было отмечено в последнем разделе, вы также можете использовать методы find() или findall(), чтобы облегчить поиск конкретных тегов, или набор тегов соответственно. Также обратите внимание на то, что каждый объект Element имеет свой тег и текстовое значение, этим можно воспользоваться для получения необходимой точной информации.

Подведем Итоги

Теперь вы знаете, как использовать minidom для парсинга XML. Вы также освоили ElementTree для создания, редактирования и парсинга XML. Существуют и другие библиотеки вне Python, которые предлагают дополнительные методы для работы с XML. Убедитесь в том, что вы пользуетесь понятным вам инструментом, так как данный вопрос может быть очень сложным и непонятным, если пытаться решить его неправильным инструментом.

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: [email protected]

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»

1С и файлы XML: запись и чтение

Рассмотрим возможности 1С 8.3 работы с XML.

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

Рассмотрим два варианта работы с XML: средствами внутреннего языка и средствами внутреннего языка с использованием XDTO пакетов.

Чтение файла XML средствами внутреннего языка 1С

Создадим новый объект: ЧтениеXML. Он позволяет читать сообщения. Далее привожу простейший код, показывающий принцип чтения и разборки XML файла. Пояснения буду приводить в виде комментариев, чтобы не разрывать код на куски и его можно было скопировать для дальнейшего использования.

ЧтениеXML = Новый ЧтениеXML;

ЧтениеXML.ОткрытьФайл("d:\Temp\Test.XML");  //Открываем файл

Пока ЧтениеXML.Прочитать() Цикл  //Цикл по структуре

Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда  //Определяем начало элемента

Пока ЧтениеXML.ПрочитатьАтрибут() Цикл

//Внутри элемента считываем атрибуты

КонецЦикла;

ИначеЕсли ЧтениеXML.ТипУзла=ТипУзлаXML.Текст Тогда

//Если это текст, читаем текст

ИначеЕсли ЧтениеXML.ТипУзла=ТипУзлаXML.КонецЭлемента Тогда

//Определяем дальнейшие действия

КонецЕсли ;

КонецЦикла;

Таким образом, зная структуру файла, можно его разобрать «по полочкам» в программе 1С.

Запись данных из 1C в XML

Так же создадим объект ЗаписьXML.

ЗаписьXML = Новый ЗаписьXML;

ЗаписьXML.ОткрытьФайл("d:\Temp\Test.XML", "UTF-8"); //Открываем файл для записи, указываем кодировку

ЗаписьXML.ЗаписатьОбъявлениеXML();  // Записываем объявление XML

ЗаписьXML.ЗаписатьНачалоЭлемента("Организации"); // Начало элемента Организации

Выборка = Справочники.Организации.Выбрать();

Пока Выборка.Следующий() Цикл  // Начинаем выгружать организации

ЗаписьXML.ЗаписатьНачалоЭлемента("Организация"); // Начало элемента Организация

ЗаписьXML.ЗаписатьАтрибут("Код",Строка(Выборка.Код));

ЗаписьXML.ЗаписатьАтрибут("Наименование",Строка(Выборка.Наименование));

ЗаписьXML.ЗаписатьКонецЭлемента(); // Конец элемента Организация

КонецЦикла;

ЗаписьXML.ЗаписатьКонецЭлемента(); // Конец элемента Организации

Таким образом мы выгрузим код и наименование всех организаций из справочника 1С «Организации».

Выгрузка из 1C в XML с помощью XDTO-пакетов

Если вы только начинаете программировать в 1С или просто хотите систематизировать свои знания — попробуйте Школу программирования 1С нашего друга Владимира Милькина. Пошаговые и понятные уроки даже для новичка с поддержкой учителя.
Попробуйте бесплатно по ссылке >>

В 1С предприятии существует такой объект метаданных, как XDTO-пакеты. Они служат для обмена данными в формате XML.

XDTO-пакет позволяет создать структуру, по которой потом пойдет выгрузка данных. Покажу пример такой структуры:

Теперь, определив структуру (ее, кстати, можно загрузить из файла), мы можем смело сформировать файл:

МойXML = Новый ЗаписьXML;

ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);

МойXML.ОткрытьФайл("d:\Temp\Test.XML",  ПараметрыЗаписиXML);

МойXML.ЗаписатьОбъявлениеXML();

ТипОбъектаАктивыВСистеме = ФабрикаXDTO.Тип("www.primer.ru/assets", "АктивыВСистеме");

ОбъектАктивыВСистеме = ФабрикаXDTO.Создать(ТипОбъектаАктивыВСистеме);

ОбъектАктивыВСистеме.ДатаВыгрузки = ТекущаяДата();

ТипОбъектаАктивы = ФабрикаXDTO.Тип("www.primer.ru/assets", "Активы");

ОбъектАктивы = ФабрикаXDTO.Создать(ТипОбъектаАктивы);

ОбъектАктивыВСистеме.Добавить(ФормаXML.Элемент, "www.primer.ru/assets", "Активы", ОбъектАктивы);

ТипОбъектаАктив = ФабрикаXDTO.Тип("www.primer.ru/assets", "Актив");

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл

ОбъектАктив = ФабрикаXDTO.Создать(ТипОбъектаАктив);

ОбъектАктив.Наименование = ВыборкаДетальныеЗаписи.Наименование;

ОбъектАктив.ISIN = ВыборкаДетальныеЗаписи.ISIN;

ОбъектАктивы.Актив.Добавить(ОбъектАктив);

КонецЦикла;

ФабрикаXDTO.ЗаписатьXML(МойXML, ОбъектАктивыВСистеме);

МойXML.Закрыть();

Вот так, определив заранее схему, можно создать файл любой сложности.

Если Вы начинаете изучать 1С программирование, рекомендуем наш бесплатный курс (не забудьте подписаться на YouTube — регулярно выходят новые видео):

К сожалению, мы физически не можем проконсультировать бесплатно всех желающих, но наша команда будет рада оказать услуги по внедрению и обслуживанию 1С. Более подробно о наших услугах можно узнать на странице Услуги 1С или просто позвоните по телефону +7 (499) 350 29 00. Мы работаем в Москве и области.

Синтаксис XML


Синтаксические правила XML очень просты и логичны. Правила
просты в освоении и использовании.


XML-документы должны иметь корневой элемент

XML-документы

должны содержать один корневой элемент , который является
родитель

всех остальных элементов:

<корень>
<ребенок>
…..

В этом примере — корневой элемент:

«?>
<Примечание>
Тове
Яни
Напоминание
Не забывай меня в эти выходные!


Пролог XML

Эта строка называется прологом XML :

» ?>

Пролог XML не является обязательным.Если он существует, он должен быть первым в документе.

Документы XML

могут содержать международные символы, например норвежский øæå или
Французский êèé.

Во избежание ошибок следует указать используемую кодировку или сохранить файлы XML.
как UTF-8.

UTF-8 — это кодировка символов по умолчанию для документов XML.

Кодировку

можно изучить в нашем
Учебник по набору символов.

UTF-8 также является кодировкой по умолчанию для HTML5, CSS, JavaScript, PHP и SQL.



Все элементы XML должны иметь закрывающий тег

В XML недопустимо пропускать закрывающий тег. Все элементы должны иметь
закрывающий тег:

Это абзац.

Примечание: В прологе XML нет закрывающего тега!
Это не ошибка. Пролог не является частью XML-документа.


XML-теги чувствительны к регистру

XML-теги чувствительны к регистру.Тег отличается от тега
<буква>.

Открывающий и закрывающий теги должны быть написаны в одном регистре:

Это верно

«Открывающие и закрывающие теги» часто называют «Начальными и конечными тегами». Использовать
Что вы предпочитаете. Это точно то же самое.


Элементы XML должны быть правильно вложены

В HTML вы можете увидеть неправильно вложенные элементы:

Этот текст выделен полужирным курсивом

В XML все элементы должны быть правильно вложены друг в друга:

Этот текст выделен полужирным курсивом

В приведенном выше примере «Правильно вложено» просто означает, что, поскольку
элемент открывается внутри элемента , он должен быть закрыт внутри
элемент.


Значения атрибутов XML должны всегда указываться в кавычках

Элементы XML

могут иметь атрибуты в парах имя / значение, как в HTML.

В XML значения атрибутов всегда должны заключаться в кавычки:


Тове
Яни


Ссылки на юридические лица

Некоторые символы имеют особое значение в XML.

Если вы поместите такой символ, как «<" внутри элемента XML, он сгенерирует ошибка, потому что синтаксический анализатор интерпретирует ее как начало нового элемента.

Это приведет к ошибке XML:

зарплата <1000

Чтобы избежать этой ошибки, замените символ «<» ссылкой на сущность :

<сообщение> зарплата & lt; 1000

В XML есть 5 предопределенных ссылок на сущности:

& lt; < менее
& gt; > больше
& amp; и амперсанд
апостроф
& quot; « кавычка

В XML строго запрещены только символы <и &, но лучше заменить>
с & gt; также.


Комментарии в XML

Синтаксис для написания комментариев в XML аналогичен синтаксису HTML:

Два тире в середине комментария не допускаются:


Пробел сохраняется в XML

XML не усекает несколько пробелов (HTML усекает несколько
белые пространства в одно белое пространство):

XML: Привет Туве
HTML: Привет Туве

XML сохраняет новую линию как LF

Приложения Windows сохраняют новую строку как: возврат каретки и перевод строки
(CR + LF).

Unix и Mac OSX используют LF.

Старые системы Mac используют CR.

XML сохраняет новую строку как LF.


Хорошо сформированный XML

XML-документов, которые соответствуют приведенным выше правилам синтаксиса, считаются «Хорошо
Формируются «XML-документы.

Синтаксический анализатор XML Xerces-C ++

Xerces-C ++ — это проверяющий синтаксический анализатор XML, написанный на переносимом подмножестве
C ++.Xerces-C ++ упрощает предоставление вашему приложению возможности чтения и записи.
XML-данные. Общий
библиотека предназначена для синтаксического анализа, генерации, управления и проверки XML-документов.
с использованием API DOM, SAX и SAX2. Для введения в программирование
с Xerces-C ++ см. Программирование
Гид.

Xerces-C ++ верен
Рекомендация XML 1.0
и многие связанные стандарты (см. раздел «Функции» ниже).

Анализатор обеспечивает высокую производительность, модульность и масштабируемость.Источник
код, образцы и документация по API предоставляются вместе с парсером. Для
переносимости, было уделено внимание минимальному использованию шаблонов и минимальному использованию
#ifdefs.

Xerces обладает широкими возможностями генерации и проверки. Парсер используется для:

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

  • Соответствует
    • XML 1.0 (третье издание), Рекомендация W3C
    • XML 1.1 (первое издание), рекомендация W3C
      (Примечание: раздел 2.13 Проверка нормализации не реализован)
    • Спецификация DOM уровня 1, рекомендация W3C от 1 октября 1998 г.
    • DOM Level 2 Core Specification, Рекомендация W3C от 13 ноября 2000 г.
    • Спецификация обхода и диапазона DOM уровня 2,
      Рекомендация W3C от 13 ноября 2000 г.
    • SAX 1.0 и SAX 2.0
    • Пространства имен в XML, Рекомендация W3C от 14 января 1999 г.
    • Пространства имен в XML 1.1, Рекомендация W3C
    • Схема XML, часть 1: структура, рекомендация W3C 2 мая 2001 г.
    • Схема XML, часть 2: Типы данных, Рекомендация W3C 2 мая 2001 г.,
    • Базовая спецификация DOM уровня 3.0, рекомендация W3C от 7 апреля 2004 г.
    • DOM уровня 3.0 Спецификация загрузки и сохранения, рекомендация W3C от 7 апреля 2004 г.
      Подробности см. В разделе «Поддержка DOM уровня 3».
    • Включение XML (XInclude) 1.0 (второе издание), рекомендация W3C от 15 ноября 2006 г.
    • Спецификация обхода элементов, рекомендация W3C от 22 декабря 2008 г.
  • Исходный код, образцы и документация предоставляются
  • Программное создание и проверка XML
  • Подключаемые каталоги, валидаторы и кодировки
  • Высокая производительность
  • Настраиваемая обработка ошибок

Если вы ищете информацию о старом Xerces 2.Икс
библиотека, имейте в виду, что Xerces 2.8.0 и все более ранние выпуски
на 100% не поддерживаются и больше не должны использоваться приложениями.

В чем разница между XML и C, C ++ или Java?

Ваша поддержка наших рекламодателей помогает покрыть расходы на хостинг, исследование и обслуживание этого FAQ

C и C ++ (и другие языки, такие как FORTRAN или Pascal,
или Visual Basic, или Java или сотни других)
языков программирования с которыми вы
указать расчеты, действия и решения, которые необходимо выполнить
в порядке:

mod curconfig [если left (date, 6) = "01 апреля",
    т.поставил "Первоапрельская!",
    f.пуск дней ('31102011', 'ДДММГГГГ') -
          дней (дата, "ДДММГГГГ")
    «больше дней покупок в Самайн»];

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


   Стопорное стопорное кольцо подшипника конца распределительного вала 
  
   Ringtown Fasteners Ltd 
   Инструмент для вставки  с острым носом 
    требуется для снятия и замены этой детали.

Сам по себе файл XML (включая HTML) не
делать что угодно. Это формат данных, который
просто сидит там, пока вы не запустите программу, которая что-то делает
с ит. См. Также вопрос о
как бежать или
выполнять файлы XML.

XSLT2 и XSL: FO

Вода мутится из-за того, что самые популярные
языки обработки преобразований (XSLT2 и XSL: FO) являются
фактически написаны в синтаксисе XML, потому что они
декларативный, а не процедурный.В этих особых случаях вы
можно сказать, что «выполняет»
XML-файл, запустив приложение обработки, например
Saxon , который составляет
директивы, указанные в файлах, в байт-код Java для
обрабатывать XML-документы. В этом смысле можно сравнить
их с другими языками программирования, но вы бы
сравнение языковых возможностей, а не синтаксиса XML в
которые они написаны.

Уильям Хаммонд пишет:

(в статье
)

SGML — это категория документа
типы »с настраиваемым общим синтаксисом,
большинство из которых (например, классический HTML) не могут быть скомпилированы в
создавать исполняемые программы. XML — это подкатегория SGML
с синтаксическими ограничениями. Например, с XML
словарь типа документа всегда чувствителен к регистру,
в то время как с SGML он может быть чувствителен к регистру или регистр
нечувствительный. Так, например, классический HTML — это SGML.
тип документа, а XHTML + MathML — это XML-документ
тип.

Хотя некоторые типы документов соответствуют
языки разметки, другие типы документов (например, каталог CTAN
запись) предназначены только для структурированных данных […]

Я серьезно сомневаюсь, однако, что компьютерный язык
как C в любом разумном смысле эквивалентен SGML
тип документа.

Как разбирать XML в C ++ — Linux Подсказка

В этой статье мы собираемся обсудить, как анализировать XML на языке программирования C ++. Мы увидим несколько рабочих примеров, чтобы понять механизм синтаксического анализа XML в C ++.

Что такое XML?

XML — это язык разметки, который в основном используется для хранения и передачи данных в организованном порядке. XML означает расширяемый язык разметки. Он очень похож на HTML. XML полностью ориентирован на хранение и передачу данных, тогда как HTML используется для отображения данных в браузере.

Пример файла XML / синтаксиса XML

Вот пример XML-файла:

Tom

Drake

В отличие от HTML, это язык разметки, ориентированный на теги, и мы можем определить наш собственный тег в файле XML.В приведенном выше примере у нас есть несколько пользовательских тегов, таких как «». У каждого тега будет соответствующий конечный тег. «» — это конечный тег для «». Мы можем определить столько пользовательских тегов, сколько захотим, чтобы систематизировать данные.

Библиотеки синтаксического анализа в C ++:

Существуют различные библиотеки для анализа XML-данных на большинстве языков программирования высокого уровня. C ++ не исключение. Вот самые популярные библиотеки C ++ для анализа XML-данных:

  1. RapidXML
  2. PugiXML
  3. TinyXML

Как следует из названия, RapidXML в основном ориентирован на скорость и представляет собой библиотеку синтаксического анализа в стиле DOM.PugiXML поддерживает преобразование Unicode. Вы можете использовать PugiXML, если хотите преобразовать документ UTF-16 в UTF-8. TinyXML — это минимальная версия для анализа XML-данных, которая не такая быстрая по сравнению с двумя предыдущими. Если вы хотите просто выполнить свою работу и не заботитесь о скорости, вы можете выбрать TinyXML.

Примеры
Теперь у нас есть базовое понимание XML и библиотек синтаксического анализа XML в C ++. Давайте теперь рассмотрим несколько примеров для синтаксического анализа XML-файла на C ++:

  • Пример 1: синтаксический анализ XML в C ++ с использованием RapidXML
  • Пример-2: Анализ XML в C ++ с использованием PugiXML
  • Пример 3: Анализ XML в C ++ с использованием TinyXML

В каждом из этих примеров мы будем использовать соответствующие библиотеки для анализа образца XML-файла.

Пример-1: синтаксический анализ XML в C ++ с использованием RapidXML

В этом примере программы мы продемонстрируем, как анализировать xml с помощью библиотеки RapidXML на C ++. Вот входной XML-файл (sample.xml):

Джон

Sean

Сара

Наша цель — проанализировать указанный выше XML-файл с помощью C ++.Вот программа на C ++ для анализа XML-данных с помощью RapidXML. Вы можете скачать библиотеку RapidXML отсюда.

#include
#include
#include
#include «rapidxml.hpp»

с использованием пространства имен std;
с использованием пространства имен rapidxml;

xml_document <> doc
xml_node <> * root_node = NULL;

int main (void)
{
cout << "\ nПарсинг данных моих студентов (sample.xml) ....." << endl; // Прочтите образец.xml файл
ifstream theFile («sample.xml»);
векторный буфер ((istreambuf_iterator (theFile)), istreambuf_iterator ());
buffer.push_back (‘\ 0’);

// Разбираем буфер
doc.parse <0> (& buffer [0]);

// Узнаем корневой узел
root_node = doc.first_node («MyStudentsData»);

// Перебираем узлы учеников
для (xml_node <> * student_node = root_node-> first_node («Student»); student_node; student_node = student_node-> next_sibling ())
{
cout << "\ nStudent Type = "<< студенческий_узел-> первый_атрибут (» ученический_тип «) -> значение ();
cout << endl; // Взаимодействие с именами учащихся
для (xml_node <> * student_name_node = student_node-> first_node («Name»); student_name_node; student_name_node = student_name_node-> next_sibling ())
{
cout << "Student Name =" << имя_студента_узел-> значение ();
cout << endl;
}
cout << endl;
}

возврат 0;
}

Пример-2: Анализ XML в C ++ с использованием PugiXML

В этом примере программы мы продемонстрируем, как анализировать xml с помощью библиотеки PugiXML на C ++.Вот входной XML-файл (sample.xml):

В этом примере программы мы продемонстрируем, как анализировать xml с помощью библиотеки pugixml на C ++.Вы можете скачать библиотеку PugiXML отсюда.

#include
#include «pugixml.hpp»

с использованием пространства имен std;
с использованием пространства имен pugi;

int main ()
{
cout << "\ nПарсинг данных сотрудников (sample.xml) ..... \ n \ n";
xml_document doc;

// загружаем XML-файл
if (! Doc.load_file («sample.xml»)) return -1;

xml_node tools = doc.child («EmployeesData»). Child («Сотрудники»);

для (xml_node_iterator it = tools.начинать(); это! = tools.end (); ++ it)
{
cout << "Сотрудники:";

для (xml_attribute_iterator ait = it-> attributes_begin (); ait! = It-> attributes_end (); ++ ait)
{
cout << "" << ait-> name () << "=" < value ();
}

cout << endl;
}

cout << endl; возврат 0; }

Пример 3: синтаксический анализ XML в C ++ с использованием TinyXML

В этом примере программы мы продемонстрируем, как анализировать xml с помощью библиотеки TinyXML на C ++.Вот входной XML-файл (sample.xml):

Джон

Шон

Сара

В этом примере программы мы продемонстрируем, как анализировать xml с помощью библиотеки TinyXML на C ++. Вы можете скачать библиотеку TinyXML отсюда.

#include
#include
#include
#include «tinyxml2.cpp «

с использованием пространства имен std;
с использованием пространства имен tinyxml2;

int main (void)
{
cout <<" \ nПарсинг данных моих учеников (sample.xml) ..... "<< endl; / / Прочитать файл sample.xml
XMLDocument doc;
doc.LoadFile («sample.xml»);

const char * title = doc.FirstChildElement («MyStudentsData») -> FirstChildElement («Student») -> GetText ( );
printf («Имя учащегося:% s \ n», заголовок);

XMLText * textNode = doc.LastChildElement («MyStudentsData») -> LastChildElement («Student») -> FirstChild () -> ToText ();
заголовок = текстовый узел-> Значение ();
printf («Имя учащегося:% s \ n», титул);

возврат 0;
}

Заключение

В этой статье мы кратко обсудили XML и рассмотрели три различных примера синтаксического анализа XML в C ++. TinyXML — это минималистичная библиотека для анализа XML-данных. Большинство программистов в основном используют RapidXML или PugiXML для анализа XML-данных.

Учебное пособие по схеме

XML — Определение элементов и атрибутов

Определение

глобальных сложных типов

Xs: complexType также может быть определен глобально и иметь имя. После этого именованные xs: complexTypes можно повторно использовать в
schema, на которую имеется прямая ссылка или используется в качестве основы для определения других xs: complexTypes. Это позволяет построить больше объекта
ориентированные структуры данных, с которыми проще работать и управлять.

Еще раз посмотрев на наш пример, было бы гораздо разумнее иметь одно определение для «Адреса», которое затем могло бы
использоваться как заказчиком, так и поставщиком. Мы можем сделать это, определив глобальный (названный) xs: complexType:


    
        
        
    

 

Предыдущие определения XSD графически отображаются в Liquid Studio следующим образом:

Теперь мы определили , который описывает наше представление адреса, поэтому давайте его воспользуемся.Раньше, когда мы
начали смотреть на элементы, мы сказали, что вы можете определять свои собственные типы вместо использования одного из стандартных типов, таких как xs: string
или xs: integer, и это именно то, что сейчас делали.


    
        
            
            
        
    


    
        
            
            
        
    

 

Предыдущие определения XSD графически отображаются в Liquid Studio следующим образом:

Надеюсь, преимущества очевидны.Вместо того, чтобы определять адрес дважды (один раз для клиента и один раз для поставщика), теперь у нас есть одно определение. Это упрощает обслуживание, т.е. если вы решите добавить элементы «Line3» или «Почтовый индекс» к своему адресу, вам нужно будет добавить их только в одном месте.

Пример XML
<Заказчик>
     2000-01-12T12: 13: 14Z 
    <Адрес>
         Где-то на улице 34 
         sometown, ww1 8uu 
    

<Поставщик>
     0123987654 
    <Адрес>
         22 в любом месте, где-нибудь 
         sometown, ss1 6gy 
    

 
Банкноты

Примечание. Только сложные типы, определенные глобально (поскольку дочерние элементы элемента могут иметь собственное имя и повторно использоваться во всей схеме).Если они определены внутри , они не могут иметь имени (анонимно) и не могут быть повторно использованы где-либо еще.

Конкурирует с C при разборе XML

В этом посте мы рассмотрим синтаксический анализ XML в Haskell, его сравнение с эффективным синтаксическим анализатором C и шаги, которые вы можете предпринять в Haskell для создания быстрой библиотеки с нуля. Мы собираемся подробно остановиться и запачкать руки.

Новенький на блоке

Несколько недель назад Нил Митчелл опубликовал в блоге сообщение о новой библиотеке XML, которую он написал.Парсер написан на C, а API написан на Haskell, который использует библиотеку C. Пишет, что очень быстро:

Hexml был разработан для скорости. В очень ограниченных тестах, которые я сделал, он обычно более чем в 2 раза быстрее при синтаксическом анализе, чем Pugixml, где Pugixml является золотым стандартом для быстрых синтаксических анализаторов XML DOM. В моем использовании он превратил синтаксический анализ XML из узкого места в ненужное, поэтому он работает для меня.

Чтобы достичь этой скорости, он жульничает, не выполняя операций, которые ему не важны:

Чтобы получить такую ​​скорость, Hexml читер.В основном он не выполняет расширение сущностей, поэтому & amp; остается как & amp; на выходе. Он также не обрабатывает разделы CData (но это потому, что я ленив), и места комментариев не запоминаются. Он также не работает с большей частью стандарта XML, игнорируя материал DOCTYPE . [..] Я работаю только с UTF8, который для тех битов UTF8, которые меня волнуют, совпадает с ASCII — мне не нужно декодировать символы.

Мошенничество — это нормально, если вы подробно опишете, как жульничать.Это просто меняет правила игры!

Но у C проблемы

Этот пост привлек мое внимание, потому что мне показалось жалким использовать C. Независимо от того, используете ли вы Haskell, Python или что-то еще, есть несколько проблем с переходом на C с вашего языка высокого уровня:

  • Программа более вероятна segfault. Я сделаю исключение по поводу segfault в любой день!
  • Программа открыта для возможной эксплуатации из-за недостаточной безопасности памяти.
  • Если люди хотят расширить ваше программное обеспечение, они должны использовать C, а не ваш язык высокого уровня.
  • Переносимость (например, Windows) — заноза в заднице с C.

Разумеется, это было незадолго до того, как Остин Сипп опубликовал краткое изложение ошибок в коде C:

На данный момент, извините, я бы не стал использовать эту библиотеку для синтаксического анализа любого произвольного XML, так как он может быть сочтен враждебным и достать меня. Используя American Fuzzy Lop, всего через несколько минут я обнаружил около 30 уникальных сбоев.

Но C действительно быстрый, правда? В 100 раз быстрее, чем Haskell! Риск стоит того.

Но-но C быстрый!

Давайте посмотрим на это. Мы собираемся проанализировать XML-файл размером 4 КБ, 31 КБ и 211 КБ.

Используя пакет тестирования Criterion, мы можем сравнить Hexml с довольно старым пакетом Haskell xml

  Файл шестнадцатеричный xml
4 КБ 6,26 мкс 1,94 мс (1940 мкс)
31 КБ 9,41 мкс 13,6 мс (13600 мкс)
211 КБ 260 мкс 25,9 мс (25900 мкс)  

Ой! Эти цифры не выглядят хорошими. Пакет xml в 100-300 раз медленнее.

Ладно, я несправедлив. Пакет xml не отличается скоростью. Описание его пакета просто Простая библиотека XML. Сравним с пакетом hexpat. В описании этого есть:

Целями проектирования являются скорость, скорость, скорость, простота интерфейса и модульность.

Так что это, вероятно, больше соответствует лучшим анализаторам XML на Haskell. Он также основан на библиотеке C expat, которая должна быть быстрой.

  Файл hexml hexpat
4 КБ 6.395 мкс 320,3 мкс
31 КБ 9,474 мкс 378,3 мкс
211 КБ 256,2 мкс 25,68 мс  

Это немного лучше. Сейчас мы в 40–100 раз медленнее, чем Hexml. Я бы предпочел в 10 раз медленнее, но это более разумный результат. Пакет hexpat обрабатывает: сохранение информации о местоположении, разумные ошибки синтаксического анализа, полный стандарт XML. Hexml ничего из этого не делает.

Давайте бросим нам вызов. Можем ли мы сопоставить или превзойти пакет Hexml в простом старом Haskell? Это зуд, который пронзил мою кожу. Я написал Нилу по электронной почте, и он согласился:

Я не считаю несправедливым или оскорбительным использовать Hexml в качестве основы — я приветствую это!

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

Начни с самого простого

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

Числа 60 и 62 — это < и > . В XML имеют значение только символы < и > (если вас не интересуют сущности). < и > не могут отображаться внутри речевых знаков (атрибутов).Это единственные важные вещи, которые нужно искать. Результатов:

  Файл шестнадцатеричный xeno
4 КБ 6,395 мкс 2,630 мкс
42 КБ 37,55 мкс 7,814 мкс  

Таким образом, базовая производительность при переходе по файлу скачками довольно высока! Почему это быстро? Давайте посмотрим на это минутку:

  • Тип данных ByteString - это безопасная оболочка вокруг вектора байтов. Это эквивалентно char * в C.
  • Имея это в виду, S.Функция elemIndex реализована с использованием стандартной функции C memchr (3) . Как мы все знаем, memchr перескакивает через ваш файл в больших границах слов или даже с помощью операций SIMD, что означает чертовски быстро. Но сама функция elemIndex безопасна.

Итак, мы фактически выполняем цикл for (..) {s = memchr (s, ..)} над файлом.

Следите за распределением

Используя пакет взвешивания для отслеживания распределения памяти, мы также можем прямо сейчас посмотреть на распределение нашего кода:

  Проверка GC байтов Case Bytes
Разбор 4 КБ 1,168 0 ОК
Разбор 42kb 1,560 0 OK
Разбор 52kb 1,168 0 OK
182kb синтаксический анализ 1,168 0 ОК  

Мы видим, что она постоянная.Хорошо, он меняется на несколько байтов, но не увеличивается линейно или что-то в этом роде. Это хорошо! Одна вещь, которая бросилась мне в глаза, это то, что мы не заплатили за распределение значений Может быть, . Для символов 1000x < и > у нас должно быть 1000 выделений из Всего / Ничего . Давай на секунду спустимся в кроличью нору.

Взгляд на ядро ​​

Ну, если скомпилировать исходники вот так

  стек ghc - -O2 -ddump-simple Xeno.HS  

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

Выход довольно большой. Ядро многословно, а быстрый код обычно длиннее. Вот результат, но вам не обязательно его понимать. Просто обратите внимание, что там нет упоминания о «Может быть, просто или ничего».Он вообще это пропускает. Смотрите здесь конкретно. Выполняется вызов memchr , затем выполняется сравнение eqAddr с NULL , чтобы узнать, выполняется ли memchr или нет. Но мы все еще проводим проверки безопасности, чтобы полученный код был безопасным.

Встраивание счетчиков

Любопытный читатель мог заметить, что в моем первом примере кода строка INLINE .

Без INLINE вся функция в два раза медленнее и имеет линейное распределение.

  Проверка GC байтов Case Bytes
Разбор 4kb 1,472 0 OK
Разбор 42 КБ 1,160 0 ОК
Разбор 52 КБ 1,160 0 ОК

бенчмаркинг 4KB / xeno
время 2,512 мкс (2,477 мкс .. 2,545 мкс)
бенчмаркинг 211KB / xeno
время 129,9 мкс (128,7 мкс .. 131,2 мкс)
бенчмаркинг 31KB / xeno
время 1,930 мкс (1,909 мкс .. 1,958 мкс)  

против:

  Проверка GC байтов Case Bytes
Разбор 4kb 12,416 0 OK
42kb синтаксический анализ 30,080 0 OK
52kb разбор 46,208 0 OK

бенчмаркинг 4KB / xeno
время 5.258 мкс (5,249 мкс .. 5,266 мкс)
бенчмаркинг 211KB / xeno
время 265,9 мкс (262,4 мкс .. 271,4 мкс)
бенчмаркинг 31KB / xeno
время 3,212 мкс (3,209 мкс .. 3,218 мкс)  

Всегда обращайте внимание на такие вещи. Вы не хотите ставить INLINE на все. Иногда это добавляет замедления, в большинстве случаев это не имеет значения. Так что сверьтесь с вашим набором тестов.

Раскрутка петли вручную

Некоторые вещи нужно делать вручную. Я добавил в нашу маленькую функцию синтаксический анализ комментариев:

И стало в 2 раза медленнее:

  тестирование 4KB / xeno
время 2.512 мкс (2,477 мкс .. 2,545 мкс)  

С

по

  тестирование 4KB / xeno
время 4,296 мкс (4,240 ... 4,348 мкс)  

Итак, я изменил S.isPrefixOf , чтобы он был развернут, на вызовов S.index , например:

И он снова упал до нашей базовой скорости.

Поиск имен тегов

Я реализовал поиск имен тегов следующим образом:

И сразу заметил большое подтормаживание. С

  Проверка GC байтов Case Bytes
Разбор 4 КБ 1,160 0 ОК
42kb синтаксический анализ 1,472 0 OK
Разбор 52 КБ 1,160 0 ОК
Тест xeno-memory-bench: ФИНИШ
Тест ксено-скорости: БЕГ...
бенчмаркинг 4KB / hexml
время 6,149 мкс (6,125 мкс .. 6,183 мкс)
бенчмаркинг 4KB / xeno
время 2,691 мкс (2,665 мкс .. 2,712 мкс)  

С

по

  Проверка GC байтов Case Bytes
Разбор 4kb 26096 0 OK
42kb разобрать 65,696 0 OK
Разбор 52 КБ 102,128 0 ОК
Тест xeno-memory-bench: ФИНИШ
Тест ксено-скорости: БЕГ ...
бенчмаркинг 4KB / hexml
время 6,225 мкс (6,178 мкс .. 6,269 мкс)
бенчмаркинг 4KB / xeno
время 10.34 мкс (10,06 мкс .. 10,59 мкс)  

Первое, что должно броситься в глаза, - это распределения. Что там происходит? Я просмотрел выходные данные профилировщика, запустив stack bench --profile , чтобы увидеть выходные данные профиля.

  Ср, 11 января, 17:41 2017 Отчет о профилировании времени и распределения (окончательный)

xeno-speed-bench + RTS -N -p -RTS 4KB / xeno

общее время = 8,09 сек (8085 тиков @ 1000 мкс, 1 процессор)
общее выделение = 6075628752 байта (без учета накладных расходов на профилирование)

МОДУЛЬ СТОИМОСТИ ЦЕНТРА% времени% распределения

разобрать.findTagName Xeno 35,8 72,7
getOverhead Criterion.Monad 13.6 0.0
parse.checkOpenComment Xeno 9.9 0.0
parse.findLT Xeno 8.9 0.0
разобрать Xeno 8.4 0.0
>> = Data.Vector.Fusion.Util 4.6 7.7
getGCStats Criterion.Measurement 2.8 0.0
basicUnsafeIndexM Данные.Вектор.Примитив 1.6 2.0
fmap Data.Vector.Fusion.Stream.Monadic 1.3 2.2
rSquare.p Статистика. Регрессия 1,3 1,5
basicUnsafeWrite Data.Vector.Primitive.Mutable 1.2 1.4
innerProduct. \ Statistics.Matrix.Algorithms 1.0 1.6
qr. \. \ Statistics.Matrix.Algorithms 0.8 1.2
basicUnsafeSlice Data.Vector.Primitive.Mutable 0.5 1.1
транспонировать статистику.Матрица 0,5 1,3  

Справа вверху у нас есть findTagName , выполняющий все распределения. Итак, я просмотрел код и обнаружил, что единственное, что можно выделить, - это S.drop . Эта функция пропускает n элементов в начале строки байта . Оказывается, S.head (S.drop index0 str) выделял промежуточную строку только для того, чтобы получить первый символ этой строки. Он не копировал всю строку, а создавал новый указатель на нее.

Итак, я понял, что могу просто заменить S.head (S.drop n s) на S.index s n :

И действительно, выделения исчезли:

  Проверка GC байтов Case Bytes
Разбор 4 КБ 1,160 0 ОК
Разбор 42 КБ 1,160 0 ОК
Разбор 52kb 1,472 0 OK
Тест xeno-memory-bench: ФИНИШ
Тест ксено-скорости: БЕГ ...
бенчмаркинг 4KB / hexml
время 6,190 мкс (6,159 мкс .. 6,230 мкс)
бенчмаркинг 4KB / xeno
время 4.215 мкс (4,175 мкс .. 4,247 мкс)  

До 4,215 мкс. Это не так быстро, как наш предварительный анализ имени 2,691 мкс. Но нам пришлось заплатить или за дополнительные операции с тегом. Мы просто больше не выделяем, и это здорово.

SAX бесплатно

В конце концов я получил функцию под названием process , которая анализирует XML и запускает события в стиле SAX:

Еще раз спасибо за оптимизацию GHC, простой вызов этой функции и бездействие в точности совпадает с функцией до SAX-ization:

  Проверка GC байтов Case Bytes
Разбор 4kb 1,472 0 OK
Разбор 42 КБ 1,160 0 ОК
Разбор 52kb 1,472 0 OK

бенчмаркинг 4KB / xeno
время 4.320 мкс (4,282 мкс .. 4,361 мкс)  

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

Специализация - по насекомым (и, как бывает, оптимизированным программам)

Интересно то, что добавление прагмы SPECIALIZE для функции process увеличивает скорость примерно на 1 мкс.Специализация означает, что для данной функции, которая является универсальной (полиморфной тип-класс), что означает, что она будет принимать аргумент словаря во время выполнения для конкретного экземпляра, вместо этого мы сгенерируем отдельный фрагмент кода, который специализируется на этом конкретном экземпляре. Ниже приведен специализированный тип монады Identity (т.е. просто чистый, ничего не делает) для процесса .

Перед

  тестирование 4KB / xeno-sax
время 5,877 мкс (5,837 мкс.. 5,926 мкс)
бенчмаркинг 211KB / xeno-sax
время 285,8 мкс (284,7 мкс .. 287,4 мкс)  

после

  тестирование 4KB / xeno-sax
время 5,046 мкс (5,036 мкс .. 5,056 мкс)
бенчмаркинг 211KB / xeno-sax
время 240,6 мкс (240,0 мкс .. 241,5 мкс)  

В случае 4KB это всего лишь 800 нс, но, как мы говорим в Британии, позаботьтесь о пенни, и фунты сами позаботятся о себе. Разница 240-> 285 невелика с практической точки зрения, но когда мы играем в игру на скорость, мы обращаем внимание на подобные вещи.

Где мы находимся: Xeno vs Hexml

В настоящее время интерфейс SAX в Zeno превосходит Hexml в пространстве и времени. Ура! Мы так же быстры, как C!

  Файл hexml-dom xeno-sax
4 КБ 6,134 мкс 5,147 мкс
31 КБ 9,299 мкс 2,879 мкс
211 Кбайт 257,3 мкс 241,0 мкс  

Также стоит отметить, что Haskell делает все это безопасно. Все функции, которые я использую, являются стандартными функциями ByteString, которые проверяют границы и генерируют исключение, если это так. Мы не получаем случайно доступ к памяти, чего не должны делать, и не допускаем ошибок.Сервер продолжает работать.

Если интересно, если мы перейдем на небезопасные функции ( unsafeTake , unsafeIndex из модуля Data.ByteString.Unsafe ), мы получим заметное увеличение скорости:

  Файл hexml-dom xeno-sax
4 КБ 6,134 мкс 4,344 мкс
31 КБ 9,299 мкс 2,570 мкс
211 Кбайт 257,3 мкс 206,9 мкс  

Но нам не нужно выпендриваться. Мы уже изложили свою точку зрения. Мы хаскеллеры, мы любим безопасность. Я сохраню свои безопасные функции.

Но Hexml делает больше!

Было бы упущением, если бы я не обратил внимание на тот факт, что Hexml делает более полезные вещи, чем мы сделали здесь. Hexml выделяет DOM для произвольного доступа. о нет! Распределение: худший враг Хаскелла!

Мы видели, что Haskell обычно выделяет много. Собственно, как следует на это посмотрели?

  Проверка GC байтов Case Bytes
4kb / hexpat-sax 444,176 0 ОК
31kb / hexpat-sax 492,576 0 ОК
211kb / hexpat-sax 21,112,392 40 OK
4kb / hexpat-dom 519,128 0 ОК
31kb / hexpat-dom 575,232 0 ОК
211кб / гекспат-дом 23,182,560 44 ОК  

Хорошо.

Реализация парсера DOM для Xeno

Еще не все потеряно. Hexml - это не простой синтаксический анализатор, который работает быстро, потому что написан на языке C, это еще и достойный алгоритм. Вместо того, чтобы выделять дерево, он выделяет большой плоский вектор узлов и атрибутов, которые содержат смещения в исходной строке. Мы можем сделать это и в Haskell!

Вот мой дизайн структуры данных, содержащейся в векторе. Мы хотим хранить в векторе только целые числа. Целые числа, указывающие на смещения в исходной строке.Вот что я придумал.

У нас есть три вида полезной нагрузки. Элементы, текст и атрибуты:

Это все подробности, о которых я собираюсь рассказать. Вы можете прочитать код, если хотите узнать больше. Это не очень оптимизированный формат. Когда у нас есть такой вектор, можно определить поверх него DOM API, который позволит вам перемещаться по дереву как обычно, что мы увидим позже.

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

Функция выглядит примерно так:

Функция работает в монаде ST , которая позволяет нам локально читать и записывать изменяемые переменные и векторы, оставаясь при этом чистыми снаружи.

Я выделяю массив из 1000 64-битных Ints (на 64-битной архитектуре), я сохраняю переменную текущего размера и текущего родителя (если есть). Текущая родительская переменная позволяет нам, увидев тег, назначить позицию в векторе, в которой родительский элемент закрыт.

Каждый раз, когда мы получаем событие, а массив слишком мал, я увеличиваю массив, удваивая его размер. Эта стратегия скопирована из пакета Hexml.

Наконец, когда мы закончили, мы получаем изменяемый вектор, «замораживаем» его (это означает создание его неизменяемой версии), а затем возвращаем эту копию. Мы используем unsafeFreeze для повторного использования массива без копирования, что включает в себя обещание, что мы не будем использовать изменяемый вектор впоследствии, чего мы не делаем.

Скорость DOM

Давайте посмотрим на скорости:

  Файл hexml-dom xeno-sax xeno-dom
4 КБ 6.123 мкс 5,038 мкс 10,35 мкс
31 КБ 9,417 мкс 2,875 мкс 5,714 мкс
211 КБ 256,3 мкс 240,4 мкс 514,2 мкс  

Неплохо! Парсер DOM лишь <2x медленнее, чем Hexml (за исключением 31 КБ, где он быстрее. shrug ). Здесь я прекратил оптимизацию и решил, что это достаточно хорошо. Но мы можем пересмотреть некоторые решения, принятые по ходу дела.

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

Изначально я пробовал STRef , которые упакованы в коробку. В рамке просто означает, что это указатель на целое число, а не на фактическое целое число. Распакованный Int - это правильный машинный регистр. Используя STRef , мы получаем худшие скорости:

  Файл xeno-dom
4 КБ 12,18 мкс
31 КБ 6,412 мкс
211 КБ 631,1 мкс  

Что является заметной потерей скорости.

Еще одна вещь, которую следует принять во внимание, - это тип массива. Я использую распакованные изменяемые векторы из пакета vector .При использовании атомарных типов, таких как Int, можно использовать распакованные векторы. Если я использую обычные упакованные векторы из Data.Vector , скорость снизится до:

  Файл xeno-dom
4 КБ 11,95 мкс (от 10,35 мкс)
31 КБ 6,430 мкс (от 5,714 мкс)
211 КБ 1,402 мс (от 514,2 мкс)  

Помимо того, что для записи требуется немного больше времени, он также выделяет в 1,5 раза больше материала:

  Проверка GC байтов Case Bytes
4kb / xeno / dom 11240 0 ОК
31kb / xeno / dom 10,232 0 ОК
211kb / xeno / dom 1,082,696 0 ОК  

становится

  Проверка GC байтов Case Bytes
4kb / xeno / dom 22,816 0 ОК
31kb / xeno / dom 14,968 0 ОК
211kb / xeno / dom 1,638,392 1 ОК  

Видите там GC? Нам это не нужно.

Наконец, еще одно замечание для парсера DOM. Если мы откажемся от безопасности и воспользуемся методами unsafeWrite и unsafeRead из векторного пакета, мы действительно увидим небольшое увеличение:

  Файл xeno-dom
4 КБ 9,827 мкс
31 КБ 5,545 мкс
211 КБ 490,1 мкс  

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

DOM API

Я написал несколько функций для доступа к нашему вектору и предоставления DOM-подобного API:

Итак, это работает.

Подведение итогов

Окончательные результаты находятся в:

И просто чтобы убедиться, что файл размером 1 МБ не дает сильно различающихся результатов:

  бенчмаркинг 1MB / hexml-dom
время 1,225 мс (1,221 мс .. 1,229 мс)
                     1.000 кв.м (1.000 кв.м .. 1.000 кв.м)
среднее 1,239 мс (1,234 мс .. 1,249 мс)
стандартное отклонение 25,23 мкс (12,28 ... 40,84 мкс)

бенчмаркинг 1MB / xeno-sax
время 1,206 мс (1,203 мс.. 1,211 мс)
                     1.000 кв.м (1.000 кв.м .. 1.000 кв.м)
среднее 1,213 мс (1,210 мс .. 1,218 мс)
стандартное отклонение 14,58 мкс (10,18 мкс .. 21,34 мкс)

бенчмаркинг 1MB / xeno-dom
время 2,768 мс (2,756 мс .. 2,779 мс)
                     1.000 кв.м (1.000 кв.м .. 1.000 кв.м)
среднее 2,801 мс (2,791 мс .. 2,816 мс)
стандартное отклонение 41,10 мкс (30,14 мкс .. 62,60 мкс)  

Тада! Мы сопоставили Hexml в чистом Haskell, используя безопасные функции доступа.Мы предоставили SAX API, который работает очень быстро, и простой демонстрационный парсер DOM со знакомым API, который также довольно быстр. При этом мы используем достаточно мало памяти.

ОБНОВЛЕНИЕ : Некоторые люди просили сравнения с libxml2 (предполагая, что это как-то быстрее). Вот отчет о критериях.

Этот пакет представляет собой эксперимент в образовательных целях, чтобы показать, что Haskell может и чего нет, для очень конкретной проблемы предметной области. Если вы хотите использовать этот пакет, подумайте о том, чтобы принять его и подарить ему хороший дом.Я не ищу дополнительных пакетов для обслуживания.

Работа с файлами XML из сценариев

Для работы с произвольными файлами XML вы можете использовать объекты XML DOM. Эти объекты предоставляют COM-интерфейс для каждого элемента и атрибута XML-документа. Все взаимодействия с файлами XML выполняются через Microsoft XML Core Services (MSXML):

Для получения дополнительных сведений о выражениях XPath и объектах XML DOM, а также об их методах и свойствах см. Соответствующую документацию в библиотеке MSDN:

В этом разделе все примеры работают с данными.xml, расположенный в корневой папке диска C . Файл должен содержать следующий код:

В этом файле есть корневой узел "control" с пятью подузлами. Каждый подузел имеет три узла: тип, имя и значение. Для последних двух узлов также указано пространство имен.

Пример 1. Открытие файлов XML

Следующий код показывает, как открыть XML-файл и проанализировать его.

В этом примере процедура TestXML создает новый объект XML DOM Document через COM и загружает данные из Data.xml файл. При загрузке анализатор XML проверяет документ. Сценарий также проверяет результат проверки с помощью объекта parseError . Если файл был загружен успешно, тест получает корневой узел и передает его программе ProcessNode для обработки.

Процедура ProcessNode записывает имя и значение узла в журнал (если узел не содержит значения, значение не публикуется). Затем процедура обрабатывает атрибуты узла и дочерние узлы.

Пример 2: Использование выражений XPath для синтаксического анализа файлов XML

Для синтаксического анализа файлов XML с объектами DOM можно также использовать выражения XPath. Это позволит вам легко получить список необходимых узлов, не разбирая весь документ. В следующем коде показано, как получить коллекцию узлов и подузлов процесса.

Приведенный выше код очень похож на предыдущий пример. Единственное отличие состоит в том, что мы вызываем метод selectNodes и передаем ему выражение XPath.Метод возвращает коллекцию запрошенных объектов. Затем разбираем коллекцию.

Пример 3: Узлы синтаксического анализа с пространствами имен

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

Приведенный выше код очень похож на предыдущие примеры. В этом примере мы определяем свойство SelectionNamespaces в выражении setProperty и передаем ему выражение XPath для обработки только узла с указанным пространством имен.Пространства имен чувствительны к регистру.

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *