PHP и XML

5
(4)

Введение в 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

Рисунок №1 — пример тега xml

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

<employee>
   <name>Ivan</name>
   <salary>100000</salary>
</employee>

Синтаксис, грамматика и семантика элементов

  • Синтаксис — правила записи элементов разметки.
  • Грамматика — отношения элементов разметки друг к другу.
  • Семантика — смысловые значения элементов разметки.

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

Более подробно о синтаксисе

Рассмотрим, из чего состоит xml документ и его структуру (рис. 2)

Пример xml документа

Рисунок №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)

Пример построенного DOM дерева xml документа

Рисунок №3 — Пример построенного DOM дерева xml документа

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

типы узлов xml документа

Рисунок №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-специалист

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 5 / 5. Количество оценок: 4

Оценок пока нет. Поставьте оценку первым.