php парсинг больших xml

Средства парсинга XML в PHP

В личной практике задача разбирать XML средствами PHP возникла еще в 2005. Однако, при попытке разобраться и написать несложный скрипт, загружающий XML-файл в массив, я наткнулся на довольно серьёзную проблему – не существует нормальных программных средств и бинарных библиотек PHP для работы с XML. По мере работы с XML средствами PHP и эволюции PHP применялись различные технологии разбора XML кода, о них далее и пойдет речь.

Сперва приведу сводную таблицу совместимости средств PHP и библиотек XML.

php парсинг больших xml. Смотреть фото php парсинг больших xml. Смотреть картинку php парсинг больших xml. Картинка про php парсинг больших xml. Фото php парсинг больших xml

Самым совместимым оказался SAX (Simple API for XML), он поддерживается даже в библиотеке EXPAT имеющейся во всех версиях PHP 4 и выше. Однако его возможности и способы применения вызвали резко негативную реакцию – нет возможности модификации XML, крайне громоздкий и сложный код с большим количеством мест для потенциальных ошибок.

DOMXML ужасная вещь, т.к. существовала в виде дополнительных экспериментальных библиотек для PHP 4. В PHP 5 не включена, т.к. PHP 5 по умолчанию обладает более универсальным средством DOM (Стандарт W3C DOM level 3). DOM наиболее документирован (English PHP & W3C) и завершен, однако не включен в PHP 4, т.к. был разработан только к началу 2006. Если выбор станет DOM или PHP4, однозначно следует сказать DOM, т.к. на сегодняшний день PHP 5 имеется у любого уважающего себя хостинг провайдера. Тем более у разработчика, есть возможность писать PHP 4 совместимый код, т.к. PHP 4 обладает базовой DOM и она поддерживает некоторые основные функции новой DOM.

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

В Рунете небыло никакой более-менее полезной литературы на тот момент (осень 2007), все разработчики наповал использовали SAX (часто даже свои библиотеки базирующиеся на SAX) либо DOMXML. О DOM ещё мало кто слышал, а те, кто слышал, отказывались от использования в пользу более старого и менее стандартного, но более привычного DOMXML. Таким образом, имелся крайне низкий уровень реализации и переносимость существующих WEB решений использующих XML. Решение использовать новое, удобное, одобренное W3C средство DOM, было единственно правильным. DOM в PHP по его совместимости и взаимопониманию идентичен DOM’у в JS.

Проведем сравнительный анализ производительности SAX PHP 4 и DOM PHP 5. Будет произведен замер времени разбора следующего XML-файла.

php парсинг больших xml. Смотреть фото php парсинг больших xml. Смотреть картинку php парсинг больших xml. Картинка про php парсинг больших xml. Фото php парсинг больших xml

$GLOBALS[‘sax’][‘links’] = array(); // В этом массиве будут храниться блоки ссылок, полученные из XML файла
$GLOBALS[‘sax’][‘current_linksblock’]=null;// Текущий блок ссылок. Используется в процессе импорта данных
$GLOBALS[‘sax’][‘page_r’] =0;
$GLOBALS[‘sax’][‘page_i’] =-1;
$GLOBALS[‘sax’][‘link_r’] =0;
$GLOBALS[‘sax’][‘link_i’] =-1;
$GLOBALS[‘sax’][‘index’] =null;// Текущий индекс в массиве ссылок.
// Используется в процессе импорта данных

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

Приведем 2 метода разбора того же XML файла, базирующиеся на DOM PHP 5.
Метод 1
/* here we must specify the version of XML : i.e: 1.0 */
$xml = new DomDocument(‘1.0’);
$xml->load($link_file);

Метод использует физическую безадресную навигацию по дереву XML документа.

Метод 2
/* here we must specify the version of XML : i.e: 1.0 */
$xml = new DomDocument(‘1.0’);
$xml->load($link_file);

Метод использует ассоциативно-адресную навигацию по дереву XML документа.
В заключении замечу, что все три алгоритма в результате получают абсолютно идентичные массивы данных:

php парсинг больших xml. Смотреть фото php парсинг больших xml. Смотреть картинку php парсинг больших xml. Картинка про php парсинг больших xml. Фото php парсинг больших xml

Тесты производительности алгоритмов производились с учетом следующих условий:
Платформа AMD Athlon(tm) 64 X2 Dual Core Processor 4200+, DDR 2 1024 MB.
Веб-сервер Windows NT 5.1 build 2600, Apache/1.3.33 (Win32) PHP/5.1.6.

php парсинг больших xml. Смотреть фото php парсинг больших xml. Смотреть картинку php парсинг больших xml. Картинка про php парсинг больших xml. Фото php парсинг больших xml
php парсинг больших xml. Смотреть фото php парсинг больших xml. Смотреть картинку php парсинг больших xml. Картинка про php парсинг больших xml. Фото php парсинг больших xml
php парсинг больших xml. Смотреть фото php парсинг больших xml. Смотреть картинку php парсинг больших xml. Картинка про php парсинг больших xml. Фото php парсинг больших xml

График производительности позволяет сделать следующие заключения: SAX наиболее стабилен и его производительность не зависит ни от положения в теле программы, ни от нагрузки на сервер.
Рассмотрим среднеквадратичные показатели производительности для каждой группы тестов.

php парсинг больших xml. Смотреть фото php парсинг больших xml. Смотреть картинку php парсинг больших xml. Картинка про php парсинг больших xml. Фото php парсинг больших xml

1-SAX Произв 1
2-DOM 1 Произв 2
3-DOM 2 Произв 3
Make — режим сборки, Run 10 times — режим нагрузки.

1)Make 2-3-1(порядок следования)
2)Run 10 times 2-3-1(порядок следования)
3)Make 3-2-1(порядок следования)
4)Run 10 times 3-2-1(порядок следования)
5)Make 1-2-3(порядок следования)
6)Run 10 times 1-2-3(порядок следования)
7)Make 1-3-2(порядок следования)
8)Run 10 times 1-3-2(порядок следования)

Очевидно, что наиболее важным на данном этапе анализа является выявление наиболее производительного метода разбора XML основанного на DOM, SAX не рассматриваем, т.к. его отставание и недостатки очевидны.
Напомню, метод 1 использует физическую безадресную навигацию по дереву XML документа, менее удобочитаем, чем метод 2, который использует ассоциативно-адресную навигацию по дереву XML документа.
Для нас наиболее важны режимы результаты производительности при режимах нагрузки, такими являются четные тесты:

php парсинг больших xml. Смотреть фото php парсинг больших xml. Смотреть картинку php парсинг больших xml. Картинка про php парсинг больших xml. Фото php парсинг больших xml

Тесты 2 и 6, тесты в которых метод 1 идет первым, тесты 4 и 8, тесты в которых метод 2 идет первым.

Из графика следует, что при своем удобстве метод 2 достигает наивысших показателей производительности, только при многочисленном использовании XML в программе.

Метод 1, при меньшей лаконичности и пиковой производительности относительно метода 2, является более стабильным в использовании для разбора в единственном месте работы PHP скрипта.

Таким образом, переход на DOM PHP 5, в независимости от способа разбора XML документа, вполне оправдан, как по удобству кода, так и по производительности, тем более, с учетом того, что в настоящее время PHP 4 практически не используется.

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

Источник

Разбор большого XML файла с помощью PHP

В этой статье я покажу пример, как разобрать большой XML файл. Если на вашем сервере (хостинге) не запрещено увеличение времени работы скрипта, то можно разбирать XML файл весом хоть гигабайты, сам лично разбирал только файлы от озона весом 450 мегабайт.

При разборе больших XML файлов возникает две проблемы:
1. Не хватает памяти.
2. Не хватает выделенного времени для работы скрипта.

Вторую проблему с временем решить можно, если сервером это не запрещено.
А вот проблему с памятью решить сложно, даже если речь идет о своем сервере, то ворочать файлы по 500 мегабайт не очень просто а уж на хостинге и на VDS увеличить память просто не получится.

Вот один из примеров, получаем объект из XML файла

Теперь можно обрабатывать этот объект, НО.
Как видно, весь XML файл считывается в память, затем все разбирается в объект.
То есть все данные попадают в память и если выделенной памяти мало, то скрипт останавливается.

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

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

$perviy_vxod = 1 ; // флаг для проверки первого входа в файл
$data = «» ; // сюда собираем частями данные из файла и отправляем в разборщик xml

Предположим что содержимое файла 1.xml некий рецепт

Начинаем все с вызова общей функции webi_xml ( ‘1.xml’ );
Дальше в этой функции стартует разборщик и все имена тегов переводим в верхний регистр, чтобы все теги имели одинаковый регистр.

Теперь указываем какие функции будут работать для отлова открытия тега, закрытия и обработки данных

Обратите внимание, что строковая переменная всегда формируется по законченному тегу > и не обязательно посылать разбощику открытый и закрытый тег с данными например
Простой хлеб
Данному обработчику важно получить целый не разбитый тег, хоть один открытый, а в следущий шаг закрытый тег, или сразу получить 1000 строк файла, не важно, главное чтобы тег не разрывался, например
Простой хлеб
Так отправить данные обработчику нельзя, так как тег разорвался.
Вы можете придумать свою методику посылания данных в обработчик, например собирать по 1 мегабайту данных и отправлять в обработчик для повышения скорости, только следите чтобы теги всегда завершались, а данные можно разрывать
Простой
хлеб

Таким образом частями, как вы пожелаете можно отправить большой файл в обработчик.

Теперь рассмотрим каким образом эти данные обрабатываются и как их получить.

А после этого опять пошло все по кругу.

Приведенный пример лишь демонстрирует принцип обработки XML, но для реального применения его нужно доработать.
Обычно, разбирать большой XML приходится для занесения данных в базу и для правильной обработки данных нужно знать к какому открытому тегу относятся данные, какой уровень вложения тега и какие теги открыты по иерархии выше. Обладая такой информацией можно без проблем правильно обработать файл.
Для этого нужно ввести несколько глобальных переменных, которые будут собирать информацию об открытых тегах, вложенности и данные.
Привожу пример, который можно использовать

// теперь пошло открытие следующего тега и дальше обработка его произойдет на следующем шаге
$webi_depth ++; // увеличиваем вложенность

$perviy_vxod = 1 ; // флаг для проверки первого входа в файл
$data = «» ; // сюда собираем частями данные из файла и отправляем в разборщик xml

Весь пример сопроводил комментариями, теперь тестируйте и экспериментируйте.
Обратите внимание, в функции работы с данными в массив данные не просто вставляются, а именно добавляются с помощью «.=» так как данные могут поступать не в целом виде и если сделать просто присвоение, то время от времени вы будете получать данные кусками.

Данные примеры увеличат время работы скрипта до 6000 секунд.
Увеличить время подобным образом можно только в выключенном безопасном режиме.

Если у вас есть доступ к редактированию php.ini можете увеличить время с помощью
max_execution_time = 6000

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

Комментарии

13.11.2009 developer
проверил.
взял файл озона 450 мб с книгами.
и обработал его этим примером.
вставлял в базу данные минут 30, долго, но в итоге вставил.

28.02.2010 leksus.info
у меня хмл-файл на 25 гигов, вот думаю, сколько это времени займёт 🙂
Я так понимаю, если указать считываемые кусочки по 1мб, дело пойдёт быстрее?

01.03.2010 Админ
25 гигов это конечно круто.
если честно, не знаю что тут может ускорить процесс, надо экспериментировать.
разобрать конечно можно такой файл, но сколько часов это будет обрабатываться.

01.05.2010 админ
Alex-Dnepr, конечно, для подобных вещей perl более предпочтителен.
Скорость выполнение подобного разбора в perl должна быть быстрее, но не сильно уж быстрее.
Да и потом у perl по времени тоже существуют ограничения, такие же как в php.

02.05.2010 админ
Alex-Dnepr, на базе strpos() и substr() тоже можно, но будет ли быстрее. мне кажется, что не будет быстрее.
проверки и поиск символов по тексту создаст тоже не малую нагрузку.
Но это все уже тестировать надо.
Если прирост в скорости будет значительный, тогда наверное стоит обратить внимание на обработку строковыми функциями.

10.05.2010 Alex-Dnepr
Здравствйте, Admin.

Какая средняя скорость разбора больших XML файлов sax-парсером была зафиксирована Вами (размер файла/время обработки)?

11.05.2010 админ
Да вот тут я не отвечу. Я не проводил тестов на время.
Была задача сделать разбор файлов до 50 МБ на хостинге.
Естественно обычным способом разобрать не получалось, не хватало памяти.
А вот вариант описанный в этой статье подошел и укладывался в ресурсы хостинга, хватало и памяти и времени.
А вот сколько по времени длились разборы, я вот тут не засекал.

14.05.2010 админ
результат конечно впечатляет, почти в два раза быстрее.
но все ли вы учли? например разбор атрибутов предусмотрели?
может покажите этот пример(на почту), я его обработаю, потестирую и присоединю к этой статье.

15.05.2010 админ
Про атрибуты я упомянул потому, что выделение атрибутов такое же затратное действие как и выделение значений тегов. И если опустить атрибуты, то скорость увеличится, поэтому я и спросил про атрибуты.
А зачем учитывать время работы с базой?
Тут было интересно узнать скорость самого разбора. Раз он быстрее в два раза, значит более предпочтителен.
Ведь может понадобиться не вставлять данные в базу, а лишь найти несколько значений в большом XML

26.07.2010 Виталий
А можно после считывания из xml сразу удалять строку?
т.е. считал, закинул эти данные в базу(например), удалил эту строку и так далее. а то у меня строк 400 считывает и потом 504ю ошибку выдает, приходится удалять уже добавленные строки.

27.07.2010 Никита
Виталий, просто так удалить строку из файла нельзя.
Для этого надо прочитать все оставшиеся строки и записать их в новый файл.

28.07.2010 Виталий
А если крупный файл, то оперативку сильно забивать будет.

28.07.2010 Никита
Виталий, ну у тебя же проблема с какой-то ошибкой после прочтения 400 строк.
Скорее всего просто не хватает времени.
А для того, чтобы выкинуть обработанные строки из файла, нужно оставшиеся строки читать и складывать в новый файл и тут опять же возникнет твоя ошибка.
Если прочитать всю оставшуюся часть файла и сохранить в новый файл, то тут конечно не хватит оперативки, если файл большой.

30.07.2010 Виталий
В общем ничего сочинять не нужно. надо просто запускать такие вещи через крон, и все потихоньку за раз хоть за час хоть за два добавится.

01.04.2011 m11
А можно пример как в базу вставить полученные данные?

12.04.2011 Алексей
Может быть что-то изменилось в PHP’шном парсере. Но факт тот, что сейчас, судя по всему, пляски с поиском начала и конца тегов не нужны.

Источник

xml_parse

(PHP 4, PHP 5, PHP 7, PHP 8)

xml_parse — Запускает разбор XML-документа

Описание

xml_parse() разбирает XML-документ. Обработчики запрограммированных событий вызываются столько раз, сколько необходимо.

Список параметров

Ссылка на используемый XML-анализатор.

Возвращаемые значения

Возвращает 1 при успешном завершении, 0 в противном случае.

Список изменений

ВерсияОписание
8.0.0Параметр parser ожидает экземпляр XMLParser ; ранее ожидался ресурс ( resource ).

Примеры

Пример #1 Разбор по частям больших XML-документов

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

User Contributed Notes 19 notes

Instead of passing a URL, we can pass the XML content to this class (either you
want to use CURL, Socks or fopen to retrieve it first) and instead of using
array, I’m using separator ‘|’ to identify which data to get (in order to make
it short to retrieve a complex XML data). Here is my class with built-in fopen
which you can pass URL or you can pass the content instead :

p/s : thanks to this great help page.

?>

And example of retrieving XML data:
p/s: example use to retrieve weather

// Im using simple curl (the original is in class) to get the contents

create an array like
array[root][child1][child1child1]

The suggestions below have been a great help, but there was one thing I really needed.

I’m parsing Amazon XML data, and I wanted to be able to index into the array using something like:

// standard XML parse object setup

// merge the array of current attributes to the open tag
// NOTE: this does not currently handle multiple attributes with the same name
// (i.e. it will overwrite them with the last values)

// set the latest open tag equal to the tag data

// pop this tag (and any subsequent tags) off the stack of open tag names

Источник

Работа с XML в PHP

Парсинг сайтов

Что такое API? Это набор функций, с помощью которых вы можете слать запрос этому сайту и получать нужный ответ. Вот этот ответ чаще всего приходит в формате XML. Поэтому давайте приступим к его изучению.

Работа с XML в PHP

Пусть у вас есть XML. Он может быть в строке, либо хранится в файле или отдаваться по запросу к определенному URL.

Пусть XML хранится в строке. В этом случае из этой строки нужно создать объект с помощью new SimpleXMLElement:

Если же XML хранится в файле или отдается по обращению к URL (что чаще всего и бывает), то следует использовать функцию simplexml_load_file, которая делает тот же объект $xml:

Приемы работы

В примерах ниже наш XML хранится в файле или по URL.

Пусть дан следующий XML:

Давайте получим имя, возраст и зарплату работника:

Корневой тег в XML может быть только один, так же, как и тег в обычном HTML.

Давайте чуть модифицируем наш XML:

В этом случае у нас получится цепочка обращений:

Работа с атрибутами

Пусть некоторые данные хранятся в атрибутах:

Теги с дефисами

В XML разрешены теги (и атрибуты) с дефисом. В этом случае обращение к таким тегам происходит так:

Перебор циклом

Пусть теперь у нас не один работник, а несколько. В этом случае мы можем перебрать наш объект с помощью цикла foreach:

Из объекта в нормальный массив

Если вам неудобно работать с объектом, вы можете преобразовать его в нормальный массив PHP с помощью следующего хитрого приема:

Больше информации

Парсинг на основе sitemap.xml

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

Подробнее об устройстве sitemap.xml читайте в википедии.

Что вам делать дальше:

Приступайте к решению задач по следующей ссылке: задачи к уроку.

Источник

Php парсинг больших xml

XMLReader это потоковый XML парсер, способный обрабатывать большие объемы данных при низких затратах оперативной памяти.

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

Самый простой пример использования XMLReader.

Предположим, у нас стоит задача импорта из XML в нашу базу данных.

Вот XML структура (файл example.xml) :

Для разбора этой, относительно несложной структуры, достаточно такого кода:

Таким образом, мы решили задачу об импорте из xml:

idcontactnumber
1kenny9(999)-999-99-99
2finny8(888)-888-88-88

Dive into XMLReader

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

Итак, стояла задача обмена конфигурацией web-приложения с 1с. Обмен производится в виде XML документов с общими настройками приложения и ценообразования.

Вот пример конфигурационного xml файла, приходящего в приложение из 1с:

Как видите, уже на первых этапах разработки приложения, минимальный конфигурационный xml довольно объемный, и дальше он будет только расти, с добавлением фич ростом требований к web-приложению.

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

Но довольно слов, приступим к коду:

Сперва нужно разработать общий базовый класс для оберток над этой библиотекой. Назовем наш абстрактный класс AbstractAdvertisementXMLReader.

Как видим, имеется защищенный от агрессивной внешней среды экземпляр XMLReader’а, хэш-массив результатов извлечения, а также контейнер событий.

В конструкторе мы пытаемся инициализировать XMLReader, и открыть с помощью него переданный путь к xml файлу.

Тут все достаточно просто и наглядно.

Теперь давайте реализуем необходимые акцессоры:

Реализация событийной модели:

В качестве параметров, подписчики дополнительно получают контекст, т.е. ссылку на вызывающий объект AbstractAdvertisementXMLReader (либо класс его наследующий).

Осталось добавить в этот класс щепотку базовой логики:

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *