XML
XML (МФА: [ˌeks.emˈel], аббр. от англ. eXtensible Markup Language) — «расширяемый язык разметки». Рекомендован Консорциумом Всемирной паутины (W3C). Спецификация XML описывает XML-документы и частично описывает поведение XML-процессоров (программ, читающих XML-документы и обеспечивающих доступ к их содержимому). XML разрабатывался как язык с простым формальным синтаксисом, удобный для создания и обработки документов как программами, так и человеком, с акцентом на использование в Интернете. Язык называется расширяемым, поскольку он не фиксирует разметку, используемую в документах: разработчик волен создать разметку в соответствии с потребностями к конкретной области, будучи ограниченным лишь синтаксическими правилами языка. Расширение XML — это конкретная грамматика, созданная на базе XML и представленная словарём тегов и их атрибутов, а также набором правил, определяющих, какие атрибуты и элементы могут входить в состав других элементов. Сочетание простого формального синтаксиса, удобства для человека, расширяемости, а также базирование на кодировках Юникод для представления содержания документов привело к широкому использованию как, собственно, XML, так и множества производных специализированных языков на базе XML в самых разнообразных программных средствах. XML является подмножеством SGML.[источник не указан 16 дней] На основе XML создаются специализированные форматы для хранения диаграмм, концептуальных карт и других моделей данных. Язык XMLСпецификация XML описывает язык и ряд вопросов, касающихся кодировки и обработки документов. Материал секции представляет собой сокращённое изложение описания языка в Спецификации XML, адаптированное для настоящей статьи. Нормативным считается английский вариант документа, поэтому основные термины приводятся с их английскими оригиналами. Перевод основных терминов в основном следует доступному в интернете переводу Спецификации на русский язык, исключение составляют термины tag и declaration. Для термина tag здесь используется перевод тег. Для термина declaration отдано предпочтение распространённому переводу объявление (против также распространённой кальки декларация). В литературе и интернете могут встречаться и иные переводы основных терминов. Физическая и логическая структуры документаС физической точки зрения документ состоит из сущностей (англ. entities), из которых каждая может ссылаться на другую сущность. Единственный корневой элемент — документная сущность. Содержание сущностей — символы. С логической точки зрения документ состоит из комментариев (англ. comments), объявлений (англ. declarations), элементов (англ. elements), ссылок на сущности (англ. character references) и инструкций обработки (англ. processing instructions). Всё это в документе структуризуется разметкой (англ. markup). Физическая структураСущность — мельчайшая часть в документе. Все сущности что-нибудь содержат, и у всех них есть имя (существуют исключения, напр. документная сущность). Проще говоря, термин «сущность» описывает «сущую вещь», «что-то»[6]. Документ состоит из сущностей, содержание которых — символы. Все символы разделены на два типа: символы данных (англ. character data) и символы разметки. К разметке относятся:
Часть документа, не принадлежащая разметке, составляет символьные данные документа. Логическая структураВсе составляющие части документа обобщаются в пролог и корневой элемент. Корневой элемент — обязательная часть документа, составляющая всю его суть (пролог, вообще говоря, может отсутствовать). Корневой элемент может включать (а может не включать) вложенные в него элементы, символьные данные и комментарии. Вложенные в корневой элемент элементы, в свою очередь, могут включать вложенные в них элементы, символьные данные и комментарии, и так далее. Пролог может включать объявления, инструкции обработки, комментарии. Его следует начинать с объявления XML, хотя в определённой ситуации допускается отсутствие этого объявления. Элементы документа должны быть правильно вложены: любой элемент, начинающийся внутри другого элемента (то есть любой элемент документа, кроме корневого), должен заканчиваться внутри элемента, в котором он начался. Символьные данные могут встречаться внутри элементов как непосредственно так и в специальных секциях «CDATA». Объявления, инструкции обработки и элементы могут иметь связанные с ними атрибуты. Атрибуты используются для связывания с логической единицей текста пар «имя-значение». Символы разметкиРазметка всегда начинается символом Наряду с символами Решение проблемы неоднозначности разметкиУпотребление разметочных символов в символьных данных затрудняет распознавание конструкций разметки и может создать проблему неоднозначности структуры. В XML эта проблема решается следующим образом: <, > и & не могут присутствовать в символьных данных и в значениях атрибутов в их непосредственном виде, для их представления в этих случаях зарезервированы специальные сущности:
Кроме того, для употребления апострофов и кавычек внутри значений атрибутов используются следующие сущности:
Правило замены разметочных символов на их обозначающие сущности не распространяется на символьные данные в секциях «CDATA», зато выполняется во всех остальных местах документа. Числовые ссылки на символыЧисловые ссылки на символы указывают кодовую позицию символа в наборе символов документа. Числовые ссылки на символы могут принимать две формы[7]:
Примеры числовых ссылок на символы:
ИменаВ языке XML все имена должны начинаться с буквы, символа подчёркивания (_) и продолжаться только допустимыми для имён символами, а именно: они могут содержать только буквы, входящие в секцию букв кодировки Unicode, арабские цифры, дефисы, знаки подчёркивания, точки. Так как буквы не ограничены исключительно символами ASCII, то в именах можно использовать буквы из любого языка. ПрологОбъявление XMLОбъявление XML указывает версию языка, на которой написан документ. Поскольку интерпретация содержимого документа зависит от версии языка, спецификация предписывает начинать документ с объявления XML. В первой (1.0) версии языка использование объявления не было обязательным, в последующих версиях оно обязательно. Если объявление отсутствует, версия языка считается равной 1.0. Кроме версии XML, объявление может содержать информацию о кодировке документа и атрибут Примеры: <?xml version="1.1" encoding="UTF-8"?>
<?xml version="1.0" encoding="windows-1251"?>
Атрибут
Если атрибут отсутствует, его значение по умолчанию считается равным Примеры с использованием атрибута: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
Объявление типа документаДля объявления типа документа существует специальная инструкция Например, вот корректный документ: <?xml version="1.0"?>
<greeting>Hello, world!</greeting>
В нём есть корневой элемент При помощи Объявления типа документа (DTD) возможно описывать его содержание и логическую структуру, а также связывать с определённым элементом пару «имя — значение». Вот как выглядит пролог в записи Бэкуса — Наура[10]: prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') Eq ::= S? '=' S? VersionNum ::= '1.' [0-9]+ Misc ::= Comment | PI | S doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' DeclSep ::= PEReference | S intSubset ::= (markupdecl | DeclSep)* markupdecl ::= elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment extSubset ::= TextDecl? extSubsetDecl extSubsetDecl ::= ( markupdecl | conditionalSect | DeclSep)* После XML-объявления могут следовать комментарии, инструкции обработки или же пустые пространства[11], но затем идёт Объявления типа документа, где «Name» — имя корневого тега, «ExternalID» — внешний идентификатор, а «intSubset» — объявление разметки или же ссылка на сущность. Как гласит спецификация, если внешний идентификатор объявляется вместе с внутренним объявлением, то последнее идёт перед первым[12]. Например: <?xml version="1.0"?>
<!DOCTYPE greeting SYSTEM "hello.dtd">
<greeting>Hello, world!</greeting>
Здесь « <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE greeting [
<!ELEMENT greeting (#PCDATA)>
]>
<greeting>Hello, world!</greeting>
Здесь же разметка была объявлена локально в инструкции Инструкция обработкиИнструкции обработки (англ. processing instruction, PI), позволяют размещать в документе инструкции для приложений. В следующем примере показана инструкция обработки xml-stylesheet, передающая xml-stylesheet-приложению (например, браузеру) инструкции в файле my-style.css посредством атрибута href: <?xml-stylesheet type="text/css" href="my-style.css"?>
КомментарийКомментарии (англ. comment) не относятся к символьным данным документа. Комментарий начинается последовательностью «<!--» и заканчивается последовательностью «-->», внутри не может встречаться комбинация символов «--». Символ & не используется внутри комментария в качестве разметки. Пример: <!-- это комментарий -->
Корневой элементЭлемент и его разметкаЭлемент (англ. element) является понятием логической структуры документа. Каждый документ содержит один или несколько элементов. Границы элементов представлены начальным и конечным тегами. Имя элемента в начальном и конечном тегах элемента должно совпадать. Элемент может быть также представлен тегом пустого элемента, то есть не включающего в себя другие элементы и символьные данные. Тег (англ. tag) — конструкция разметки, которая содержит имя элемента. Начальный тег: Конечный тег: Тег пустого элемента: В элементе атрибуты могут использоваться только в начальном теге и теге пустого элемента. Пример кулинарного рецепта, размеченного с помощью XML: <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE recipe>
<recipe name="хлеб" preptime="5min" cooktime="180min">
<title>
Простой хлеб
</title>
<composition>
<ingredient amount="3" unit="стакан">Мука</ingredient>
<ingredient amount="0.25" unit="грамм">Дрожжи</ingredient>
<ingredient amount="1.5" unit="стакан">Тёплая вода</ingredient>
</composition>
<instructions>
<step>
Смешать все ингредиенты и тщательно замесить.
</step>
<step>
Закрыть тканью и оставить на один час в тёплом помещении.
</step>
<!--
<step>
Почитать вчерашнюю газету.
</step>
- это сомнительный шаг...
-->
<step>
Замесить ещё раз, положить на противень и поставить в духовку.
</step>
</instructions>
</recipe>
Секция CDATAСекция CDATA используется для включения фрагментов текста, в которых символы Корректный документКорректный (англ. well-formed) документ соответствует всем общим правилам синтаксиса XML, применимым к любому XML-документу: правильная структура документа, совпадение имен в начальном и конечном теге элемента и т. п. Документ, который неправильно построен, не может считаться документом XML. Пространства имёнПример документа: <?xml version="1.0" encoding="UTF-8"?>
<!-- login screen -->
<edsscript>
<sequence name="start">
<action cmd="triggeron">
btn*
</action>
<action cmd="triggeron">
msg_generic
</action>
<action cmd="disablenbb">
all
</action>
<action cmd="setscrtext">
@@Sisteme Giriş@@
</action>
<action cmd="enablenbb">
forward,mainmenu
</action>
<action cmd="switchmsgtarget">
LOGIN_DLG
</action>
<action cmd="sendmsg">
start
</action>
<action cmd="jump">
step2
</action>
</sequence>
<sequence name="step2">
<action cmd="waittrigger">
btnforward
</action>
<action cmd="triggeron">
login*
</action>
<action cmd="disablenbb">
all
</action>
<action cmd="sendmsg">
check
</action>
</sequence>
<trigger name="login_succeded">
<condition type="appmsg">
login_succeeded
</condition>
<sequence>
<action cmd="endscript" />
</sequence>
</trigger>
<trigger name="login_unknownuser">
<condition type="appmsg">
login_unknownuser
</condition>
<sequence name="login_unknownuser">
<action cmd="disablenbb">
all
</action>
<action cmd="setscrtext">
@@Hata@@
</action>
<action cmd="showhtml">
generic_neg.htm,@@Yanlış kullanıcı ismi@@,@@Lütfen kullanıcı ismini doğru giriniz.@@
</action>
<action cmd="enablenbb">
back
</action>
<action cmd="waittrigger">
btnback
</action>
<action cmd="jump">
start
</action>
</sequence>
</trigger>
<trigger name="login_incorrectpwd">
<condition type="appmsg">
login_incorrectpwd
</condition>
<sequence name="login_incorrectpwd">
<action cmd="disablenbb">
all
</action>
<action cmd="setscrtext">
@@Hata@@
</action>
<action cmd="showhtml">
generic_neg.htm,@@Hatalı parola@@,@@Lütfen parolanızı doğru giriniz.@@
</action>
<action cmd="enablenbb">
back
</action>
<action cmd="waittrigger">
btnback
</action>
<action cmd="jump">
start
</action>
</sequence>
</trigger>
<!-- generic triggers -->
<trigger name="btnback">
<condition type="buttonclick">
back
</condition>
<sequence name="btnback">
<action cmd="triggeron">
btnback
</action>
</sequence>
</trigger>
<trigger name="btnforward">
<condition type="buttonclick">
forward
</condition>
<sequence name="btnforward">
<action cmd="triggeron">
btnforward
</action>
</sequence>
</trigger>
<trigger name="btnmainmenu">
<condition type="buttonclick">
mainmenu
</condition>
<sequence>
<action cmd="jumpscript">
<value label="mainmenuscript" scope="local" />
</action>
</sequence>
</trigger>
<trigger name="btnquitapp">
<condition type="buttonclick">
quitapplication
</condition>
<sequence name="btnquitapp">
<action cmd="callscript">
quitapp.xml
</action>
<action cmd="jump">
start
</action>
</sequence>
</trigger>
<trigger name="error_generic">
<condition type="appmsg">
error*
</condition>
<sequence>
<action cmd="showhtml">
errdsc_null.htm,@@Hata@@
</action>
<action cmd="disablenbb">
all
</action>
<action cmd="enablenbb">
forward
</action>
<action cmd="waittrigger">
btnforward
</action>
<action cmd="endscript" />
</sequence>
</trigger>
<trigger name="msg_generic">
<condition type="appmsg">
msg_generic
</condition>
<sequence>
<action cmd="showhtml">
generic_msg.htm
</action>
<action cmd="triggeron">
msg_generic
</action>
</sequence>
</trigger>
<!-- An unhandled exception is thrown from the hard code side. -->
<trigger name="error_hardcodeside">
<condition type="appmsg">
error_hardcodeside
</condition>
<sequence>
<action cmd="triggeroff">
*
</action>
<action cmd="triggeron">
btnmainmenu
</action>
<action cmd="triggeron">
btnquitapp
</action>
<action cmd="disablenbb">
all
</action>
<action cmd="enablenbb">
mainmenu
</action>
<action cmd="showhtml">
errdsc_null.htm,Hata, @@İşlem sırasında bir hata meydana geldi.@@
</action>
<action cmd="waittrigger">
btnmainmenu
</action>
</sequence>
</trigger>
</edsscript>
Регламентация работы с документами: правила, языки, программные интерфейсыЭтот раздел содержит изложение некоторых положений рекомендаций W3C, касающихся работы с документами. Соответствующие рекомендации могут относиться как к документам XML, так и к более широкому классу документов. Ссылки, как правило, даются на средства работы с документами, рекомендованные W3C. Кодировка документовСпецификация требует, чтобы обрабатывающие программы поддерживали по крайней мере две кодировки Юникод: UTF-8 и UTF-16. XML-процессор и приложениеСпецификация XML определяет понятия XML-процессор и приложение. XML-процессор (парсер) — программа, анализирующая разметку и передающая информацию о структуре документа другой программе — приложению. Спецификация XML налагает определённые требования на процессор, не касаясь требований к приложению. Действительный документ. Проверяющие и непроверяющие процессорыДокумент является действительным, если с ним связано определение типа документа и если этот документ отвечает представленным в определении типа документа ограничениям. XML-процессоры делятся на два класса: проверяющие и непроверяющие. Проверяющие процессоры проверяют действительность документа и должны сообщать (по выбору пользователя) о нарушении ограничений, сформулированных в определении типа документа. Непроверяющие процессоры не проверяют действительность документа, но обязанности по предварительной обработке документа, упомянутые выше, остаются за ними. Описание типов документов: языки схемДля описания типов документов используются языки схем (англ. schema language). Поскольку XML является подмножеством языка SGML[источник не указан 16 дней], то он унаследовал разработанный для SGML язык Document Type Definition (DTD). Позднее были разработаны и другие языки схем, наиболее известны из которых XML Schema, RELAX NG. Преобразование документа XMLДля решения задачи преобразования документа XML в другую схему или другой формат предназначен язык XSLT. Формат для визуализации документаДля форматированного документа (документа, подготовленного к визуализации) предназначен формат XSL-FO. Языки запросовXPath — синтаксис для адресации содержимого документа, представленного в форме дерева. Выражения XPath используются в языке XQuery. Выражения XPath, вообще говоря, могут использоваться в любом контексте, где уместно использовать формальные ссылки на элементы дерева, в частности, в качестве параметров методов интерфейсов доступа к документу. XQuery — язык программирования, ориентированный на работу с документами. Чтение XML: три варианта API
Для чтения XML есть три варианта API[14]. Событийный API (event-driven API, push-style API) — XML-процессор читает XML; при определённом событии (появлении открывающего или закрывающего тега, текстовой строки, атрибута) вызывается callback-функция.
Все пять примеров работают с таким XML <?xml version="1.0" encoding="UTF-8" ?>
<document>
<thing name="A">Alpha</thing>
<thing name="B">Bravo</thing>
</document>
Пример кода (C++, выдуманный API) enum class Place { ROOT, DOCUMENT, THING, N }
Place parentPlace[static_cast<int>(Place::N)] = { ROOT, ROOT, DOCUMENT };
class MyEvent : public Xml::Event
{
private:
Place place = Place::ROOT;
Thing* currThing = nullptr;
public:
/// @return true — тег нужен; false — пропустить его и всё, что внутри
bool onTagOpen(const std::string& aName) override;
void onTagClose() override;
void onAttr(const std::string& aName, const std::string& aValue) override;
void onText(const std::string& aText) override;
}
bool MyEvent::onTagOpen(const std::string& aName)
{
switch (place) {
case Place::ROOT:
if (aName == "document") {
place = Place::DOCUMENT;
return true;
}
break;
case Place::DOCUMENT:
if (aName == "thing") {
place = Place::THING;
currThing = &things.emplace_back();
return true;
}
break;
}
return false;
}
void MyEvent::onTagClose()
{
place = parentPlace[place];
}
void MyEvent::onAttr(const std::string& aName, const std::string& aValue)
{
if (place == Place::THING && aName == "name")
currThing->name = aValue;
}
void MyEvent::onText(const std::string& aText)
{
if (place == Place::THING)
currThing->value = aText;
}
xml::eventDrivenRead("in.xml", MyEvent());
Потоковый API (также pull-style API) — устроен на манер потоков ввода-вывода. Прикладной код запрашивает у процессора части XML, тот умеет только двигаться по XML вперёд, забывая уже пройденные части.
Пример кода (C++, выдуманный API) xml::StreamReader reader("in.xml");
reader.enterTag("document");
while (reader.getTag("thing") {
Thing thing;
thing.name = reader.requireStringAttr("name");
reader.enterTag();
thing.value = reader.getText();
reader.leaveTag();
things.emplace_back(std::move(thing));
}
Объектный API (Document Object Model, DOM, «объектная модель документа») — считывает XML и воссоздаёт его в памяти в виде объектной структуры.
Пример кода (C++, pugixml) #include <iostream>
#include <vector>
#include "pugixml.hpp"
struct Thing {
std::string name, value;
};
// Если какая-то сущность pugixml конвертируется в bool как false — выкинуть ошибку!
template <class T>
inline T need(T&& val, const char* errmsg)
{
if (!val) throw std::logic_error(errmsg);
return std::forward<T>(val);
}
int main()
{
std::vector<Thing> things;
pugi::xml_document doc;
need(doc.load_file("in.xml"), "Cannot load XML!");
auto elDocument = need(doc.root().child("document"), "Need <document>");
for (pugi::xml_node elThing : elDocument.children("thing")) {
auto attrName = need(elThing.attribute("name"), "Need <thing>.name!");
things.emplace_back( Thing { attrName.as_string(), elThing.text().as_string() } );
}
for (auto &v : things) {
std::cout << v.name << "=" << v.value << std::endl;
}
return 0;
}
Бывают и гибридные API: внешние и маловажные части читаются потоковым методом, а внутренние и важные — объектным. Пример кода (C++, выдуманный API) xml::StreamReader reader("in.xml");
std::string name, value;
reader.enterTag("document");
while (reader.getTag("thing") {
xml::Element* elThing = reader.readEntireSubtree();
things.emplace_back();
Thing& thing = things.back();
thing.name = elThing.requireStringAttr("name");
thing.value = elThing.text();
}
Запись XML: два варианта APIAPI прямой записи записывает XML тег за тегом, атрибут за атрибутом.
Пример кода (C++, выдуманный API) xml::Writer wri("out.xml");
wri.openTag("document");
for (auto &v : things) {
wri.openTag("thing");
wri.writeAttr("name", v.name);
wri.writeText(v.value);
wri.closeTag("thing");
}
wri.closeTag("document");
Объектный API, он же Document Object Model.
Пример кода (C++, pugixml) #include "pugixml.hpp"
struct Thing { std::string name, value; };
Thing things[] { { "A", "Alpha", }, { "B", "Bravo", }, { "C", "Charlie" } };
int main()
{
pugi::xml_document doc;
auto root = doc.append_child("document");
for (auto& thing : things) {
auto node = root.append_child("thing");
node.append_attribute("name") = thing.name.c_str();
node.append_child(pugi::node_pcdata).set_value(thing.value.c_str());
}
doc.save_file("test.xml");
return 0;
}
Инструменты работы с документами: парсеры, средства создания и визуализации, системы баз данныхРеализации парсеровXML имеет реализации парсеров для всех современных языков программирования[19]. Веб-браузеры как инструмент визуализации документаВизуализация без использования стилей CSSБез использования CSS или XSL XML-документ отображается как простой текст в большинстве веб-браузеров. Некоторые браузеры, такие как Internet Explorer, Mozilla Firefox и Opera (встроенный инструмент Opera Dragonfly) отображают структуру документа в виде дерева, позволяя сворачивать и разворачивать узлы с помощью нажатий клавиши мыши. Применение стилей CSSПроцесс аналогичен применению CSS к HTML-документу для отображения. Для применения CSS при отображении в браузере, XML-документ должен содержать специальную ссылку на таблицу стилей. Например: <?xml-stylesheet type="text/css" href="myStyleSheet.css"?>
Это отличается от подхода HTML, где используется элемент <link>. Применение преобразований к формату XSL-FOСовременные браузеры принадлежат к числу программных средств, способных выполнять преобразования XSLT. В браузере такое преобразование выполняется, как правило, для форматирования документа (преобразования документа в формат XSL-FO)[источник не указан 16 дней]. Следующая инструкция в прологе документа XML предписывает браузеру выполнить XSLT-преобразование, описанное в файле transform.xsl: <?xml-stylesheet type="text/xsl" href="transform.xsl"?>
Редакторы XMLС документом XML можно работать в обычном текстовом редакторе, однако обычные редакторы не поддерживают структуру документа. Существуют специальные редакторы XML, которые делают работу с документом более удобной и эффективной. Системы управления базами данных, работающие с данными в формате XMLСистема управления базами данных DB2 позволяет хранить данные в формате XML и предоставляет доступ к таким данным с помощью языка XQuery. Поддержка на аппаратном уровнеXML поддерживается на низком аппаратном, микропрограммном и программном уровнях в современных аппаратных решениях[20]. Конвертация XMLXML можно конвертировать в другие форматы, включая JSON, HTML, CSV и YAML. Для конвертации можно использовать программы EasyDataTransform, PDFElement и Advanced XML Converter.[21] Область применения, ограничения, перспективы развитияЭффективность использования XMLXML — язык разметки, другими словами, средство описания документа. Именно в нише документов, текстов, где доля разнотипных символьных данных велика, а доля разметки мала — XML успешен. С другой стороны, обмен данными в открытых системах не сводится к обмену документами. Избыточность разметки XML (а в целях разработки языка прямо указано, что лаконичность не является приоритетом проекта) сказывается в ситуациях, когда данные не вписываются в традиционную модель документа. Лента новостей, например, оформляемая с использованием синтаксиса XML (форматы RSS, Atom), представляет собой не документ в традиционном понимании, а поток однотипных мини-документов — многословная и избыточная разметка в этом случае составляет существенную часть передаваемых данных. W3C озабочен эффективностью применения XML, и соответствующие рабочие группы занимаются этой проблемой (к началу 2013 года нормативные документы не разработаны). Другая ситуация, когда форматы XML могут оказаться не лучшим решением — работа с данными с простой структурой и небольшим объёмом символьных данных (поля данных). В этом случае доля разметки в общем объёме велика, а программная обработка XML может оказаться неоправданно затратной по сравнению с работой с данными более простой структуры. В этой области разработчики рассматривают средства, изначально ориентированные на данные, такие как INI, YAML, JSON. См. также
Примечания
Литература
Ссылки
|