Эта тема на forum.dklab.ru


Scarlet: Parsing XML
Здравствуйте. Проблема такая. Есть большой xml файл. А точнее каталог магазина Озон.
Требуется разобрать его на кусвочки. Я написал работчий код, который это делает (приведу его ниже).
Код превосходно работает с фалами примеро до 60МБ. А вот файлы под 200МБ обрабатывает очень медленно.
Видимо он создает какие-то хитрые объекты гигантских размеров.
Как лучше обойти эту проблему?
Обещанный код:
<?php
//Создание списка фильмов и их цен - ОЗОН

//Скрипт обрабатывает XML документ с помощью стандарта DOM1
include("db.php");
//Подключаем базу данных
$DB->connect_to_mysql('localhost',"root", "", "goods");

function utf8encode($str, $encode=Encoding){
return iconv($encode, 'UTF-8', $str);
}

function utf8decode($str, $encode=Encoding){
return iconv('UTF-8', $encode, $str);
}

// Стандартная кодировка документа
define('Encoding', 'WINDOWS-1251');

print "<B>...Начало обработки!...</B><BR><BR>";
$dom = new DOMDocument('1.0', Encoding);
// Свойство preserveWhiteSpace отвечает за обработку символа \n
// как символа новой строки, а не просто текста
$dom->preserveWhiteSpace = false;
// Свойство formatOutput отвечает за форматированный вывод дерева
// объектов.
$dom->formatOutput = true;
// Закгружаем XML файл как дерево объектов
$dom->load('soft.xml');
// Находим корень
$root = $dom->documentElement; //yml_catalog
// Единственным Потомком yml_catalog является shop,
// он нам и нужен
$nodesList = $root->childNodes;
$root = $nodesList->item(0);
// Получаем список дочерних элементов корня
$nodesList = $root->childNodes;
echo "Всего дочерних узлов у корневого узла: $nodesList->length";
// Обходим все элементы в поисках нужного
$findEltment = "offers";
// Цикл по дочерним элементам
for ($i=0; $i<$nodesList->length; $i++)
{
// Рассматриваем дочерний элемент с номером $i
$child = $nodesList->item($i);
// Если элемент искомый, то получаем список его элементов
if (utf8decode($child->nodeName) == $findEltment)
{
// Получаем список дочерних элементов искомого узла
$nodesList = $child -> childNodes;
echo "<BR><B>Узел $findEltment найден!</B>";
break;

}
echo "<BR>Узел $i ".utf8decode($child->nodeName);
}
echo "<BR>Всего дочерних узлов у $findEltment: $nodesList->length";

// Цикл по дочерним элементам
for ($i=0; $i<$nodesList->length; $i++)
{
// Рассматриваем дочерний элемент с номером $i
$child = $nodesList->item($i);
// Получаем содержание атрибута с ID
$namedNodeMap = $child->attributes;
$idAtt = $namedNodeMap->item(0);
$ID = $idAtt->nodeValue;

//Получаем узлы элемента
$itemList = $child -> childNodes;
$categoryID = "";
for ($p=0; $p<$itemList->length; $p++)
{

$item = $itemList->item($p);
switch($item->nodeName)
{
case 'price':
$price = $item->nodeValue;
break;
case 'url':
$url = $item->nodeValue;
break;
case 'categoryId':
$categoryID .= "-$item->nodeValue-";
break;
case 'picture':
$picture = $item->nodeValue;
break;
case 'name':
$name = utf8decode($item->nodeValue);
$name = str_replace("'", "`", $name);
break;
case 'vendor':
$vendor = utf8decode($item->nodeValue);
$vendor = stripslashes(str_replace("'", "`", $vendor));
break;
case 'description':
$description = utf8decode($item->nodeValue);
$description = stripslashes(str_replace("'", "`", $description));
break;
default:
break;
} //switch
} //for
// Таблица с товарами
$query = "INSERT INTO goods SET
ID='$ID',
categoryID='$categoryID',
picture='$picture',
title='$name',
year='$year',
media='$media',
artist='$artist',
type='soft',
description='$description'";
$DB->query($query);
// Таблица с ценами
$query = "INSERT INTO price SET
goodsID = '$ID',
shopID = '1',
price = '$price',
url='$url'";
$DB->query($query);
}
echo "<BR><BR><B>...Конец обработки...</B>";
?>
Scarlet:
Не правильно выразился, файлы больших размеров этот скрпт обрабатывает не медленно, а практически с нулевым резульатом.
Примерно 50 записей за полтора часа.
Тогда как файл около 30МБ, содержащий около 40000 записей, он обрабатывает за 5 минут.
Антон Макаренко:
Для чтения больших файлов лучше использовать не php_domxml, а SAX - см. раздел мануала "CLXXIII. XML Parser Functions"
Scarlet:
Спасибо. Попробую.
Я попытался программно разбить большой xml файл на много маленьких, но столкнулся с еще одной проблемой.
Если открыть xml файл функцией fopen и читать его построчно, то PHP автоматически убирает все теги.
Т.е. вместо
<catalog>NAME</catalog>
мы получаем просто:
NAME
Как это обойти?

<?php
print "Hello!";
$name='soft';
$max_row = 20000;
$catalog = fopen($name.".xml", "r");
$i=0;
$name_index = 0;
while ($row=fgetss($catalog, 50000)):
if ($i==0)
{
$file = fopen($name.$name_index, "w");
$name_index++;
}

fputs($file, $row);
$i++;

if ($i>$max_row and strpos($row.".xml", "</offer>"))
{
fclose($file);
$i=0;
}
endwhile;
print "END!";

?>
Антон Макаренко:
Scarlet
fgetss
(PHP 3, PHP 4, PHP 5)

fgetss -- Прочитать строку из файла и отбросить HTML-теги
Описание
string fgetss ( resource handle [, int length [, string allowable_tags]] )


Данная функция идентична функции fgets() с той только разницей, что осуществляет отбрасывание любых HTML и PHP-тегов из прочитанной строки.

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

Замечание: Параметр allowable_tags был добавлен в версиях PHP 3.0.13 и PHP 4.0.0.


Параметр length является необязательным начиная с версии PHP 5.

Замечание: Если у вас возникают проблемы с распознаванием PHP окончания строк при чтении файлов на Macintosh-совместимом компьютере или при чтении файлов, созданных на Macintosh-совместимом компьютере, необходимо включить опцию auto_detect_line_endings.

См.также описание функций fgets(), fopen(), fsockopen(), popen() и strip_tags().

Курите мануал
Scarlet:
Я такой невнимательный! =) Бывает, зацикливаюсь на чем-то, а элементарного не вижу.
Спасибо большое!
GlazOrla: Перевод хатэмель в хмель
Кто-нибудь сталкивался с задачей перевода html в xml. Имеется в виду прайс на сайте ГлазОрла.Ру. Не поделитесь опытом?

Эта тема на forum.dklab.ru