Опубликован: 01.03.2005 | Доступ: свободный | Студентов: 33897 / 4520 | Оценка: 4.31 / 4.06 | Длительность: 16:41:00
ISBN: 978-5-9556-0026-0
Лекция 14:

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

< Лекция 13 || Лекция 14: 12345 || Лекция 15 >

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

Для получения значения текущего узла (вне зависимости от его типа) используют метод 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. Добавление описания новой личности в каталог

Заключение

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

< Лекция 13 || Лекция 14: 12345 || Лекция 15 >
Дарья Федотова
Дарья Федотова
Сергей Березовский
Сергей Березовский

В рамках проф. переподготовки по программе "Программирование"

Есть курсы, которые я уже прошел. Но войдя в курс я вижу, что они не зачтены (Язык Ассемблера и архитектура ЭВМ, Программирование на С++ для профессионалов). Это как?

Алексей Лысенков
Алексей Лысенков
Россия
Артём Терентьев
Артём Терентьев
Россия, г. Орск