Введение в XML
Xml — это язык разметки, являющий собой способ представления структурированных данных. Он:
- Универсальный, расширяемый.
- Независимый от платформы, операционной системы.
- Позволяет сохранять описательные данные (метаданные).
В xml в качестве некой единицы измерения представлен “документ”. Это некая законченная порция данных.
Документ может содержать:
- данные (само содержание),
- структуру (иерархичность данных),
- представление (то, как все это сможет увидеть конечный пользователь).
Различия XML и HTML
HTML описывает ИЗ ЧЕГО СОСТОИТ и КАК отображать документ.
Пример:
<table> <tbody> <tr> <td>NAME</td> <td>IVAN</td> </tr> <tr> <td>SALARY</td> <td>1000000</td> </tr> </tbody> </table>
XML определяет ЗНАЧЕНИЕ и ОТНОШЕНИЕ данных
<employee> <name>IVAN</name> <salary>1000000</salary> </employee>
XML теги
XML использует теги для определения данных.

Рисунок №1 — пример тега xml
В совокупности открывающий тег и закрывающий, а также содержание этих тегов, называется элемент. Элементы можно вкладывать друг в друга.
<employee> <name>Ivan</name> <salary>100000</salary> </employee>
Синтаксис, грамматика и семантика элементов
- Синтаксис — правила записи элементов разметки.
- Грамматика — отношения элементов разметки друг к другу.
- Семантика — смысловые значения элементов разметки.
В xml на базовом уровне есть только синтаксис. Грамматики нет, так как изначально не определено ни одного тега. Семантики изначально также нет, по той же причине. Все это появляется только в процессе создания своих тегов и и привязывания к ним того или иного смысла.
Более подробно о синтаксисе
Рассмотрим, из чего состоит xml документ и его структуру (рис. 2)

Рисунок №2 — Пример xml документа
Декларация (инструкция по обработке) не несет в себе данных, а несет инструкции о том, как их обрабатывать. Инструкций может быть любое количество. Например, у нас может быть такой документ:
<?xml version="1.0" encoding="UTF-8"?> <?format drive="c"?> <data> </data>
Тут мы видим уже 2 инструкции по обработке. Вторая инструкция дает команду отформатировать диск С. В базовой конфигурации такой инструкции нет, это пример расширяемости языка. Но мы можем передавать этот документ в другую программу, где на эту инструкции будет прописана соответствующая реакция.
Любой элемент в xml регистрозависимый. Т.е. теги можно писать как в нижнем, так и в верхнем регистре, главное единообразие.
Все теги в xml должны быть закрыты. В тех случаях, когда тег не подразумевает в себе содержимого, используется сокращенный синтаксис.
- стандартный вариант — <exists></exists>
- сокращенный вариант — <exists />
При возникновении необходимости использовать внутри тега строку, содержащую запрещенные символы (>,<,&), используется конструкция CDATA. Т.е. мы указываем, что содержание нужно воспринимать просто как строку, а не анализировать содержание.
Пример
<?xml version="1.0" encoding="UTF-8"?> <?format drive="c"?> <data> <desc> <![CDATA[ Тут идет текст, в котором используются запрещенные символы >, <, &. ]]> </desc> </data>
Все элементы могут содержать атрибуты. Значения атрибутов, по правилам синтаксиса, должны быть в двойных кавычках. Некоторые парсеры xml документов позволяют использовать в атрибутах одинарные. Повторяющихся атрибутов в рамках одного элемента не должно быть.
Well-formed (синтаксически корректный) и валидный xml
Well-formed — данный статус документ получает в том случае, если он соответствует всем правилам синтаксиса. По сути, если при открытии браузером документа он не выдал ошибку, значит он корректен.
Валидный документ — это, во-первых, синтаксически корректный документ, а во-вторых, соответствующий заранее определенному набору правил или структуре документа.
Для описания структуры документа используются:
- DTD — document Type Definition
- XML схемы
Работа с XML средствами PHP
Simple API for XML (SAX)
SAX — этот инструмент позволяет читать xml документ и получать из него данные. Создать или же, например, изменить xml документ при помощи данного инструмента невозможно.
Логика работы проста, — парсер имеет три события:
- когда он обнаруживает открывающий тег,
- когда он обнаруживает закрывающий тег,
- когда он обнаруживает содержимое тега.
Т.е. необходимо описать функции, которые отработают, когда будут происходить вышеперечисленные события.
Пример
<?php #Создание парсера $sax = xml_parser_create("utf-8"); #Функция, которая вызывается, когда парсер обнаруживает открывающий тег /* $parser - парсер передает сам себя, $tag - в этот параметр будет передан открывающий тег в верхнем регистре, $attributes - если у тега есть атрибуты, то в этот параметр придет ассоциативный массив */ function onStart($parser, $tag, $attributes){ if($tag != "CATALOG" & $tag != "BOOK") echo "<td>"; if($tag == "BOOK") echo "<tr>"; } #Функция, которая вызывается, когда парсер обнаруживает закрывающий тег /* Параметры заполняются аналогично. Параметр $attributes отсутствует. */ function onEnd($parser, $tag){ if($tag != "CATALOG" & $tag != "BOOK") echo "</td>"; if($tag == "BOOK") echo "</tr>"; } #Функция, которая вызывается, когда парсер обнаруживает содержимое тега /* $parser - парсер передает сам себя, $text - в этот параметр передается содержимое тега */ function onText($parser, $text){ echo "$text"; } #При помощи функции xml_set_element_handler, мы передаем имена функций для #события "открывающий тег" и "закрывающий тег" xml_set_element_handler($sax, "onStart", "onEnd"); #При помощи функции xml_set_character_data_handler, #передаем имя функции для события "содержимое тега" xml_set_character_data_handler($sax, "onText"); $file = "catalog.xml"; if (!($fp = fopen($file, "r"))) { die("Невозможно произвести чтение XML"); } #Запускаем парсер while ($data = fread($fp, 4096)) { if (!xml_parse($sax, $data, feof($fp))) { die(sprintf("Ошибка XML: %s на строке %d", xml_error_string(xml_get_error_code($sax)), xml_get_current_line_number($sax)) . PHP_EOL); } } #В результате получим такой HTML /* <tr> <td>Братья Карамазовы</td> <td>Великая книга</td> <td>1000</td> </tr> <tr> <td>Страдания юного Вертера</td> <td>Стоящая книга</td> <td>100</td> </tr> */ #xml for example /* <?xml version="1.0" encoding="utf-8"?> <catalog> <book> <author> Aleks Gomer </author> <title> XML and IES </title> <pubyear> 2000 </pubyear> <price> 200 </price> </book> <book> <author> Достоевский </author> <title> Идиот </title> <pubyear> 1868 </pubyear> <price> 400 </price> </book> </catalog> */
DOM
DOM (Document Object Model) — это интерфейс, позволяющий программам управлять содержимым документов xml, а также изменять их структуру. Данный интерфейс представляет xml документ в виде дерева узлов. Работа с DOM парсером является самым ресурсоемким процессом, так как весь документ записывается в память и в памяти строится дерево узлов.
Например, документ:
<catalog> <book> <author> Достоевский </author> <title> Братья Карамазовы </title> </book> <book> <author> Гете </author> <title> Страдания юного Вертера </title> </book> </catalog>
Будет иметь следующий вид (рис. 3)

Рисунок №3 — Пример построенного DOM дерева xml документа
Идея заключается в том, что все, что есть в xml документе это — узел. В том числе и комментарий. И каждый узел является объектом. Логика аналогичная с DOM деревом html и тем как с ним работает JavaScript. Т.е. все узлы предстают в виде объектов, у которых есть свойства и методы. Тут есть важный момент, логично предположить, что если обратиться к свойству или методу объекта, которого у него нет, мы получим ошибку. И для того, чтобы такую ошибку не получить нужно знать, какие есть типы узлов и какие свойства и методы доступны каждому типу. Типы узлов xml документа представлены на рисунке 4.

Рисунок №4 — типы узлов xml документа
Схематично, связь между узлами можно представить следующим образом (рис 5).

Рисунок №5 — Связь между узлами
Базовое использование DOM для чтения из файла
//создаем объект, который будет экземпляром класса DomDocument $dom = new DomDocument(); //Загружаем наш xml файл $dom->load("catalog.xml"); //Так как в файле, в любом случае, есть корневой элемент, //получаем первым делом именно его. //Для этого используется свойство документа documentElement $root = $dom->documentElement; //Если запросить тип узла, который сейчас находится в root //получим 1 echo $root->nodeType; //Для получения списка/коллекции всех "детей"/дочерних узлов, корневого элемента //используем свойство childNodes //Дочерними узлами корневого элемента в нашем случае будут элементы book $children = $root->childNodes; //Для получения текстового контента используется свойство textContent $textContent = $root->textContent; //Для того, чтобы получить коллекцию элементов по их имени, //используется метод getElementsByTagName("elementName") $books = $dom->getElementsByTagName("book");
Чтение xml документа
<!-- содержание xml файла --> <?xml version="1.0" encoding="UTF-8"?> <catalog> <book> <title>Братья Карамазовы</title> <desc>Великая книга</desc> <price>1000</price> </book> <book> <title>Страдания юного Вертера</title> <desc>Стоящая книга</desc> <price>100</price> </book> </catalog> <!-- Содержание php скрипта --> $dom = new DomDocument(); $dom->load("catalog.xml"); $root = $dom->documentElement; // foreach($root->childNodes as $book){ if($book->nodeType == 1){ echo ""; foreach($book->childNodes as $item){ if($item->nodeType == 1){ echo "{$item->textContent}"; } } echo ""; } }
Базовое использование DOM для создания/изменения документа
//=== //создаем объект, который будет экземпляром класса DomDocument //Параметры передадут значения в пролог документа //указав версию и кодировку $dom = new DOMDocument("1.0", "utf-8"); //=== //Создаем элементы book и title //НО данные методы не создают сразу элементы в файле, //а лишь в памяти $catalog = $dom->createElement("catalog"); $book = $dom->createElement("book"); $title = $dom->createElement("title"); //=== //По аналогичной схеме создаем в памяти //текстовый узел $bookName = $dom->createTextNode("php 7 в подлиннике"); //=== //теперь мы можем созданные узлы вложить друг в друга $title->appendChild($bookName); $book->appendChild($title); $catalog->appendChild($book); //=== /*PHP предоставляет дополнительный, упрощенный способ с созданием элементов*/ $author = $dom->createElement("author", "Игорь Симдянов и Дмитрий Котеров"); //=== //Также может возникнуть задача вставить узел не в конец, //а, например, перед каким-то конкретным узлом //вставим в узел book, //элемент author перед элементом title $book->insertBefore($author, $title); //=== //При создании текстового узла, //мы можем создавать такие узлы, которые //содержат запрещенные символы. //Используя для этого метод createCDATASection $description = $dom->createElement("description"); $cdata_desc = $dom->createCDATASection( "В книге раскрыта древняя тайна использования символов < & > "); $description->appendChild($cdata_desc); $book->appendChild($description); //=== //Далее элемент каталог мы вкладываем в тело документа //он и будет корневым элементом $dom->appendChild($catalog); //=== //После того, как логика будет составлена остается //только сохранить созданные узлы в документ $dom->save("book_catalog.xml");
В результате описанных выше манипуляций, мы получим следующий xml документ.
<?xml version="1.0" encoding="utf-8"?> <catalog> <book> <author>Игорь Симдянов и Дмитрий Котеров</author> <title>php 7 в подлиннике</title> <description> <![CDATA[В книге раскрыта древняя тайна использования символов < & > ]]> </description> </book> </catalog>
Simple XML
Этот инструмент предназначен для чтения xml документа. Хотя, есть возможность и изменить текстовое содержимое элемента. Инструмент является надстройкой над DOM. Представляет собой более простой способ чтения.
Базовое использование
<!-- файл xml --> <?xml version="1.0" encoding="UTF-8"?> <catalog> <book> <title>Братья Карамазовы</title> <desc>Великая книга</desc> <price>1000</price> </book> <book> <title lang="ru">Страдания юного Вертера</title> <desc>Стоящая книга</desc> <price>100</price> </book> </catalog>
<!-- файл php скрипта --> //Для загрузки документа и преобразования его в объект //используется метод simplexml_load_file; $sxml = simplexml_load_file("catalog.xml"); /*Для тех случаев, когда нужно работать не с файлом, а с xml в виде строки, используется метод simplexml_load_ $sxml = simplexml_load_string("XML строка"); */ //как результат, в переменной $sxml будет объект, //свойствами которого стали все элементы, входящие в состав корневого. //Следовательно, чтобы получить текст элемента //используется следующий подход. //Для примера получим название второй книги из каталога echo $sxml->book[1]->title; //Страдания юного Вертера //Если нужно получить значение атрибута, //используем аналогичную конструкцию echo $sxml->book[1]->title["lang"];//ru //По тому же принципу можно и заменить содержание элемента //Сначала меняем его в памяти $sxml->book[0]->title = "php 7 в подлиннике"; //Далее, мы берем все содержимое корневого элемента, //преобразованное к строке $xml = $sxml->asXML(); //и записываем все это в файл file_put_contents("catalog.xml", $xml);
Преобразование XML с XSL/T
Не смотря на то, что для стилизации xml документов можно применять даже обычный css, так практически никто не делает. Для преобразования xml документа используется технология XSL/T, что значит — Extensible Stylesheet Language/Transformations.
Описание работы с XSL/T выходит за рамки этого урока, так как инструмент сложный и в несколько абзацев его не вместить. Как впрочем и CSS. Поэтому, данную тему я попытаюсь раскрыть подробнее, когда возьмусь ее за изучение.
Подключается файл xsl/t в блоке декларации следующим образом
<?xml-stylesheet type="text/xsl" href="file_name.xsl"?>
Это стандартный метод подключения. Тут подразумевается, что вы открываете в браузере xml, а в нем есть ссылка на преобразователь. Браузер загружает файл по этой ссылке и на его основе отрисовывает преобразованный xml. Php предоставляет возможность подключить преобразователь к xml документу на сервере. В результате, вы сможете обращаться к php скрипту, а получить преобразованный xml.
Используется для этого штатное расширение php.
Пример
//Создаем объект для xml $xml = new DomDocument(); //Загружаем в этот объект xml документ $xml->load("catalog.xml"); //Создаем объект для xsl $xsl = new DomDocument(); //Загружаем в этот объект xsl документ $xml->load("catalog.xsl"); //Создаем экземпляр класса XSLTProcessor $processor = new XSLTProcessor(); //Загружаем xsl в процессор $processor->importStylesheet($xsl); //Преобразование переданного в процессор xml файла //на основе имеющегося xsl //И вывод на экран echo $processor->transformToXML($xml);
Автор Виталий Сухомлинов
практикующий веб разработчик
и seo-специалист