→ Пошук по сайту       Увійти / Зареєструватися
Знання Мова програмування PHP Взаимодействие PHP и XML

Взаимодействие PHP и XML посредством DOM XML

Компетенція Програмування на PHP

Взаимодействие PHP и XML посредством DOM XML

Что происходит, если взаимодействие PHP и XML осуществляется с помощью объектной модели стандарта DOM? Модуль DOM XML определяет в PHP несколько классов, таких как DomNode, DomDocument, DomElement, DomText и DomAttribute, большинство из которых идут из ядра стандарта DOM. Почти для всех классов (в частности, для перечисленных выше) класс DomNode является родительским, поэтому его свойства и методы наследуются всеми остальными классами.

Если рассмотреть произвольный XML-документ, то классу DomDocument будет соответствовать сам этот документ, классу DomElement – каждый XML-тег, классу DomAttribute – атрибуты тегов, а классу DomText – содержание XML-элементов. В то же время классу DomNode будет соответствовать каждый из перечисленных элементов XML-документа.

Рассмотрим коллекцию, содержащую описания персон. Если каждую из них мы описываем с помощью таких характеристик, как фамилия, имя, дата рождения и электронный адрес, то структура коллекции «Личности», где хранится информация обо всех известных нам персонах, может быть представлена следующим образом.

<?xml version="1.0"?>
<collection>
    <person id="10">
        <name>
            <first>Nick</first>
            <last>Petrov</last>
        </name>
        <birth>
            <day>23</day>
            <month>12</month>
            <year>89</year>
        </birth>
        <email> nick@ngs.ru 
        </email>
    </person>
    <person id="20">
        <name>
            <first>Bob</first>
            <last>Ivanov</last>
        </name>
        <birth>
            <day>03</day>
            <month>05</month>
            <year>90</year>
        </birth>
        <email> bob@ngs.ru 
        </email>
    </person>
</collection>
Пример 14.2. Коллекция «Личности» в виде XML-файла (persons.xml)

В дальнейшем, приводя примеры, мы будем использовать этот файл.

Нам необходимо научиться читать, добавлять, изменять и искать информацию, находящуюся в XML-файлах.

Перевод данных XML-файла в объекты и классы PHP

Первое, что нужно сделать, если мы хотим работать с XML-данными в PHP при помощи расширения DOM XML, это перевести имеющиеся данные в объекты и классы DOM. Это можно сделать несколькими способами.

  1. С помощью функции domxml_open_mem.

    Синтаксис:

    object domxml_open_mem (string str)
    
    В качестве параметра эта функция принимает строку str, содержащую XML-документ. Результатом ее работы является объект класса, называемого DOMDocument.
  2. С помощью функции domxml_open_file.

    Синтаксис:

    object domxml_open_file (string filename)
    Эта функция обрабатывает XML-файл, имя которого задается параметром filename, и переводит его в объект класса DOMDocument. Доступ к файлу производится только на чтение.

Такие функции, как domxml_open_mem() и domxml_open_file(), как правило, нужно вызывать перед вызовом любых других функций, связанных с расширением DOM.

Эти функции преобразуют XML-файл в дерево объектов. К таким объектам можно обращаться с помощью различных методов. В частности, для выделения корневого элемента используется метод DomDocument->document_element().

Еще существует функция domxml_new_doc(string version), которая создает новый пустой XML-документ. Ее параметром является номер версии создаваемого документа. Но ее мы касаться не будем, а будем считать, что XML-файл уже создан.

<?
//считываем файл "persons.xml" в строку
$xmlstr = join('',file('persons.xml'));
// переводим строку с xml-файлом
// в дерево объектов. Если операция
// прошла неудачно, то выводим
// ошибку и прекращаем работу.
if(!$dom = domxml_open_mem($xmlstr)) {
  echo "Ошибка при разборе документа\n";
  exit;
}
// можно посмотреть, как выглядит
// этот объект
print_r($dom);
echo "<hr>";
// выделяем корневой элемент
// дерева объектов.
// В нашем случае это будет
// элемент <collection>
$root = $dom->document_element();
print_r($root);
echo "<hr>";
?>
Пример 14.3. Перевод XML-файла в дерево объектов PHP и выделение корневого элемента

Итак, каждому элементу XML-файла мы поставили в соответствие какой-то объект. Теперь нужно научиться перемещаться по дереву объектов и обращаться с этими объектами: получать и изменять их значения, находить их потомков и предков, удалять объекты.

Обход дерева объектов

Для получения значения текущего узла (вне зависимости от его типа) используют метод DomNode->node_value() или DomNode->get_content() для получения содержимого узла.

Для получения значения атрибута используется метод DomElement->get_attribute (attr_name). А метод DomNode->child_nodes() возвращает массив потомков данного узла.

Для того чтобы сделать обход дерева объектов, полезно еще уметь различать объекты по типам, т.е. определять, является ли узел элементом (тегом), текстом, атрибутом и т.п. Для этого используются специальные константы. XML_ELEMENT_NODE определяет, является ли узел элементом, XML_ATTRIBUTE_NODE определяет, является ли узел атрибутом, и XML_TEXT_NODE определяет, является ли узел куском текста. Эти константы имеют целочисленные значения 1, 2 и 3 соответственно. Использование этих констант полезно, поскольку переводы строки, применяемые для удобочитаемости XML-файлов, тоже становятся узлами.

<?
// сначала делаем то же,
// что и в предыдущем примере
$xmlstr = join('',file('persons.xml'));
if(!$dom = domxml_open_mem($xmlstr)) {
  echo "Ошибка при разборе документа\n";
  exit;
}
$root = $dom->document_element();
// Получаем массив потомков
// родительского узла
// (в нашем случае это массив <person>)
$nodes = $root->child_nodes();
print_r($nodes);
echo "<hr>";
// Начинаем обработку каждого
// узла в массиве
foreach($nodes as $node){
    // Если текущий узел – один
    // из узлов <person>, то
    // продолжаем ее обработку,
    // чтобы получить информацию
    // об этой личности
    if ($node->tagname=='person'){
    // Создаем массив, куда
    // будем собирать информацию
    // о рассматриваемой личности
    $currentPers = array();
    // Получаем id личности,
    // который хранится в атрибуте 'id'
    $currentPers['id'] = 
          $node->get_attribute('id');
    // Получаем массив потомков
    // <person>. Это вся
    // информация о личности
    // (<name>,<birth> и т.д.)
    $persons_info = 
                $node->child_nodes();
    // Перебираем все дочерние
    // узлы $node
    foreach ($persons_info as $info){
    // проверяем, является ли узел
    // элементом (xml-тегом)
    if ($info->type==
                  XML_ELEMENT_NODE) {
        // тогда метод tagname
        // возвратит имя этого  
        // элемента (тега), а метод
        // get_content() –
        // его содержимое
        $currentPers[$info->tagname] =
                 $info->get_content();
        }
    }
    // выводим на экран полученные
    // массивы
    print_r ($currentPers);
                                        
    echo "<br>";
    }
}
?>
Пример 14.4. Обход дерева XML

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

...
<person id="20">
  <name>
    <first>Иван</first>
    <last>Иванов</last>
  </name>
...

Тогда в наш предыдущий пример вставим (после вывода на экран полученных массивов) строчку для поиска электронного адреса Ивана Иванова.

...
    $str = $currentPers["email"];
    if ($currentPers["name"] ==
                    "Иван Иванов" )
        echo "Здравствуйте Иван! " .
        "Ваш e-mail $str";
...

Добавление новых элементов в XML-документ

Далее разберем задачу, как можно добавить в нашу базу данных новую личность средствами php.

Сначала нужно скопировать описание личности (считаем, что все личности описываются с помощью стандартного набора характеристик, как в файле persons.xml ). Это делается с помощью метода DomNode->clone_node(). Таким образом, мы клонируем элемент <person> и все его внутренние элементы (содержание тегов не копируется).

Потом можно установить какие-нибудь значения для элементов описания личности. Например, задать имя человека, дату его рождения и т.п. В конце нужно записать полученное описание личности в качестве потомка корневого элемента в дерево DOM с помощью метода DomNode->append_child(new_node), где в качестве параметра передается созданный объект (новый узел).

В PHP до версии 4.3 перед добавлением потомка к узлу с помощью данной функции этот потомок сначала копировался. Таким образом, новый узел являлся новой копией, которая могла изменяться без изменения узла, переданного как параметр в эту функцию. В более поздних версиях PHP новый узел удаляется из существующего контекста, если он уже есть в дереве. Такое поведение соответствует спецификациям W3C.

Для удаления узла можно воспользоваться методом, применив его к узлу, который требуется удалить, т.е. DomNode->unlink_node().

// Для того чтобы добавить описание
// новой личности, нужно знать,
// как описывается каждая личность.
// Выбираем элемент person,
// который содержит описание личности
$elements =
$dom->get_elements_by_tagname("person");
$element = $elements[0];
//вычисляем родителя и потомков
$parent = $element->parent_node();
$children = $element->child_nodes();
// клонируем элемент person
$person = $element->clone_node();
// устанавливаем новой
// личности идентификатор
$attr = $person->set_attribute("id", "30");
// если у личности были потомки,
// то их тоже надо клонировать
foreach ($children as $child){
  //клонируем ребенка
  $node = $child->clone_node();
  //получаем массив внуков
  $grand_children = $child->child_nodes();
  // если ребенок имеет потомков,
  //т.е. массив внуков не пуст, то
  if (count($grand_children)<>1){
       //клонируем каждого внука
       //и присоединяем к уже
       //клонированному ребенку
    foreach($grand_children as $grand_child){
     $lastnode = $grand_child->clone_node();
       //записываем в нужные теги
       //подходящие значения
      if ($grand_child->tagname=="first")
       $cont = $lastnode->set_content("Nina");
      if ($grand_child->tagname=="last")
       $cont = $lastnode->set_content("Saveljeva");
      if ($grand_child->tagname=="day")
       $cont = $lastnode->set_content("7");
      if ($grand_child->tagname=="month")
       $cont = $lastnode->set_content("06");
      if ($grand_child->tagname=="year")
       $cont = $lastnode->set_content("1981");
      $newlastnode = $node->append_child($lastnode);
        }
    }
    if ($child->tagname=="email") {
        $cont = $node->set_content("help@intuit.ru");
    }
    $newnode2 = $person->append_child($node);
}
$newnode = $parent->append_child($person);
//dump_mem создает XML-документ из dom
//представления
echo "<PRE>";
$xmlfile = $dom->dump_mem(true);
// посмотрим в браузере,
// что получилось
echo htmlentities($xmlfile);
echo "</PRE>";
// запишем полученный XML-файл
// в файл "test.xml"
$h = fopen("test.xml","a");
if (!fwrite($h, $xmlfile)) {
        print "Cannot write " . "to file ($filename)";
        exit;
    }
}
Пример 14.5. Добавление описания новой личности в каталог
    © INTUIT.ru. Автор: Н.В. Савельева. Курс размещен по договоренности с администрацией INTUIT.ru
загрузка...
Теми розділу
Сторінки, близькі за змістом