Потоковый парсер xml. Парсинг XML с помощью SimpleXML. SimpleXML в действии

28.3K

Я видел много xml parser`ов, но не затрагивал при этом веб-программирование. Теперь же я хочу выяснить и научиться вместе с вами, как сделать простой xml parser в php.

А зачем? Надо!

Не, ну на самом деле: xml-файлы — очень полезная штука. И любой профессионал должен… нет, не должен, а обязан знать, как с ними работать. Мы же хотим стать профессионалами? Если Вы на моем блоге, то такое желание у Вас есть.

Мы предполагаем, что знаем, что такое XML и описывать его здесь не будем. Ну, если не знаем, то легко узнаем здесь: http://ru.wikipedia.org/wiki/XML

При поиске способов парсинга XML на PHP, я обнаружил простой набор функций в PHP для работы с XML-файлами, который называется «XML Parser Functions». Парсинг начинается с инициализации парсера вызовом функции xml_parser_create:

$xml_parser = xml_parser_create();

Потом нам нужно сказать парсеру, какие функции будут обрабатывать попадающиеся ему xml-теги и текстовую информацию в процессе парсинга. Т.е. нужно установить некие обработчики:

xml_set_element_handler($xml_parser, “startElement”, “endElement”);

Эта функция отвечает за установку обработчиков начала элемента и конца элемента. Например, если в тексте xml-файла встретится комбинация, то функция startElement сработает, когда парсер найдет элемент, а функция endElement — при нахождении.

Сами же функции startElement и endElement принимают несколько параметров согласно документации по php:

А как же считывать данные из файла? Мы же пока не видели ни одного параметра для этого ни в одной из функций! А об этом дальше: считывание файла возлагается на плечи программиста, т.е. мы должны использовать стандартные функции для работы с файлами:

Открыли файл. А теперь нужно построчно считывать его и скармливать считываемые строки функции xml_parse:

XML Error: ".xml_error_string(xml_get_error_code($xml_parser)); echo " at line ".xml_get_current_line_number($xml_parser); break; } } ?>

Здесь заметим две очень важные вещи. Первая — это то, что функции xml_parse в третьем параметре нужно передать флаг считывания последней строки (true — если строка последняя, false — если нет). Второе — это то, что как и в любом деле, мы должны следить здесь за ошибками. За это отвечают функции xml_get_error_code и xml_error_string. Первая функция получает код ошибки, а вторая — по полученному коду возвращает текстовое описание ошибки. Что в результате возникновения ошибки получится — рассмотрим позже. Не менее полезная функция xml_get_current_line_number скажет нам номер текущей обрабатываемой строки в файле.

И как всегда мы должны освободить занимаемые системой ресурсы. Для парсинга XML — это функция xml_parser_free:

xml_parser_free($xml_parser);

Вот, основные функции мы рассмотрели. Пора бы посмотреть их на деле. Для этого я придумал xml-файл с очень простой структурой:




123

71234567890

Назовем этот файл data.xml и попытаемся его распарсить с помощью следующего кода:

Element: $name
"; // имя элемента $depth++; // увеличиваем глубину, чтобы браузер показал отступы foreach ($attrs as $attr => $value) { echo str_repeat(" ", $depth * 3); // отступы // выводим имя атрибута и его значение echo "Attribute: ".$attr." = ".$value."
"; } } function endElement($parser, $name) { global $depth; $depth--; // уменьшаем глубину } $depth = 0; $file = "data.xml"; $xml_parser = xml_parser_create(); xml_set_element_handler($xml_parser, "startElement", "endElement"); if (!($fp = fopen($file, "r"))) { die("could not open XML input"); } while ($data = fgets($fp)) { if (!xml_parse($xml_parser, $data, feof($fp))) { echo "
XML Error: "; echo xml_error_string(xml_get_error_code($xml_parser)); echo " at line ".xml_get_current_line_number($xml_parser); break; } } xml_parser_free($xml_parser); ?>

В результате разработанного нами простейшего скрипта браузер вывел в свое окно следующую информацию:

Element: ROOT
Element: INFO
Attribute: WHO = моя
Element: ADDRESS

Attribute: KVARTIRA = 12
Attribute: DOM = 15
Element: PHONE

Попробуем испортить XML-файл, заменив тег На , а закрывающий тег оставив прежним:

Element: ROOT
Element: INFO
Attribute: WHO = моя
Element: ADDRESS
Attribute: ULICA = моя улица!!
Attribute: KVARTIRA = 12
Attribute: DOM = 15
Element: TELEPHONE

XML Error: Mismatched tag at line 5

Ух ты! Сообщения об ошибках работают! Причем довольно информативные.

Эх, я забыл еще одну вещь… Мы же не вывели текст, содержащийся внутри тегов address и phone. Исправляем наш недочет — добавляем текстовый обработчик с помощью функции xml_set_character_data_handler:

xml_set_character_data_handler($xml_parser, ’stringElement’);

И добавляем в код саму функцию-обработчик.

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

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

Стоит начать с того, что SimpleXML — это отдельный подключаемый модуль, а потому его надо заранее подключить на используемом сервере.

Теперь мы можем работать!

Для того, чтобы обработать документ, используем функцию simplexml_load_file(). В качестве параметра ей передается адрес файла в формате eXtended Markup Language (XML — Ваш К.О.).

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

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

Для примера я возьму простенькую конструкцию отсюда :


>
>
> PHP: Появление Парсера>
>
>
> Ms. Coder>
> Onlivia Actora>
>
>
> Mr. Coder>
> El ActÓ r>
>
> > Mr. Parser> > John Doe> > >
>
Таким образом, это язык. Это все равно язык программирования. Или
это скриптовый язык? Все раскрывается в этом документальном фильме,
похожем на фильм ужасов.
>
>
> PHP решает все мои задачи в web>
>
7>
5>
PG> >
>

Пусть это будет файл export.xml, который лежит прямо в корне моего сервера вместе с обрабатывающим его скриптом.
Массив строится в соответствии со структурой DOM-элементов в XML-документе. Обработка начинается от корня. Для того, чтобы получить имя Ms. Coder, мы должны выстроить следующий путь: $xml->movies->movie->characters->character->name.
Обращаю внимание, что мы выбираем конкретное значение. Отсюда и берется запись такого рода character — не забываем, что мы работаем с массивом!

Как и любой массив, наши данные можно обработать при помощи цикла foreach. Код будет такой:

$xml = simplexml_load_file ("export.xml" ) ; //выгрузили файл
$ttl = $xml -> movies -> movie -> title ; //получили заголовок. он один, так что или другое значение ставить не надо

foreach ($xml -> movies -> movie -> caracters as $crc ) // а теперь поработаем в динамике
{
//выведем имена героев
$name = $crc -> caracter -> name ;
echo ("$name
"
) ;
}

Такой код положит в переменную $ttl текст «PHP: Появление Парсера», а затем выведет построчно на экран имена героев
Ms. Coder, Mr. Coder, Mr. Parser.

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

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

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

Работа с XML в PHP

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

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

$str = " Коля 25 1000 "; $xml = new SimpleXMLElement($str);

Сейчас у нас в переменной $xml хранится объект с разобранным XML. Обращаясь к свойствам этого объекта можно получать доступ с содержимому тегов XML. Как именно - разберем чуть ниже.

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

Коля 25 1000

$xml = simplexml_load_file(путь к файлу или урл);

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

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

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

Коля 25 1000

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

$xml = simplexml_load_file(путь к файлу или урл); echo $xml->name; //выведет "Коля" echo $xml->age; //выведет 25 echo $xml->salary; //выведет 1000

Как вы видите, у объекта $xml есть свойства, соответствующие тегам.

Вы может обратили внимание, что тег нигде не фигурирует при обращении. Это потому, что он корневой тег. Можно переименовать его, например, на - и ничего не поменяется:

Коля 25 1000

$xml = simplexml_load_file(путь к файлу или урл); echo $xml->name; //выведет "Коля" echo $xml->age; //выведет 25 echo $xml->salary; //выведет 1000

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

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

Коля 25 1000

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

$xml = simplexml_load_file(путь к файлу или урл); echo $xml->worker->name; //выведет "Коля" echo $xml->worker->age; //выведет 25 echo $xml->worker->salary; //выведет 1000

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

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

Номер 1

$xml = simplexml_load_file(путь к файлу или урл); echo $xml->worker["name"]; //выведет "Коля" echo $xml->worker["age"]; //выведет 25 echo $xml->worker["salary"]; //выведет 1000 echo $xml->worker; //выведет "Номер 1"

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

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

Коля Иванов

$xml = simplexml_load_file(путь к файлу или урл); echo $xml->worker->{first-name}; //выведет "Коля" echo $xml->worker->{last-name}; //выведет "Иванов"

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

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

Коля 25 1000 Вася 26 2000 Петя 27 3000

$xml = simplexml_load_file(путь к файлу или урл); foreach ($xml as $worker) { echo $worker->name; //выведет "Коля", "Вася", "Петя" }

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

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

$xml = simplexml_load_file(путь к файлу или урл); var_dump(json_decode(json_encode($xml), true));

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

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

Зачастую на сайте есть файл sitemap.xml. В этом файле хранятся ссылки на все страницы сайта для удобства индексации их поисковыми системами (индексация - это по сути и есть парсинг сайта яндексом и гуглом).

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

Как проверить наличие этого файла: пусть мы парсим сайт site.ru, тогда обратитесь в браузере к site.ru/sitemap.xml - если что-то увидите, значит он там есть, а если не увидите - то увы.

Если sitemap есть - то в нем содежатся ссылки на все страницы сайта в формате XML. Спокойно забираете этот XML, парсите его, отделяете ссылки на нужные вам страницы любым удобным вам способом (например, анализом URL, который был описан в методе паука).

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

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

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

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

Когда все решите - переходите к изучению новой темы.

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

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

$dom = new domDocument("1.0", "utf-8"); // Создаём XML-документ версии 1.0 с кодировкой utf-8
$dom->load("users.xml"); // Загружаем XML-документ из файла в объект DOM
$root = $dom->documentElement; // Получаем корневой элемент
$childs = $root->childNodes; // Получаем дочерние элементы у корневого элемента
/* Перебираем полученные элементы */
for ($i = 0; $i < $childs->length; $i++) {
$user = $childs->item($i); // Получаем следующий элемент из NodeList
$lp = $user->childNodes; // Получаем дочерние элементы у узла "user"
$id = $user->getAttribute("id"); // Получаем значение атрибута "id" у узла "user"
$login = $lp->item(0)->nodeValue; // Получаем значение узла "login"
$password = $lp->item(1)->nodeValue; // Получаем значение узла "password"
/* Выводим полученные данные */
echo "ID: $id
";
echo "Логин: $login
";
echo "Пароль: $password
";
echo "-----------------------
";
}
?>

Из этого кода Вы должны не только понять, как парсить XML-документ на PHP , но и то, что сам процесс парсинга зависит от структуры документа . То есть Вы должны знать, какова структура, иначе разобрать такой документ будет проблемно. Я уже когда-то писал, что главная особенность XML - это строгость синтаксиса . Надеюсь, Вы теперь понимаете, почему это так важно. Без этой "жёсткости кода " было бы крайне затруднительно парсить документы, а вещь эта очень часто требуется. Элементарно при импорте каких-то данных из XML-файла с последующим размещением их в базе данных.


публикация данной статьи разрешена только со ссылкой на сайт автора статьи

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

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

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

В PHP существует несколько встроенных вариантов обработки XML - SimpleXML, DOM, SAX.
Все эти варианты подробно описаны во многих статьях с примерами, но все примеры демонстрируют работу с полным XML документом.

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

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

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

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

Function webi_xml ($file )
{

########
### функция работы с данными

{
print $data ;
}
############################################



{
print $name ;
print_r ($attrs );
}


## функция закрывающих тегов
function endElement ($parser , $name )
{
print $name ;
}
############################################

($xml_parser , "data" );

// открываем файл
$fp = fopen ($file , "r" );

$perviy_vxod = 1 ; $data = "" ;



{

$simvol = fgetc ($fp ); $data .= $simvol ;


if($simvol != ">" ) { continue;}


echo "

break;
}

$data = "" ;
}
fclose ($fp );

Webi_xml ("1.xml" );

?>

В этом примере я все сложил в одну функцию webi_xml() и в самом низу видно ее вызов.
Сам скрипт состоит из трех основных функций:
1. Функция которая ловит открытие тега startElement()
2. Функция которая ловит закрытие тега endElement()
3. И функция получения данных data() .

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



< title > Простой хлеб
< ingredient amount = "3" unit = "стакан" > Мука
< ingredient amount = "0.25" unit = "грамм" > Дрожжи
< ingredient amount = "1.5" unit = "стакан" > Тёплая вода
< ingredient amount = "1" unit = "чайная ложка" > Соль
< instructions >
< step > Смешать все ингредиенты и тщательно замесить .
< step > Закрыть тканью и оставить на один час в тёплом помещении .
< step > Замесить ещё раз , положить на противень и поставить в духовку .
< step > Посетить сайт сайт


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

$xml_parser = xml_parser_create ();
xml_parser_set_option ($xml_parser , XML_OPTION_CASE_FOLDING , true );

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

xml_set_element_handler ($xml_parser , "startElement" , "endElement" );
xml_set_character_data_handler ($xml_parser , "data" );

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

И отправит ее в разборщик
xml_parse ($xml_parser , $data , feof ($fp )) ;
После обработки данных строковая переменная сбрасыватеся и снова начинается сбор данных в строку и во второй раз сформируется строка

В третий
</b><br> в четвертый <br><b> Простой хлеб

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

le>Простой хлеб
Так отправить данные обработчику нельзя, так как тег разорвался.
Вы можете придумать свою методику посылания данных в обработчик, например собирать по 1 мегабайту данных и отправлять в обработчик для повышения скорости, только следите чтобы теги всегда завершались, а данные можно разрывать
Простой </b><br><b>хлеб

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

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

Начинаем с функции открывающих тегов startElement ($parser , $name , $attrs )
Предположим, что обработка дошла до строки
< ingredient amount = "3" unit = "стакан" > Мука
Тогда внутри функции переменная $name будет равна ingredient то есть название открытого тега (до закрытия тега дело еще не дошло).
Так же в данном случае будет доступен массив атрибутов этого тега $attrs , в котором будут данные amount = "3" и unit = "стакан" .

После этого пошла обработка данных открытого тега функцией data ($parser , $data )
В переменной $data будет все, что находится между открывающим и закрывающим тегом, в нашем случае это текст Мука

И завершается обработка нашей строки функцией endElement ($parser , $name )
Это название закрытого тега, в нашем случае $name будет равна ingredient

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

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

Function webi_xml ($file )
{
global $webi_depth ; // счетчик, для отслеживания глубины вложенности
$webi_depth = 0 ;
global $webi_tag_open ; // будет содержать массив открытых в данный момент тегов
$webi_tag_open = array();
global $webi_data_temp ; // этот массив будет содержать данные одного тега

####################################################
### функция работы с данными
function data ($parser , $data )
{
global $webi_depth ;
global $webi_tag_open ;
global $webi_data_temp ;
// добавляем данные в массив с указанием вложенности и открытого в данный момент тега
$webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "data" ].= $data ;
}
############################################

####################################################
### функция открывающих тегов
function startElement ($parser , $name , $attrs )
{
global $webi_depth ;
global $webi_tag_open ;
global $webi_data_temp ;

// если уровень вложенности уже не нулевой, значит один тег уже открыт
// и данные из него уже в массиве, можно их обработать
if ($webi_depth )
{




" ;

print "
" ;
print_r ($webi_tag_open ); // массив открытых тегов
print "


" ;

// после обработки данных удаляем их для освобождения памяти
unset($GLOBALS [ "webi_data_temp" ][ $webi_depth ]);
}

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

$webi_tag_open [ $webi_depth ]= $name ; // добавляем открытый тег в массив информаци
$webi_data_temp [ $webi_depth ][ $name ][ "attrs" ]= $attrs ; // теперь добавляем атрибуты тега

}
###############################################

#################################################
## функция закрывающих тегов
function endElement ($parser , $name ) {
global $webi_depth ;
global $webi_tag_open ;
global $webi_data_temp ;

// здесь начинается обработка данных, например добаление в базу, сохранение в файл и т.д.
// $webi_tag_open содержит цепочку открытых тегов по уровню вложенности
// например $webi_tag_open[$webi_depth] содержит название открытого тега чья информация сейчас обрабатывается
// $webi_depth уровень вложенности тега
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["attrs"] массив атрибутов тега
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["data"] данные тега

Print "данные " . $webi_tag_open [ $webi_depth ]. "--" .($webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "data" ]). "
" ;
print_r ($webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "attrs" ]);
print "
" ;
print_r ($webi_tag_open );
print "


" ;

Unset($GLOBALS [ "webi_data_temp" ]); // после обработки данных удаляем массив с данными целиком, так как произошло закрытие тега
unset($GLOBALS [ "webi_tag_open" ][ $webi_depth ]); // удаляем информацию об этом открытом теге... так как он закрылся

$webi_depth --; // уменьшаем вложенность
}
############################################

$xml_parser = xml_parser_create ();
xml_parser_set_option ($xml_parser , XML_OPTION_CASE_FOLDING , true );

// указываем какие функции будут работать при открытии и закрытии тегов
xml_set_element_handler ($xml_parser , "startElement" , "endElement" );

// указываем функцию для работы с данными
xml_set_character_data_handler ($xml_parser , "data" );

// открываем файл
$fp = fopen ($file , "r" );

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

// цикл пока не найден конец файла
while (! feof ($fp ) and $fp )
{
$simvol = fgetc ($fp ); // читаем один символ из файла
$data .= $simvol ; // добавляем этот символ к данным для отправки

// если символ не завершающий тег, то вернемся к началу цикла и добавим еще один символ к данным, и так до тех пор, пока не будет найден закрывающий тег
if($simvol != ">" ) { continue;}
// если закрывающий тег был найден, теперь отправим эти собранные данные в обработку

// проверяем, если это первый вход в файл, то удалим все, что находится до тега // так как иногда может встретиться мусор до начала XML (корявые редакторы, либо файл получен скриптом с другого сервера)
if($perviy_vxod ) { $data = strstr ($data , "

// теперь кидаем данные в разборщик xml
if (! xml_parse ($xml_parser , $data , feof ($fp ))) {

// здесь можно обработать и получить ошибки на валидность...
// как только встретится ошибка, разбор прекращается
echo "
XML Error: " . xml_error_string (xml_get_error_code ($xml_parser ));
echo " at line " . xml_get_current_line_number ($xml_parser );
break;
}

// после разбора скидываем собранные данные для следующего шага цикла.
$data = "" ;
}
fclose ($fp );
xml_parser_free ($xml_parser );
// удаление глобальных переменных
unset($GLOBALS [ "webi_depth" ]);
unset($GLOBALS [ "webi_tag_open" ]);
unset($GLOBALS [ "webi_data_temp" ]);

Webi_xml ("1.xml" );

?>

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

Ну вот и все, теперь при обработке файла любого размера памяти хватит, а вот время работы скрипта увеличить можно несколькими способами.
В начало скрипта вставьте функцию
set_time_limit (6000 );
или
ini_set ("max_execution_time" , "6000" );

Либо добавьте в файл.htaccess текст
php_value max_execution_time 6000

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

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

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

Понравилось? Лайкни нас на Facebook