Дело в том что xml, который я планирую обрабатывать и добавлять в БД весит 250 МБ... И парсить его желательно каждый день. Файл содержит базу книг магазина Лабиринт.ру.
На моём хостинге ограничение работы скрипта - 30 сек. и соответственно толкового ничего не получается...
Вот сам файл:
XML - http://partner.labirint.ru/xml/export/genres/-1.xml (256 MB).
ZIPXML - http://partner.labirint.ru/xml/export/genres/-1.xml.gz (55,1 MB).
Действия которые предпринял:
1) Написал первый скрипт используя SimpleXML. Но вычитал что он не в силах обрабатывать большие файлы. Скрипт ест более 300МБ оперативы и мне сказали чтобы я про него забыл:
<?php
// Подключаем БД
require_once('db.php');
// Загружаем прайс
$xml = simplexml_load_file('http://partner.labirint.ru/xml/export/genres/145.xml');
// Формируем цикл
foreach ($xml->shop->offers->offer as $item) {
$name = iconv("UTF-8","Windows-1251", $item->name);
$category = iconv("UTF-8","Windows-1251", $item->category);
$img = iconv("UTF-8","Windows-1251", $item->picture_big);
$status = iconv("UTF-8","Windows-1251", $item->orderingTime->ordering);
$author = iconv("UTF-8","Windows-1251", $item->author);
$price = iconv("UTF-8","Windows-1251", $item->price);
$publisher = iconv("UTF-8","Windows-1251", $item->publisher);
$year = iconv("UTF-8","Windows-1251", $item->year);
$description = iconv("UTF-8","Windows-1251", $item->description);
// Отображаем ход результата
echo "<b> $name </b> - <font color='red'>импорт успешен!</font>";
echo "<hr>";
// Подключение к базе
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
$query = "INSERT INTO products VALUES (0, NOW(), '$name', '$author', '$price', '$status', '$category', '$img', '$series', '$publisher', '$isbn', '$description')";
$data = mysqli_query($dbc, $query);
}
// Закрываем соединение
mysqli_close($dbc);
?>
2) Почитал про функцию разборщика (парсера) 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)
{
// здесь начинается обработка данных, например добаление в базу, сохранение в файл и т.д.
// $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']).'<br>';
print_r($webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]['attrs']);
print '<br>';
print_r($webi_tag_open); // массив открытых тегов
print '<hr>';
// после обработки данных удаляем их для освобождения памяти
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']).'<br>';
print_r($webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]['attrs']);
print '<br>';
print_r($webi_tag_open);
print '<hr>';
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, '<?'); $perviy_vxod=0;}
// теперь кидаем данные в разборщик xml
if (!xml_parse($xml_parser, $data, feof($fp))) {
// здесь можно обработать и получить ошибки на валидность...
// как только встретится ошибка, разбор прекращается
echo "<br>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');
?>
Этот скрипт лишь демонстрирует принцип работы, но не является готовым решением=)
Так вот проблема стала в том что, хоть убей не пойму каким образом можно вывести из XML в этом скрипте, только те тэги которые мне нужны...
Например, также как я делал в SimpleXML: echo "$name - импортирован!"; .
Подскажите пожалуйста неучу=)
Или может кто-нибудь сталкивался с такой проблемой и готов предложить другое решение=)
Спустя 24 минуты, 30 секунд (23.04.2011 - 15:45) Mirexzpalich написал(а):
Так ты сделай так.... Обработал одну часть редиректнулся, обрабатываешь следующую.... Так все ГУД будет... тоже недавно с такой проблемкой столкнулся....
Спустя 14 минут, 46 секунд (23.04.2011 - 16:00) borland написал(а):
Спасибо, но если б я знал как бы мне грамотно редиректнуться=)
Спустя 3 часа, 54 минуты, 57 секунд (23.04.2011 - 19:55) Mirexzpalich написал(а):
borland
Не понял?? Всмысле грамотно редиректнуться?
Не понял?? Всмысле грамотно редиректнуться?
Спустя 22 часа, 51 минута, 20 секунд (24.04.2011 - 18:46) Guest написал(а):
Mirexzpalich
Ну в смысле как вы свою проблему решили?=) Был бы очень признателен за помощь!
Хотя бы где можно почитать про парсинг больших файлов?
Просмотрел кучу ресурсов, но не нашёл где описана именно обработка построчно или по кускам...
Вы простите за то что я в этом вопросе ни бум-бум, просто только недавно PHP начал изучать=)
Ну в смысле как вы свою проблему решили?=) Был бы очень признателен за помощь!
Хотя бы где можно почитать про парсинг больших файлов?
Просмотрел кучу ресурсов, но не нашёл где описана именно обработка построчно или по кускам...
Вы простите за то что я в этом вопросе ни бум-бум, просто только недавно PHP начал изучать=)
Спустя 9 минут, 26 секунд (24.04.2011 - 18:55) borland написал(а):
Mirexzpalich
А что вы подразумеваете под "редиректнуться"?
А что вы подразумеваете под "редиректнуться"?
Спустя 4 минуты, 43 секунды (24.04.2011 - 19:00) Mirexzpalich написал(а):
Ну... давай условимся, что считывать будетм по к строк или к еще чегото там...
Вот.... дальше... Когда заходим на страницу обработки в первый раз... ее УРЛ пусть будет такой
Вот.... дальше... Когда заходим на страницу обработки в первый раз... ее УРЛ пусть будет такой
"http://purse.ru/?part=0"
// Берем part
$part = $_GET['part']; //Получили, какаю часть файла мы уже обработали.....
// сейчас пока -
//определим с какой строчки будет обрабатывать
$start = $part*$k;
// по какую
$end = $start+$k-1;
.....
// Обработали
......
// делаем редирект сюда же, но уже
...."http://purse.ru/?part=".($part+1);
// Т.о. в $part у нас будет хранться информация, о том какаю часть мы уже обработали....
// Ну... можно хратнить номер строки... никто не мешает...
Спустя 2 минуты, 25 секунд (24.04.2011 - 19:02) Mirexzpalich написал(а):
Цитата (borland @ 24.04.2011 - 15:55) |
Mirexzpalich А что вы подразумеваете под "редиректнуться"? |
перенаправиться на....