Только для читателей Lifeexample возможно открыть интернет-магазин на Moguta.CMS со скидкой в 15%

<<< SQL Работа с датами || Награждение победителей конкурса на 5000 рублей >>>

Работа с XML в PHP

03.07.2013
Работа с XML в PHP

Здравствуйте, уважаемые читатели блога LifeExample, в этой статье "Работа с XML в PHP" я расскажу о том, как считывать, перезаписывать, удалять и производить php запись в xml файл. А так же о том, как в принципе быстро и удобно создать и поместить данные в xml разметку. Будучи студентом работая над своими проектами, я самостоятельно писал библиотеки для обработки XML документов. Я очень рад, что теперь мне не приходится пользоваться своими велосипедами т.к. есть готовые решения присутствующие в PHP по умолчанию.

Работа с XML в PHP — PHP запись в XML

Инструмент XMLWriter был создан специально для записи в XML формате. Один из важных его методов это startDocument(), который позволяет задать кодировку версии XML.

Попробуем создать простенький XML следующего вида:

1
2
3
4
5
6
<?xml version="1.0"?>
<Customer>
<id>1</id>
<name>Марк</name>
<address>Санкт-Петербург</address>
</Customer>

Получить такой формат можно с помощью XMLWriter таки вот образом:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
//Простой пример
$xml = new XMLWriter(); //создаем новый экземпляр класса XMLWriter
$xml->openMemory(); //использование памяти для вывода строки
$xml->startDocument(); //установка версии XML в первом теге документа
$xml->startElement("Customer"); //создание корневого узла
$xml->writeElement("id", "1");
$xml->writeElement("name", "Марк"); //запись элемента
$xml->writeElement("address", "Санкт-Петербург");
$xml->endElement(); //закрытие корневого элемента
echo $xml->outputMemory(); //завершение записи в XML
?>

Как видите, Работа с XML в PHP, благодаря XMLWriter становится невероятно простой, и сильно облегчает задачи записи XML формата. Далее приведу маленький комплекс примеров о том, как осуществить, на php запись в xml. Например, задача поставлена — получить файл XML в следующем формате:

1
2
3
4
5
6
7
8
9
10
11
12
13
<xml version="1.0"?>
<purchase>
<customer>
<id>1</id>
<time>2013-04-19 10:56:03</time>
<total>$350</total>
</customer>
<customer>
<id>2</id>
<time>2013-04-23 13:43:41</time>
<total>$1456</total>
</customer>
</purchase>

Чтобы получить такую структуру нужно выполнить ряд не хитрых методов класса XMLWriter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$xml = new XMLWriter();
$xml->openMemory();
$xml->startDocument();
$xml->startElement("purchase");
$xml->startElement("customer");  //открытие элемента первого покупателя с ID =  1
$xml->writeElement("id", 1);
$xml->writeElement("time", "2013-04-19 10:56:03");
$xml->writeElement("total", "$350");
$xml->endElement();  //закрытие элемента первого покупателя с ID =  1
$xml->startElement("customer");  //Открытие элемента второго покупателя с ID = 2
$xml->writeElement("id", 2);
$xml->writeElement("time", "2013-04-23 13:43:41");
$xml->writeElement("total", "$1456");
$xml->endElement();  //закрытие элемента первого покупателя с ID =  2
$xml->endElement();
echo $xml->outputMemory();
?>

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

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0"?>
<products>
<product pid="314">
<name>Яблоко</name>
<price>$1.00</price>
<discount>3%</discount>
</product>
<product pid="315">
<name>Манго</name>
<price>$0.90</price>
<discount>3%</discount>
</product>
</products>

С помощью XMLWriter, делается это так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
    $xml = new XMLWriter();
    $xml->openMemory();
    $xml->startDocument();
        $xml->startElement("products");
            $xml->startElement("product");      
            $xml->writeAttribute("pid", 314);
                $xml->writeElement("name", "Яблоко");
                $xml->writeElement("price", "$1.00");
                $xml->writeElement("discount", "3%");
            $xml->endElement();                          
            $xml->startElement("product");      
            $xml->writeAttribute("pid", 315);
                $xml->writeElement("name", "Манго");
                $xml->writeElement("price", "$0.90");
                $xml->writeElement("discount", "3%");
            $xml->endElement();                          
        $xml->endElement();
    echo $xml->outputMemory();                          
?>

Работа с XML в PHP — Чтение и получение данных из XML

Ниже будет приведен пример чтения и получения данных из XML с использованием классов XMLReader и SimpleXMLElement. Читать будем уже имеющийся XML объект, который мы создали в примере №1 при PHP записи в XML.

XMLReader используется для получения заданного узла из XML.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Чтение XML формата
$rxml = new XMLReader();    //Создание элемента для чтения
$rxml->xml($nXML);        //Загрузка  XML, $nXML - строка в формате XML

//Переместиться к первому элементу customer    
while($rxml->read() && $rxml->name !== 'customer');

$amountSpent = 0;

//Получим значение поля total у второго узла дерева
while($rxml->name === 'customer'){      
    //Чтение текущего дочернего через SimpleXMLElement
    $node = new SimpleXMLElement($rxml->readOuterXML());
    //Проверяем, номер элемента, если он равен 2 то это искомый элемент
    if($node->id == 2){
        $amountSpent = $node->total;
        break;
    }
    //Переместиться к следующему элементу customer
    $rxml->next('customer');
}

echo $amountSpent;

Часто задача возникает в получении данных из XML по значению, какого либо атрибута. Давайте по примеру №2 из раздела PHP запись в XML, получим название, цену и скидку продукта по его атрибуту pid = 315.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$rxml = new XMLReader();                               
    $rxml->xml($nXML2);                                    
    while($rxml->read() && $rxml->name !== 'product');//Перемещаемся к первому продукту
   
    $name = "";
    $price = "";
    $discount = "";
    while($rxml->name === 'product'){              
        if($rxml->getAttribute("pid") == "315") //если  pid = 315 то это искомый элемент
        {
            $node = new SimpleXMLElement($rxml->readOuterXML());//читаем значение элементов
            $name = $node->name;
            $price = $node->price;
            $discount = $node->discount;
            break;
        }
        $rxml->next('product');     //перемещаемся к следующему
    }  
    echo "Продукт №315. Наименование: {$name}, цена: {$price} скидка: {$discount}";

Работа с XML в PHP — Добавление узлов дерева в существующий XML

Работая с XML в PHP, не редко приходится ломать голову над тем как добавить новый элемент в имеющуюся XML структуру. Используя XMLWriter и SimpleXMLElement сделать это очень легко:

1
2
3
4
5
6
7
8
9
//Добавим новый узел в имеющийся XML
$sXML = new SimpleXMLElement($nXML2); // загрузка в XML
$newchild = $sXML->addChild("product");
//Добавление параметров записи
$newchild->addAttribute("pid", 328);
$newchild->addChild("name", "Банан");
$newchild->addChild("price", "$3.00");
$newchild->addChild("discount", "0.3%");
echo $sXML->asXML();

Работа с XML в PHP — Перезапись элементов существующего XML

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
 *  Перезапись узлов дерева XML формата.
 */

   
    $productId = 314;
    $parent = new DomDocument;
    // создаем новый  элемент дома product
    $parent_node = $parent->createElement('product');
   
    //Добавляем атрибут
    $attribute = $parent->createAttribute("pid");
    //устанавливаем значение
    $attribute->value = $productId;
    $parent_node->appendChild($attribute);
   
    // Добавляем дочерний элементы
    $parent_node->appendChild($parent->createElement('name', "Яблоко"));
    $parent_node->appendChild($parent->createElement('price', "$2.00"));
    $parent_node->appendChild($parent->createElement('discount', "1%"));

    //Вставляем созданные элементы в создаваемый 'product'
    $parent->appendChild($parent_node);

    // Загружаем оригинальный XML формат
    $dom = new DomDocument;
    $dom->loadXML($nXML);

    // Находим имеющийся элемент с pid = 314
    $xpath = new DOMXpath($dom);
    $nodelist = $xpath->query("/products/product[@pid={$productId}]");
   
    $oldnode = $nodelist->item(0);
               
    // Импортируем созданый ранее элемент в текущее дерево
    $newnode = $dom->importNode($parent->documentElement, true);

    // заменяем  страрый элемент на новый
    $oldnode->parentNode->replaceChild($newnode, $oldnode);
    // сохраняем  XML        
    echo $dom->saveXML();

Работа с XML в PHP — Удаление элементов XML

Из всего выше рассмотренного, осталась только одна операция, без которой данную статью о работе с XML в PHP , нельзя считать завершенной – это удаление элементов. Удаление элементов самое легкое из всей связки операций. Ну что же, ломать – не стоить, давайте удалим один из продуктов.

1
2
3
4
5
6
7
8
9
10
11
12
13
 //Удаление продукта Манго
//загрузим оригинальный формат XML
$productId = 315;
$dom = new DomDocument;
$dom->loadXML($nXML2);

// Найдем элемент который необходимо удалить
$xpath = new DOMXpath($dom);
$nodelist = $xpath->query("/products/product[@pid={$productId}]");
$oldnode = $nodelist->item(0);
// Удаляем элемент
$oldnode->parentNode->removeChild($oldnode);  
echo $dom->saveXML();

Закрыть текущий элемент (тэг) в xmlwriter

1
$xml->endDTDElement(); // закрыть текущий <tag attr='1' />

Скачать исходный код примеров ( Скачали: 702 чел. ) 

Найдя время и отвлекшись от основного своего проекта, я всё-таки опубликовал действительно полезную статью "Работа с XML в PHP", и надеюсь она пригодится в своих разработках. Пишите мне на e-mail, с какими задачами вы сталкиваетесь, и я попробую сформировать материал по их решению в следующих статьях

Чтобы не пропустить публикацию следующей статьи подписывайтесь на рассылку по E-mail или RSS ленту блога.

Нравится

Комментарии

  • Дмитрий

    К сожалению в моем рнр у провайдера nic.ru по умолчанию классы из вашей строки не существуют

    Fatal error: Class ‘XMLReader’ not found in /home/smelloftea/smelloftea.ru/docs/subdmn/billing/ajax1.php on line 16

    Где мне взять эти классы для помещения на свой сайт?

    • Задайте, данный вопрос своем хостинг-провайдеру. Насколько я знаю у nic.ru можно самостоятельно подключать необходимые библиотеки прямо из панели управления.

  • Дмитрий

    Такое впечатление, что у вас где-то опечатка.
    Я сделал все по вашем рекомендациям, но выходит ошибка
    мой XML файл

    18533883886651968791782864205137
    1019

    №1-836
    275123457
    ошибка в этой строке (#19):
    while($rxml->read() && $rxml->name !== ‘stb_item’);
    сообщения:
    Warning: XMLReader::read() [xmlreader.read]: /home/smelloftea/smelloftea.ru/docs/subdmn/billing/:1: parser error : Document is empty in /home/smelloftea/smelloftea.ru/docs/subdmn/billing/ajax1.php on line 19

    Warning: XMLReader::read() [xmlreader.read]: &lt;?xml version="1.0" encoding="utf-8"?&gt; in /home/smelloftea/smelloftea.ru/docs/subdmn/billing/ajax1.php on line 19

    Warning: XMLReader::read() [xmlreader.read]: ^ in /home/smelloftea/smelloftea.ru/docs/subdmn/billing/ajax1.php on line 19

    Warning: XMLReader::read() [xmlreader.read]: An Error Occured while reading in /home/smelloftea/smelloftea.ru/docs/subdmn/billing/ajax1.php on line 19

    • Попробуйте пример из архива с исходным кодом в конце статьи.

  • fatograf

    Не сомневаюсь, что с примером в конце статьи все хорошо, но я не могу решить свою проблему. Я должен обработать XML сообщение. При помощи Javascript я сообщение с экрана поместил в переменную и передал PHP скрипту для получения информации с помощью XMLReader. Я понял, что во время передачи метом POST символы » поменялись на ‘<‘ и ‘&gt’, что и вызывает сообщение об ошибки у XMLReader::get(). Как мне вернуть прежние » ?
    PHP функция str_replace не помогает.
    Или есть другой способ получения XML-строки?

    • Попробуйте полученную переменную прогнать через htmlspecialchars_decode.

  • Дмитрий

    Как можно получить XML строку для работы с ней в PHP из выведенного на экран сообщения в виде XML не используя Javascript?

  • Евгений

    Честно говоря немного не понятно про чтение XML.
    Если я пытаюсь прочитать к примеру какой то уже готовый XML файл …
    Я должен указать
    $rxml->open(‘test.xml’))

    так ?

    • нет, нужно передать в метод ниже строку в формате XML

      1
      $rxml->xml($nXML);  //Загрузка  XML, $nXML - строка в формате XML

      получить строку из XML файла можно так:

      1
      $nXML= file_get_contents('myfile.xml');
  • Евгений

    Здравствуйте! Может Вы подскажите. Работал с кодировкой cp1251. Начинал делать сайт в этой кодировке. Имеются скрипты Ajax с передачей данных на сервер и, соответственно, чтением результатов обработки сервера на стороне клиента через XML. Все прекрасно работало. Но потом решил перевести сайт в кодировку UTF-8. Перезаписал скрипты и базу данных в эту кодировку. Но столкнулся с проблемой. Клиент передает с помощью Ajax данные PHP-скрипту на сервер. Тот их обрабатывает, делает перезапись в БД, но не формирует XML файл для получения ответа клиенту. На выходе получается обычный HTML документ. Хотя при cp1251 прекрасно формировался XML.

    Формирую так:

    1
    2
    3
    4
    5
    6
    7
          header("Content-Type: text/xml");
          $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
                    <response>
                      <res_pas id_uz='$id_uzer'>$res</res_pas>
                    </response>";
                   
          echo $xml;

    В чем может быть проблема?
    На выходе получаю такое:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!--?xml version="1.0" encoding="UTF-8"?-->
      <html>
        <head></head>
        <body>
            <response>
                <res_pas id_uz="6">4</res_pas>
            </response>
        </body>
    </html>

    Т.е. заголовок стоит вроде XML, а в реалии обычный HTML-документ.
    Хотя, когда работал с cp1251, этот код выводил именно XML-документ. Естественно при той кодировке файл и запись encoding была cp1251.
    Да, пробовал и Вашим способом создавать XML. Результат тот же.

    • А как вы принимаете этот XML в клиенте, может там нужно явно тип указать?

  • nikonor

    Имеем выгрузку из 1с в формате commerceml (xml). По факту характеристики у товаров заполнялись «абы как» и пробил час, когда они стали необходимы, но возможности как следует их записать уже нет.
    Есть только вариант прописать их построчно в элемент .
    например
    Диаметр=100мм
    Длина=120мм

    Таким образом получаем в выгрузке

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <Товар>
        <Ид>001bfc8d17d7</Ид>
        <Наименование>Название товара</Наименование>
        <БазоваяЕдиница Код="796" НаименованиеПолное="Штука" МеждународноеСокращение="">шт</БазоваяЕдиница>
        <ЗначенияРеквизитов>
            <ЗначениеРеквизита>
                <Наименование>ВидНоменклатуры</Наименование>
                <Значение>Товар</Значение>
            </ЗначениеРеквизита>
            <ЗначениеРеквизита>
                <Наименование>ТипНоменклатуры</Наименование>
                <Значение>Товар</Значение>
            </ЗначениеРеквизита>
            <ЗначениеРеквизита>
                <Наименование>Полное наименование</Наименование>
                <Значение>Здесь полное название товара</Значение>
            </ЗначениеРеквизита>
        </ЗначенияРеквизитов>
        <СтавкиНалогов>
            <СтавкаНалога>
                <Наименование>НДС</Наименование>
                <Ставка>18</Ставка>
            </СтавкаНалога>
        </СтавкиНалогов>
        <Группы>
            <Ид>001bfc8d17d7</Ид>
        </Группы>
        <Описание>Диаметр=100мм
    Длина=120мм
        </Описание>
    </Товар>

    Требуется каждую характеристику (Диаметр,Длина) записать в этот же файл должным образом, а значение элемента удалить (или вообще удалить весь этот элемент), то есть чтобы получилось так

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    <Товар>
        <Ид>001bfc8d17d7</Ид>
        <Наименование>Название товара</Наименование>
        <БазоваяЕдиница Код="796" НаименованиеПолное="Штука" МеждународноеСокращение="">шт</БазоваяЕдиница>
        <ЗначенияРеквизитов>
            <ЗначениеРеквизита>
                <Наименование>ВидНоменклатуры</Наименование>
                <Значение>Товар</Значение>
            </ЗначениеРеквизита>
            <ЗначениеРеквизита>
                <Наименование>ТипНоменклатуры</Наименование>
                <Значение>Товар</Значение>
            </ЗначениеРеквизита>
            <ЗначениеРеквизита>
                <Наименование>Полное наименование</Наименование>
                <Значение>Здесь полное название товара</Значение>
            </ЗначениеРеквизита>
        </ЗначенияРеквизитов>
        <СтавкиНалогов>
            <СтавкаНалога>
                <Наименование>НДС</Наименование>
                <Ставка>18</Ставка>
            </СтавкаНалога>
        </СтавкиНалогов>
        <Группы>
            <Ид>001bfc8d17d7</Ид>
        </Группы>
        <ХарактеристикиТовара>
            <ХарактеристикаТовара>
                <Наименование>Диаметр</Наименование>
                <Значение>100мм</Значение>
            </ХарактеристикаТовара>
            <ХарактеристикаТовара>
                <Наименование>Длина</Наименование>
                <Значение>120мм</Значение>
            </ХарактеристикаТовара>    
        </ХарактеристикиТовара>
    </Товар>

    Я смог только выдернуть характеристики из элемента и придать им нужный вид вот этим кодом

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    $reader = new XMLReader();
    $reader->open($file);

    while ($reader->read()) {
        switch ($reader->nodeType) {
            case (XMLREADER::ELEMENT):
                if ($reader->localName == "Описание") {
                    $reader->read();
                    $rparams = explode("\n", $reader->value);
                    $newitem = "<ХарактеристикиТовара>\n";
                    foreach ($rparams as $rparam) {
                        $pieces = explode("=", $rparam);
                        $newitem .= "<ХарактеристикаТовара>\n";
                        $newitem .= "<Наименование>".$pieces[0]."</Наименование>\n";
                        $newitem .= "<Значение>".$pieces[1]."</Значение>\n";
                        $newitem .= "</ХарактеристикаТовара>\n";
                    }
                    $newitem .= "</ХарактеристикиТовара>\n";
                    echo $newitem;
                }
        }
    }

    Но как теперь записать это в файл, точнее заменить Описание на ХарактеристикиТовара — никак не пойму … может кто подскажет?

  • Алексей

    Добрый день,

    $xml->openURI(‘test.xml’);

    А как сделать чтобы test.xml записался в другую папку на другом сайте через фтп.

    Спасибо.

  • Дмитрий

    Учитель ты хренов…
    «Работа с XML в PHP – Добавление узлов дерева в существующий XML»… И что??? Где новый элемент, как было? Как стало после???
    Может тебе это все и так понятно, а не опытному человеку ни хрена не понятно. Так что если вздумал учить — то разжовывай как первоклассникам…

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

    Не отвечать

    Подписаться на комментарии к этой статье по RSS

    Яндекс.Метрика