Работа с XML

08.09.2013

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

Исходный XML файл:


<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2013-10-05 01:43">
  <shop>
    <company>ООО "Рога и копыта"</company>
    <offers>
      <offer id="1" available="true">
        <price>16</price>
        <name>Товар 1</name>
      </offer>
      <offer id="2" available="false">
        <price>25</price>
        <name>Товар 2</name>
      </offer>
      <offer id="3" available="true">
        <price>22</price>
        <name>Товар 3</name>
      </offer>
    </offers>
  </shop>
</yml_catalog>

Нам нужно получить из файла название компании (ООО "Рога и копыта"), дату файла (2013-10-05 01:43), и список доступных предложений (у которых available="true"). Для начала загружаем XML-файл:


if (!$xml = simplexml_load_file($path)){
    //$path может быть локальный или удаленный (с html://)
    die('Ошибка!!! Не удалось получить XML файл');
}

Получим объект класса SimpleXMLElement, содержащий всю структуру XML-файла, узлы которого также хранятся в виде объектов класса SimpleXMLElement. Для справки, скажу, что загружать XML можно не только из файла, но и из строки, с помощью функции simplexml_load_string. Чтобы дальнейшее было понятней, приведу, дамп переменной $xml:


SimpleXMLElement Object
(
    [@attributes] => Array
        (
            [date] => 2013-10-05 01:43
        )

    [shop] => SimpleXMLElement Object
        (
            [company] => ООО "Рога и копыта"
            [offers] => SimpleXMLElement Object
                (
                    [offer] => Array
                        (
                            [0] => SimpleXMLElement Object
                                (
                                    [@attributes] => Array
                                        (
                                            [id] => 1
                                            [available] => true
                                        )

                                    [price] => 16
                                    [name] => Товар 1
                                )

                            [1] => SimpleXMLElement Object
                                (
                                    [@attributes] => Array
                                        (
                                            [id] => 2
                                            [available] => false
                                        )

                                    [price] => 25
                                    [name] => Товар 2
                                )

                            [2] => SimpleXMLElement Object
                                (
                                    [@attributes] => Array
                                        (
                                            [id] => 3
                                            [available] => true
                                        )

                                    [price] => 22
                                    [name] => Товар 3
                                )

                        )

                )

        )

)

Ниже приведу код, как из переменной $xml достать необходимые нам данные:


$attributes = $xml->attributes();//получаем массив атрибутов корневого узла
$res = array(
    'date' => (string)$attributes['date'],//все узлы и данные
          // хранятся как объекты класса SimpleXMLElement,
          //принудительно преобразуем в строку (string)
    'name' => (string)$xml->shop->company,
    'offers' => array(),
);
foreach ($xml->shop->offers->offer as $xmlOffer){
    $attributes = $xmlOffer->attributes();//аналогично получаем
                                // массив атрибутов предложений
    if ((string)$attributes['available']=='true'){
        $res['offers'][] = array(
            'id' => (string)$attributes['id'],
            'price' => (string)$xmlOffer->price,
            'name' => (string)$xmlOffer->name,
        );
    }
}
unset($xml);//Переменная $xml больше не нужна, освободим память

Вот и все! Все необходимые данные хранятся в удобном виде в массиве $res:


Array
(
    [date] => 2013-10-05 01:43
    [name] => ООО "Рога и копыта"
    [offers] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [price] => 16
                    [name] => Товар 1
                )

            [1] => Array
                (
                    [id] => 3
                    [price] => 22
                    [name] => Товар 3
                )

        )

)

Комментарии:

Dimmik

04.05.2015 23:19:16

Спасибо! Очень помогло. В начале как то не думал здесь оставлять свой комментарий, но потом почитал о проекте так сказать :). И решил написать, что очень помог данный готовый метод парсинга. Я до этого нашел решение своей задачи распарсить xml методами SAX парсинга, но для решения моего вопроса нужно было бы сохранять промежуточные результаты скорее всего в таблицу базы mysql. Но освоив так сказать что описал, не воплотив в жизнь, но заимев опыт, решил найти другое более подходящее и современное решение, тогда я уже понял, что мой файл XML для DOM не является большим(раньше думал иначе). И вот набрел на это дело :). Огромное спасибо, очень помогло!

Евгений

25.09.2015 13:47:14

Подскажите пожалуйста если я загружаю файл, а мне указывает много ошибок например такая.

Warning: simplexml_load_file() [function.simplexml-load-file]: 2.xml:62876: parser error : CData section not finished 8шт 1/4" Головки торцевые: 613 in G:\OpenServer\domains\Test\xml.php on line 17


Это почти везде где у товаров в описании прописанно 1/4" можно как то обойти эту ошибку, что бы преобразовывал в другую кодировку или пропускал такие записи ?

Евгений

25.09.2015 15:40:49

Сам спросил, сам ответил

libxml_use_internal_errors(true);
$xml = simplexml_load_file('$path');
if (!$xml) {
echo "Ошибка загрузки XML\n";
foreach(libxml_get_errors() as $error) {
echo "\t", $error->message;
}
}

Олег

15.03.2016 22:15:30

Спасибо,добрый человек.
Наконец-то нормальное решение среди горы интернетовского мусора .

Валерий

30.01.2017 12:59:43

Спасибо тебе мил человел, облазил много форумов, ничего не помогло, но твой пост все решил за секунды, спасибо!

Сергей

06.03.2019 22:37:57

Код выше рабочий. Но в yml каталоге практически всегда есть еще значение param

<param name="Вес">18.8</param>
<param name="Акция Цена">9900</param>
<param name="Объем">0.112</param>

а как получить значение по например name="Акция Цена" проигнорировав другие используя за основу Ваш код?

Оставить комментарий:

Представьтесь пожалуйста:
Электронная почта:
Электронный адрес не публикуются
Текст сообщения:
Для подсветки кода, оборачивайте ваш код в теги <code></code>
Введите 5 цифр с картинки:

Рекомендую:

Поделюсь промокодами для хостинга TimeWeb!

Поддержать проект: