Веб-программирование

Парсим XML при помощи SimpleXML

Парсинг XML по сути означает проход по XML-документу и возвращение соответствующих данных

Парсим XML при помощи SimpleXML
Поделиться в соцсетях:

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

Используя расширение SimpleXML в PHP, которое было добавлено еще в PHP 5.0, работать с XML очень легко и просто. В этой статье я покажу вам, как это делать.

Основы использования

Давайте начнем со следующего примера languages.xml:

<?xml version="1.0" encoding="utf-8"?>
<languages>
    <lang name="C">
        <appeared>1972</appeared>
        <creator>Dennis Ritchie</creator>
    </lang>
    <lang name="PHP">
        <appeared>1995</appeared>
        <creator>Rasmus Lerdorf</creator>
    </lang>
    <lang name="Java">
        <appeared>1995</appeared>
        <creator>James Gosling</creator>
    </lang>
</languages>

Данный XML-документ содержит список языков программирования с некоторой информацией о каждом языке: год его реализации и имя его создателя.

Первый шаг заключается в загрузке XML с использованием функций либо simplexml_load_file(), либо simplexml_load_string(). Как понятно из названия функций, первая загружает XML из файла, а вторая будет загружать XML из строки.

<?php
$languages = simplexml_load_file("languages.xml");

Обе функции считывают все дерево DOM в память и возвращают объект SimpleXMLElement. В приведенном выше примере, объект сохраняется в переменной $languages. Вы можете использовать функции var_dump() или print_r(), чтобы получить подробную информацию о возвращенном объект, если хотите.

SimpleXMLElement Object
(
  [lang] => Array
  (
    [0] => SimpleXMLElement Object
    (
      [@attributes] => Array
      (
          [name] => C
      )
      [appeared] => 1972
      [creator] => Dennis Ritchie
    )
    [1] => SimpleXMLElement Object
    (
      [@attributes] => Array
      (
          [name] => PHP
      )
      [appeared] => 1995
      [creator] => Rasmus Lerdorf
    )
    [2] => SimpleXMLElement Object
    (
      [@attributes] => Array
      (
          [name] => Java
      )
      [appeared] => 1995
      [creator] => James Gosling
    )
  )
)

Данный XML содержит корневой элемент languages, внутри которого находятся три элемента lang. Каждый элемент массива соответствует элементу lang в XML-документе.

Вы можете получить доступ к свойствам объекта при помощи оператора ->. Например, $languages->lang[0] вернет вам объект SimpleXMLElement, который соответствует первому элементу lang. Этот объект содержит два свойства: appeared и creator.

$languages->lang[0]->appeared;
$languages->lang[0]->creator;

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

foreach ($languages->lang as $lang) {
    printf (
        "<p>%s появился в %d и был создан %s.</p>",
        $lang["name"],
        $lang->appeared,
        $lang->creator
    );
}

Обратите внимание, как я получил доступ к имени атрибута элемента lang, чтобы получить название языка. Таким образом Вы можете получить доступ к любому атрибуту элемента представленого в виде объекта SimpleXMLElement.

Работа с пространствами имен

Во время работы с XML различных веб-сервисов вы не раз столкнетесь с пространствами имен элементов. Давайте изменим наш languages.xml, чтобы показать пример использования пространства имен:

<?xml version="1.0" encoding="utf-8"?>
<languages
xmlns:dc="http://purl.org/dc/elements/1.1/">
<lang name="C">
    <appeared>1972</appeared>
    <dc:creator>Dennis Ritchie</dc:creator>
</lang>
<lang name="PHP">
    <appeared>1995</appeared>
    <dc:creator>Rasmus Lerdorf</dc:creator>
</lang>
<lang name="Java">
    <appeared>1995</appeared>
    <dc:creator>James Gosling</dc:creator>
</lang>
</languages>

Теперь элемент creator помещается в пространстве имен dc, который указывает на http://purl.org/dc/elements/1.1/. Если вы попытаетесь распечатать создателей языка, используя наш предыдущий код, то он не будет работать. Для того, чтобы читать пространства имен элементов вам необходимо использовать один из следующих подходов.

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

$dc = $languages->lang[1]- >children("http://purl.org/dc/elements/1.1/");
echo $dc->creator;

Метод children() принимает пространство имен и возвращает дочерние элементы, которые начинаются с префикса. Он принимает два аргумента, первый из которых является пространством имен XML, и второй необязательный аргумент, который по умолчанию равен false. Если второй аргумент установлен как TRUE, пространство имен будет рассмотрено как префикс. Если FALSE, то пространство имен будет рассмотрено как пространство имен URL.

Второй подход состоит в чтении имен URI из документа и использование их при обращении к пространству имен элементов. На самом деле это лучший способ доступа к элементам, потому что вы не должны быть жестко привязаны к URI.

$namespaces = $languages->getNamespaces(true);
$dc = $languages->lang[1]->children($namespaces["dc"]);

echo $dc->creator;

Метод GetNamespaces() возвращает массив имен префиксов и связанные с ними URI. Он принимает дополнительный параметр, который по умолчанию равен false. Если вы установите его как true, то этот метод будет возвращать имена, используемые в родительских и дочерних узлах. В противном случае, он находит пространства имен, используемые только в родительском узле.

Теперь вы можете пройтись по списку языков следующим образом:

$languages = simplexml_load_file("languages.xml");
$ns = $languages->getNamespaces(true);

foreach($languages->lang as $lang) {
    $dc = $lang->children($ns["dc"]);
    printf (
        "<p>%s появился в %d и был создан %s.</p>",
        $lang["name"],
        $lang->appeared,
        $dc->creator
    );
}

Практический пример: парсинг видео-канала с YouTube

Давайте рассмотрим пример, который получает RSS-feed с канала YouTube и отображает ссылки на все видео из него. Для этого нужно обратится по следующему адресу:

http://gdata.youtube.com/feeds/api/users/xxx/uploads

URL возвращает список последних видео с данного канала в формате XML. Мы распарсим XML и получим следующую информацию для каждого видео:

  • Ссылка на видео
  • Миниатюра
  • Название

Мы начнем с поиска и загрузки XML:

$channel = "Имя_канала";
$url = "http://gdata.youtube.com/feeds/api/users/".$channel."/uploads";
$xml = file_get_contents($url);

$feed = simplexml_load_string($xml);
$ns=$feed->getNameSpaces(true);

Если вы посмотрите на XML-feed, то вы можете увидеть, что там есть несколько элементов entity, каждый из которых хранит подробную информацию о конкретном видео с канала. Но мы используем только миниатюры изображений, адрес видео и название. Эти три элемента являются потомками элемента group, который, в свою очередь, является дочерним для entry:

<entry>
    …
    <media:group>
        …
        <media:player url="video url"/>
        <media:thumbnail url="video url" height="height" width="width"/>
        <media:title type="plain">Title…</media:title>
        …
    </media:group>
    …
</entry>

Мы просто пройдемся по всем элементам entry, и для каждого из них извлечем необходимую информацию. Обратите внимание, что player, thumbnail и title находятся в пространстве имен media. Таким образом, мы должны действовать, как в предыдущем примере. Мы получаем имена из документа и используем пространство имен при обращении к элементам.

foreach ($feed->entry as $entry) {
    $group=$entry->children($ns["media"]);
    $group=$group->group;
    $thumbnail_attrs=$group->thumbnail[1]->attributes();
    $image=$thumbnail_attrs["url"];
    $player=$group->player->attributes();
    $link=$player["url"];
    $title=$group->title;
    printf('<p><a href="%s"><img src="%s" alt="%s"></a></p>',
    $player, $image, $title);
}

Заключение

Теперь, когда вы знаете, как использовать SimpleXML для разбора XML-данных, вы можете улучшить свои навыки путем анализа различных XML-каналов с различными API. Но важно учитывать, что SimpleXML считывает весь DOM в память, так что если вы парсите большой набор данных, то вы можете столкнуться с нехваткой памяти. Чтобы узнать больше о SimpleXML прочтите документацию.

Новый комментарий

Имя:
Для редактирования комментария осталось 10 минут
Комментарии отсутствуют