Время на прочтение
5 мин
Количество просмотров 82K
На работе попросили провести исследование какими средствами лучше разбирать объёмный XML файл (более 100Mb). Предлагаю сообществу ознакомиться с результатами.
Рассмотрим основные методы работы с XML:
1. Simple XML (documentation)
2. DOM (documentation)
3. xml_parser (SAX) (documentation)
4. XMLReader (documentation)
Simple XML
Минусы: работает очень медленно, собирает весь файл в память, дерево составляется в отдельных массив.
Плюсы: простота работы, работа «из коробки» (требует библиотеки libxml которая включена практически на всех серверах)
Пример использования Simple XML
$xml = simplexml_load_file("price.xml");
echo "<table border='1'>n";
foreach ($xml->xpath('/DocumentElement/price') as $producs) { ?>
<tr>
<td><?php echo $producs->name; ?></td>
<td><?php echo $producs->company; ?></td>
<td><?php echo $producs->city; ?></td>
<td><?php echo $producs->amount ?></td>
</tr>
<?
}
echo "</table>n";
DOM
Минусы: работает очень медленно, как и все предыдущие примеры собирает весь файл в память.
Плюсы: На выходе привычный DOM с которым очень легко работать.
Пример использования DOM
$doc = new DOMDocument();
$doc->load( 'books.xml' );
$books = $doc->getElementsByTagName( "book" );
foreach( $books as $book )
{
$authors = $book->getElementsByTagName( "author" );
$author = $authors->item(0)->nodeValue;
$publishers = $book->getElementsByTagName( "publisher" );
$publisher = $publishers->item(0)->nodeValue;
$titles = $book->getElementsByTagName( "title" );
$title = $titles->item(0)->nodeValue;
echo "$title - $author - $publishern";
xml_parser и XMLReader.
Предыдущие 2 нам не подходят из-за работы с целым файлом, т.к. файлы у нас бывают по 20-30 Mb, и во время работы с ними некоторые блоки образуют цепочку (массив) в 100> Mb
Оба способа работают чтением файла построчно что подходит идеально для поставленной задачи.
Разница между xml_parser и XMLReader в том что, в первом случае вам нужно будет писать собственные функции которые будут реагировать на начало и конец тэга.
Проще говоря, xml_parser работает через 2 триггера – тэг открыт, тэг закрыт. Его не волнует что там идёт дальше, какие данные используются и т.д. Для работы вы задаёте 2 триггера указывающие на функции обработки.
Пример работы xml_parser
class Simple_Parser
{
var $parser;
var $error_code;
var $error_string;
var $current_line;
var $current_column;
var $data = array();
var $datas = array();
function parse($data)
{
$this->parser = xml_parser_create('UTF-8');
xml_set_object($this->parser, $this);
xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1);
xml_set_element_handler($this->parser, 'tag_open', 'tag_close');
xml_set_character_data_handler($this->parser, 'cdata');
if (!xml_parse($this->parser, $data))
{
$this->data = array();
$this->error_code = xml_get_error_code($this->parser);
$this->error_string = xml_error_string($this->error_code);
$this->current_line = xml_get_current_line_number($this->parser);
$this->current_column = xml_get_current_column_number($this->parser);
}
else
{
$this->data = $this->data['child'];
}
xml_parser_free($this->parser);
}
function tag_open($parser, $tag, $attribs)
{
$this->data['child'][$tag][] = array('data' => '', 'attribs' => $attribs, 'child' => array());
$this->datas[] =& $this->data;
$this->data =& $this->data['child'][$tag][count($this->data['child'][$tag])-1];
}
function cdata($parser, $cdata)
{
$this->data['data'] .= $cdata;
}
function tag_close($parser, $tag)
{
$this->data =& $this->datas[count($this->datas)-1];
array_pop($this->datas);
}
}
$xml_parser = new Simple_Parser;
$xml_parser->parse('<foo><bar>test</bar></foo>');
В XMLReader всё проще. Во первых, это класс. Все триггеры уже заданы константами (их всего 17), чтение осуществляется функцией read() которая читает первое вхождение подходящее под заданные триггеры. Далее мы получаем объект в который заносится тип данных (аля триггер), название тэга, его значение. Также XMLReader отлично работает с аттрибутами тэгов.
Пример использования XMLReader
<?php
<?php
Class StoreXMLReader
{
private $reader;
private $tag;
// if $ignoreDepth == 1 then will parse just first level, else parse 2th level too
private function parseBlock($name, $ignoreDepth = 1) {
if ($this->reader->name == $name && $this->reader->nodeType == XMLReader::ELEMENT) {
$result = array();
while (!($this->reader->name == $name && $this->reader->nodeType == XMLReader::END_ELEMENT)) {
//echo $this->reader->name. ' - '.$this->reader->nodeType." - ".$this->reader->depth."n";
switch ($this->reader->nodeType) {
case 1:
if ($this->reader->depth > 3 && !$ignoreDepth) {
$result[$nodeName] = (isset($result[$nodeName]) ? $result[$nodeName] : array());
while (!($this->reader->name == $nodeName && $this->reader->nodeType == XMLReader::END_ELEMENT)) {
$resultSubBlock = $this->parseBlock($this->reader->name, 1);
if (!empty($resultSubBlock))
$result[$nodeName][] = $resultSubBlock;
unset($resultSubBlock);
$this->reader->read();
}
}
$nodeName = $this->reader->name;
if ($this->reader->hasAttributes) {
$attributeCount = $this->reader->attributeCount;
for ($i = 0; $i < $attributeCount; $i++) {
$this->reader->moveToAttributeNo($i);
$result['attr'][$this->reader->name] = $this->reader->value;
}
$this->reader->moveToElement();
}
break;
case 3:
case 4:
$result[$nodeName] = $this->reader->value;
$this->reader->read();
break;
}
$this->reader->read();
}
return $result;
}
}
public function parse($filename) {
if (!$filename) return array();
$this->reader = new XMLReader();
$this->reader->open($filename);
// begin read XML
while ($this->reader->read()) {
if ($this->reader->name == 'store_categories') {
// while not found end tag read blocks
while (!($this->reader->name == 'store_categories' && $this->reader->nodeType == XMLReader::END_ELEMENT)) {
$store_category = $this->parseBlock('store_category');
/*
Do some code
*/
$this->reader->read();
}
$this->reader->read();
}
} // while
} // func
}
$xmlr = new StoreXMLReader();
$r = $xmlr->parse('example.xml');
Тест производительности
Код генератора example.xml
<?php
$xmlWriter = new XMLWriter();
$xmlWriter->openMemory();
$xmlWriter->startDocument('1.0', 'UTF-8');
$xmlWriter->startElement('shop');
for ($i=0; $i<=1000000; ++$i) {
$productId = uniqid();
$xmlWriter->startElement('product');
$xmlWriter->writeElement('id', $productId);
$xmlWriter->writeElement('name', 'Some product name. ID:' . $productId);
$xmlWriter->endElement();
// Flush XML in memory to file every 1000 iterations
if (0 == $i%1000) {
file_put_contents('example.xml', $xmlWriter->flush(true), FILE_APPEND);
}
}
$xmlWriter->endElement();
// Final flush to make sure we haven't missed anything
file_put_contents('example.xml', $xmlWriter->flush(true), FILE_APPEND);
Результаты тестирования (чтение без разбора данных)
Характеристики тестовой среды
Ubuntu 16.04.1 LTS
PHP 7.0.15
Intel® Core(TM) i5-3550 CPU @ 3.30GHz, 16 Gb RAM, 256 SSD
Метод | Время выполнения (19 Mb) | Время выполнения (190 Mb) |
---|---|---|
Simple XML | 0.46 сек | 4.56 сек |
DOM | 0.52 сек | 4.09 сек |
xml_parse | 0.22 сек | 2.25 сек |
XML Reader | 0.26 сек | 2.18 сек |
P.S. Советы и комментарии с удовольствием выслушаю. Прошу сильно не пинать
20.11.21 — 19:02
Есть файлик XML 320МБ
У VSCode парсер на этом объёме падает.
Украл (временно) XMLSpy — тоже ничего внятного не показывает.
А чем вы смотрите XML таких размеров?
1 — 20.11.21 — 19:05
Altova
2 — 20.11.21 — 19:36
notepad++
3 — 20.11.21 — 19:38
(2) ++
4 — 20.11.21 — 19:42
А что в них смотреть?
Посмотреть как выглядит можно и far-ом
5 — 20.11.21 — 19:45
тоже notepad++
6 — 20.11.21 — 19:49
(1) Altova XMLSpy? Я про него написал
(2) Он умеет сворачивать большие файлы?
7 — 20.11.21 — 19:49
(4) 50 МБ правил нужно пропустить. И ещё N объектов дальше тоже.
Нужно свернуть и смотреть конкретные записи
8 — 20.11.21 — 19:51
XMLPad
9 — 20.11.21 — 19:55
(8) Так это тот же IE. Он тупо сдохнет на таком файле
10 — 20.11.21 — 19:59
Vscode. Быстро и наглядно.
11 — 20.11.21 — 20:02
(10) лучше чем просто в хроме?
12 — 20.11.21 — 20:05
MySql не работает с XML как с базой данных ?
13 — 20.11.21 — 20:05
(10) Ещё раз. VSCode на таком объёме дохнет. В смысле — еёный (с) парсер.
(12) А причём тут мускул?
14 — 20.11.21 — 20:05
(11) Да, конечно. Но и машинка должна быть не Пентиум 3, как у Дениски.
15 — 20.11.21 — 20:06
https://softwarerecs.stackexchange.com/questions/77495/is-there-a-text-editor-that-can-open-big-xml-files
There are quite a few. The universal editors that can handle huge files are Emacs and XEmacs. They are both available for most platforms and I have been using those on Linux and Windows 10
16 — 20.11.21 — 20:08
EmEditor. Работает с очень большими файлами
17 — 20.11.21 — 20:15
(16) EmEditor платный, notepad++ умеет сворачивать
18 — 20.11.21 — 20:16
(0) Саблайм пробовал?
19 — 20.11.21 — 20:55
http://www.firstobject.com/dn_editor.htm
уж много лет пользуюсь, искать замену в голову не приходило ни разу…
20 — 20.11.21 — 21:57
для больших файлов (любых) пользую https://www.hhdsoftware.com/free-hex-editor
да, в нем разметки, зато можно редактировать реально большие файлы (лично редактировал около 5 гигов)….
21 — 20.11.21 — 22:02
AK XML Editor
22 — 20.11.21 — 22:03
(0) Да ничем, ФИАС-овский 30 Гб файл домов, например, нарезаю на файлы по 10 Мб самопальным сплиттером в директорию, потом поиск текста в этих файлах, ну и где текст нашелся браузером открываю.
23 — 20.11.21 — 22:07
Любая попытка загрузить большой файл ХМЛ в DOM падает в ошибку нехватки памяти. Только нарезка на мелкие файлы спасает.
24 — 20.11.21 — 22:31
(0) Любые большие тестовые файлы смотрю FAR.
25 — 20.11.21 — 22:35
Akelpad
26 — 20.11.21 — 22:40
300мб? Легко
firstobject
еще и удобный поиск
27 — 21.11.21 — 05:18
(24) И что, фар сворачивает элементы xml?
(25) тот же вопрос
28 — 21.11.21 — 05:19
(19) А вот это, похоже, подойдёт. Спасибо.
29 — 21.11.21 — 06:01
Если гигов 30, то ultraedit32
30 — 21.11.21 — 07:07
(29) Дяденька, а расскажите нам про мамонтов — их правда можно было стричь и они были выше человека?
31 — 21.11.21 — 07:30
Поддерживаю (19), лучше firstobject ничего не видел.
32 — 21.11.21 — 09:22
Вордпад.
33 — 21.11.21 — 09:25
(32) Ваш комментарий попадает в номинацию самых тупых, поздравляю!
34 — 21.11.21 — 10:04
(33) а ты попробуй
35 — 21.11.21 — 10:09
(34) rtf, doc, odt, txt
xml не вижу.
Если и откроет, то как текст. А мне нужно не это.
36 — 21.11.21 — 10:14
(35) открывает тяжёлые xml с любого компа влёт.
вопрос был «А чем вы смотрите XML таких размеров?»
37 — 21.11.21 — 10:14
(0) XML Explorer https://xmlexplorer.github.io — быстро открывает очень большие файлы, сворачивает, есть поиск, и вроде даже портабельный
38 — 21.11.21 — 10:16
Кстати, кто советовал Notepad++ — я конечно его очень ценю, но на больших XML он (notepad++) может надолго зависнуть — какой тогда в нём смысл? Для небольших файлов он конечно лучше всех.
39 — 21.11.21 — 10:17
(36) Если бы мне нужно было смотреть как plain — я взял бы far.
А так » парсер на этом объёме падает.» — нормальному человеку этого должно быть достаточно
40 — 21.11.21 — 10:34
очень долго время пользуюсь XML Notepad 2007
за гиговые файлы не скажу, не пробовал, но файлы на десятки и сотни мгбайт работает норм.
из забавного в одном обсуждении по поводу локализаций этой программки: «Автор этой программы — Chris Lovett, сотрудник (по кр.мере на тот момент 2006го года) компании Microsoft (Редмонд, штат Вашингтон, США). Программа Microsoft XML Notepad не получила локализацию ни на один язык, поскольку была предназначена для своих же разработчиков (которые, конечно, знают английский). Наружу она выложена не как «программный продукт», а как «полезняшка» без поддержки: т.е. хотите — пользуйтесь, хотите — нет, но претензии оставьте при себе.»
41 — 21.11.21 — 10:37
42 — 21.11.21 — 10:45
(0) свой парсер напиши аля SAX
43 — 21.11.21 — 12:07
(27) Нет, конечно.
Когда смотришь файл — нет смысла анализировать все данные. Обычно вопрос возникает по какому-то определенному полю. FARa для этого достаточно.
44 — 21.11.21 — 12:07
+43 Поправка: *Когда смотришь файл большого размера — ….
45 — 21.11.21 — 12:43
(43) Ты ошибаешься.
46 — 21.11.21 — 12:52
(0) Большие Far-ом. Не очень большие Notepad++.
(7) Выгрузить минимум данных для отладки лень-матушка не дает?
47 — 21.11.21 — 12:53
(46) Причём тут лень? Ошибка возникает только при полной выгрузке
48 — 21.11.21 — 12:55
(47) На каких именно данных ошибка, понятно?
49 — 21.11.21 — 13:31
Ради интереса попробовал на файле 1,2 гб — (37) и (41) открывают нормально, больше вроде ничего из предложенного не подходит.
50 — 21.11.21 — 16:07
если xml ~30 Гб, по крайней мере в рамках 1С, то это уже клиника
51 — 21.11.21 — 16:23
(42) а зачем писать свой, их уже написано как грязи. Но есть проблема. (0) от просмотрщика XML требуется сворачивать узлы, но когда вы парсите XML по методу SAX, вы не знаете, когда узел закончится. Он может быть и размером около всего файла. В результате разбивка на узлы и постепенное показывание файла оказывается нетривиальной задачей…
52 — 21.11.21 — 17:23
(30) дык к нему тоже есть плаггины для «удобного» просмотра xml, и сворачивает он там их.. и т.д
53 — 21.11.21 — 18:10
Между прочим, в конфигураторе можно открыть гигантский XML
54 — 21.11.21 — 18:46
(53) Неа, падает
55 — 21.11.21 — 19:27
(54) лично открывал под 4 гига файл. Правда конфигуратор оперативы сожрал over 10 Гб, несколько минут открывал, но открыл
56 — 21.11.21 — 19:40
(55) А, если как текст открывать, то да, открывает, но это неинтересно. Я думал он именно как xml может.
57 — 22.11.21 — 06:12
несколько гигов нотепад у меня отказался открывать
поставил Liquid studio, идеальная прога. быстро красиво в нескольких вариантах просмотра.
пишут что любого размера файлы открывает хоть в терабайты.
58 — 22.11.21 — 06:50
(57) и сколько это стоит? по мне notepad ++ и Far вполне хватает. нафейхуа дял этого целую студию покупать?
59 — 22.11.21 — 07:34
(37) поиск только XPath ?
Открыл (отформатировал) конечно быстро
60 — 22.11.21 — 09:15
(58) «Я старый пират, и не знаю слов лицензионного соглашения!» (с) ))
61 — 22.11.21 — 09:24
(0) тотал коммандер норм открывает большие файлы, 300мб это вообще ерунда
62 — 22.11.21 — 09:25
(61) точнее не он сам, а встроенный Far в нем.
63 — 22.11.21 — 09:25
(61) Да как же вы ТЗ-то читаете… (((
64 — 22.11.21 — 09:27
(62) far в total’е?
вы там совсем?
65 — 22.11.21 — 09:28
66 — 22.11.21 — 09:31
и да far хрень
total лучше
67 — 22.11.21 — 09:33
(0) firstobject xml editor
68 — 22.11.21 — 09:34
(66) денешек стоит. И не вполне понятно, что там принципиально такого, за что платить, в отличие от халявного фара.
69 — 22.11.21 — 09:41
(68) так сложно кнопочку 1, 2 или 3 при запуске нажать?
70 — 22.11.21 — 09:49
(42) «свой парсер напиши аля SAX» — Пожалуйста с исходным кодом — https://github.com/sikuda/bigxmlread
71 — 22.11.21 — 09:52
(70) Библиотека Qt. Читает первый уровень узлов, остальные по мере раскрытия, поиск работает.
А так конечно таким программ как грязи, выбирай на свой вкус.
72 — 22.11.21 — 09:55
+ к firstobject xml editor
73 — 22.11.21 — 09:59
Нотепад ++. Хорош.
74 — 22.11.21 — 11:56
(67) (73) (72) они же не открывают большие файлы
75 — 22.11.21 — 11:59
(74) firstobject открыл.
76 — 22.11.21 — 12:09
(75) Больше гига уже не открывает — пишет out of memory
77 — 22.11.21 — 12:34
(76) Ну тогда bigxmlreader.
mikecool
78 — 22.11.21 — 12:38
(76) у меня > гига никогда не было, значит есть проблема
но firstobject достаточно шустро работает с хмл
I need to parse and process an XML feed, unfortunately the feed is about 110mb in size (and i cannot do anything about it) but to be able to parse it i need to see the structure (or if anyone has any other ideas i’d love to hear it).
But for some reason using editplus i’ve been unable to open the file. I’m on a 64bit Vista Machine with 4gb of ram (And alot of it free for use) but the file crashes every program i try to open it with.
Anyone have any ideas of how i can parse blindly (server runs linux…) ?! (PHP please..!) or a program that might be able to resolve my problem?
Cheers
UPDATE
I have managed to find the problem but it was resolved by the answer i’ve accepted. It seemed to be that the XML file wasn’t just large but all on one line which seemed to break the line limit in most programs. The chosen answer textpad++ detected this and broke the file across different lines so that it can be viewed…(might help someone in the future!)
asked Dec 1, 2009 at 20:24
Shadi AlmosriShadi Almosri
11.6k16 gold badges57 silver badges79 bronze badges
1
THIS is the program you want. It’s the best I’ve seen anywhere and I regularly use it for large XML documents. It’s completely free, tiny and doesn’t require an install.
Damned genius, and nobody has ever heard of it!
XML Viewer 3.1
If that link doesn’t work, scroll down on this page until you find it:
http://www.mitec.cz/Data/XML/data_downloads.xml
answered May 27, 2010 at 18:44
Chuck Le ButtChuck Le Butt
47.1k61 gold badges199 silver badges286 bronze badges
I’ve never had trouble opening very large files in TextPad: http://www.textpad.com/
answered Dec 1, 2009 at 20:26
Zoran SimicZoran Simic
10.3k6 gold badges33 silver badges35 bronze badges
1
XmlReader
is a pull-parser. It maintains a cursor in the file and only reads in one element at a time. It’s a slightly different way to work with XML over DOM, but it performs well for large files.
Of course, if you just want to peek manually into the file, use less
or vim
for it.
answered Dec 1, 2009 at 21:01
troelskntroelskn
114k26 gold badges132 silver badges155 bronze badges
gVim can open extremely large files without trouble.
answered Dec 1, 2009 at 20:39
AmberAmber
500k82 gold badges622 silver badges548 bronze badges
XMLMax will open your 100MB file in a treeview in under 5 seconds and will handle any size or structure xml file. It also has a number of options to split it up for you. YOu mentioned wanting to see the structure: if you create an index, the index file, which is a plain text utf-8 file, has a list at the end of all the unique paths in the xml file.
answered Dec 2, 2009 at 1:28
bill seachambill seacham
3951 gold badge2 silver badges4 bronze badges
Since XML is just text, you could potentially split it into multiple smaller files, and examine each section individually to determine the structure of the XML inside. I’ve used these many times to split large files into manageable chinks for emailing and such (with 20MB limits, etc). I don’t know of any viewers that I can guarantee will open a 100MB+ XML file without crashing.
answered Dec 1, 2009 at 20:28
Nathan WheelerNathan Wheeler
5,8762 gold badges29 silver badges47 bronze badges
2
You have several options for this:
-
Notepad++ is my personal favourite for opening large files.
-
The V file viewer is pretty handy
-
Microsoft Log Parser is pretty good too, it is desgned to allow you to use SQL-like access to large text files including XML.
E.g. Select top 10 * from test.xml
-
You could install Cygwin then use the GNU utility ‘head’
-
You could use OPENROWSET to import the XML file into a SQL Server table
answered Dec 1, 2009 at 20:49
Jon WinstanleyJon Winstanley
22.8k21 gold badges73 silver badges115 bronze badges
IntelliJIDEA can open big files (read-only mode)
answered Feb 6 at 9:19
Zaur_MZaur_M
7373 gold badges11 silver badges18 bronze badges
12.11.2009
сайт автора: http://webi.ru
публикация данной статьи разрешена только со ссылкой на сайт автора статьи
В этой статье я покажу пример, как разобрать большой XML файл. Если на вашем сервере (хостинге) не запрещено увеличение времени работы скрипта, то можно разбирать XML файл весом хоть гигабайты, сам лично разбирал только файлы от озона весом 450 мегабайт.
При разборе больших XML файлов возникает две проблемы:
1. Не хватает памяти.
2. Не хватает выделенного времени для работы скрипта.
Вторую проблему с временем решить можно, если сервером это не запрещено.
А вот проблему с памятью решить сложно, даже если речь идет о своем сервере, то ворочать файлы по 500 мегабайт не очень просто а уж на хостинге и на VDS увеличить память просто не получится.
В PHP существует несколько встроенных вариантов обработки XML — SimpleXML, DOM, SAX.
Все эти варианты подробно описаны во многих статьях с примерами, но все примеры демонстрируют работу с полным XML документом.
Вот один из примеров, получаем объект из XML файла
<? $xml = simplexml_load_file("1.xml"); ?>
Теперь можно обрабатывать этот объект, НО…
Как видно, весь XML файл считывается в память, затем все разбирается в объект.
То есть все данные попадают в память и если выделенной памяти мало, то скрипт останавливается.
Для обработки больших файлов такой вариант не подходит, нужно читать файл построчно и обрабатывать эти данные по очереди.
При этом проверка на валидность осуществляется так же по мере обработки данных, поэтому нужно иметь возможность для отката, например удалить все внесенные в базу данные в случае не валидного XML файла, либо осуществить два прохода по файлу, сначала читать на валидность, затем читать для обработки данных.
Вот теоретический пример разбора большого XML файла.
Этот скрипт читает по одному символу из файла, собирает эти данные в блоки и отправляет в разборщик XML.
Такой подход полностью решает проблему с памятью и не вызывает нагрузки, но усугубляет проблему со временем. Как попытаться решить проблему со временем, читайте ниже.
<?function webi_xml($file)
{####################################################
### функция работы с данными
function data ($parser, $data)
{
print $data;
}
############################################
####################################################
### функция открывающих тегов
function startElement($parser, $name, $attrs)
{
print $name;
print_r($attrs);
}
###############################################
#################################################
## функция закрывающих тегов
function endElement($parser, $name)
{
print $name;
}
############################################$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);
}
webi_xml('1.xml');?>
В этом примере я все сложил в одну функцию webi_xml() и в самом низу видно ее вызов.
Сам скрипт состоит из трех основных функций:
1. Функция которая ловит открытие тега startElement()
2. Функция которая ловит закрытие тега endElement()
3. И функция получения данных data().
Предположим что содержимое файла 1.xml некий рецепт
<?xml version="1.0" encoding="windows-1251"?>
<recipe name="хлеб" preptime="5" cooktime="180">
<title>Простой хлеб</title>
<ingredient amount="3" unit="стакан">Мука</ingredient>
<ingredient amount="0.25" unit="грамм">Дрожжи</ingredient>
<ingredient amount="1.5" unit="стакан">Тёплая вода</ingredient>
<ingredient amount="1" unit="чайная ложка">Соль</ingredient>
<instructions>
<step>Смешать все ингредиенты и тщательно замесить.</step>
<step>Закрыть тканью и оставить на один час в тёплом помещении.</step>
<step>Замесить ещё раз, положить на противень и поставить в духовку.</step>
<step>Посетить сайт webi.ru</step>
</instructions>
</recipe>
Начинаем все с вызова общей функции 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 version=»1.0″ encoding=»windows-1251″?>
И отправит ее в разборщик
xml_parse($xml_parser, $data, feof($fp));
После обработки данных строковая переменная сбрасыватеся и снова начинается сбор данных в строку и во второй раз сформируется строка
<recipe name=»хлеб» preptime=»5″ cooktime=»180″>
В третий
<title>
в четвертый
Простой хлеб</title>
Обратите внимание, что строковая переменная всегда формируется по законченному тегу > и не обязательно посылать разбощику открытый и закрытый тег с данными например
<title>Простой хлеб</title>
Данному обработчику важно получить целый не разбитый тег, хоть один открытый, а в следущий шаг закрытый тег, или сразу получить 1000 строк файла, не важно, главное чтобы тег не разрывался, например
<tit
le>Простой хлеб
Так отправить данные обработчику нельзя, так как тег разорвался.
Вы можете придумать свою методику посылания данных в обработчик, например собирать по 1 мегабайту данных и отправлять в обработчик для повышения скорости, только следите чтобы теги всегда завершались, а данные можно разрывать
<title>Простой
хлеб</title>
Таким образом частями, как вы пожелаете можно отправить большой файл в обработчик.
Теперь рассмотрим каким образом эти данные обрабатываются и как их получить.
Начинаем с функции открывающих тегов startElement($parser, $name, $attrs)
Предположим, что обработка дошла до строки
<ingredient amount=«3» unit=«стакан»>Мука</ingredient>
Тогда внутри функции переменная $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)
{
// здесь начинается обработка данных, например добаление в базу, сохранение в файл и т.д.
// $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');?>
Весь пример сопроводил комментариями, теперь тестируйте и экспериментируйте.
Обратите внимание, в функции работы с данными в массив данные не просто вставляются, а именно добавляются с помощью «.=» так как данные могут поступать не в целом виде и если сделать просто присвоение, то время от времени вы будете получать данные кусками.
Ну вот и все, теперь при обработке файла любого размера памяти хватит, а вот время работы скрипта увеличить можно несколькими способами.
В начало скрипта вставьте функцию
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 на мастерхосте, но об этом не в этой статье.
Комментарии
RSS комментарии
13.11.2009 developer
проверил.
взял файл озона 450 мб с книгами.
и обработал его этим примером.
вставлял в базу данные минут 30, долго, но в итоге вставил…
28.02.2010 leksus.info
у меня хмл-файл на 25 гигов, вот думаю, сколько это времени займёт
Я так понимаю, если указать считываемые кусочки по 1мб, дело пойдёт быстрее?
01.03.2010 Админ
25 гигов это конечно круто.
если честно, не знаю что тут может ускорить процесс, надо экспериментировать.
разобрать конечно можно такой файл, но сколько часов это будет обрабатываться…
01.05.2010 Alex-Dnepr
PHP для разбора больших баз не очень-то подходит, причем — всего лишь в силу того, что сам процесс занимает очень много времени (450MB = 30мин. = 1800сек.), а, очень часто, настройки веб-сервера просто не позволяют его осуществить полностью из-за установленного лимита времени на работу php-скрипта (например стандартные для Апача 30сек.).
Такие вещи реально осуществлять на своем выделенном сервере (виртуальном либо реальном), так как появляется возможность изменения данного лимита времени исходя из своих потребностей.
Поэтому, в этом плане, парсер на базе perl — один из лучших вариантов.
P.S. Пробовал изменять размер куска на считывание — почти нулевое изменение производительности.
01.05.2010 админ
Alex-Dnepr, конечно, для подобных вещей perl более предпочтителен.
Скорость выполнение подобного разбора в perl должна быть быстрее, но не сильно уж быстрее.
Да и потом у perl по времени тоже существуют ограничения, такие же как в php.
02.05.2010 Alex-Dnepr
Как ни крути, но sax-парсер — медленный.
Для ускорения разбора больших баз можно попробовать использовать парсер, построенный, например на базе strpos() и substr().
02.05.2010 админ
Alex-Dnepr, на базе strpos() и substr() тоже можно, но будет ли быстрее… мне кажется, что не будет быстрее.
проверки и поиск символов по тексту создаст тоже не малую нагрузку.
Но это все уже тестировать надо.
Если прирост в скорости будет значительный, тогда наверное стоит обратить внимание на обработку строковыми функциями.
10.05.2010 Alex-Dnepr
Здравствйте, Admin.
Какая средняя скорость разбора больших XML файлов sax-парсером была зафиксирована Вами (размер файла/время обработки)?
11.05.2010 админ
Да вот тут я не отвечу. Я не проводил тестов на время.
Была задача сделать разбор файлов до 50 МБ на хостинге.
Естественно обычным способом разобрать не получалось, не хватало памяти.
А вот вариант описанный в этой статье подошел и укладывался в ресурсы хостинга, хватало и памяти и времени.
А вот сколько по времени длились разборы, я вот тут не засекал.
14.05.2010 Alex-Dnepr
Попробовал парсить XML-базу с помощью строковых функций — результат достаточно преемлемый.
По факту, разбор XML базы размером 500 Мб (только чтение — без записи в БД) с помощью SAX занял 460 сек, а строковыми функциями — 260 сек.
14.05.2010 админ
результат конечно впечатляет, почти в два раза быстрее.
но все ли вы учли? например разбор атрибутов предусмотрели?
может покажите этот пример(на почту), я его обработаю, потестирую и присоединю к этой статье.
15.05.2010 Alex-Dnepr
Как уже указывал — такие результаты были достигнуты в режиме <u>чтения</u> XML-базы — без учета затрат времени на работу с СУБД (например MySQL).
По факту, необходимость записи в базу данных — практически нивелирует относительную разницу в результатах работы парсеров.
П.С. Выделение атрибутов осуществляется и не ничем не отличается от процесса выделения значений, заключенных в теги.
По факту — это тот же sax, разница в том, что выделение тегов и атрибутов осуществляется с помощью строковых функций.
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’шном парсере… Но факт тот, что сейчас, судя по всему, пляски с поиском начала и конца тегов не нужны…
Читай хоть по одному символу — оно запоминает и парсит как надо:
while ($data = fread($fp, 1)) {
if (!xml_parse($xml_parser, $data, feof($fp))) {
* * * *
}
}
Добавить свой комментарий
На работе попросили провести исследование какими средствами лучше разбирать объёмный XML файл (более 100Mb). Предлагаю сообществу ознакомиться с результатами.
Рассмотрим основные методы работы с XML:
1. Simple XML (documentation)
2. DOM (documentation)
3. xml_parser (SAX) (documentation)
4. XMLReader (documentation)
Simple XML
Минусы: работает очень медленно, собирает весь файл в память, дерево составляется в отдельных массив.
Плюсы: простота работы, работа «из коробки» (требует библиотеки libxml которая включена практически на всех серверах)
Пример использования Simple XML
$xml = simplexml_load_file("price.xml");
echo "<table border='1'>n";
foreach ($xml->xpath('/DocumentElement/price') as $producs) { ?>
<tr>
<td><?php echo $producs->name; ?></td>
<td><?php echo $producs->company; ?></td>
<td><?php echo $producs->city; ?></td>
<td><?php echo $producs->amount ?></td>
</tr>
<?
}
echo "</table>n";
DOM
Минусы: работает очень медленно, как и все предыдущие примеры собирает весь файл в память.
Плюсы: На выходе привычный DOM с которым очень легко работать.
Пример использования DOM
$doc = new DOMDocument();
$doc->load( 'books.xml' );
$books = $doc->getElementsByTagName( "book" );
foreach( $books as $book )
{
$authors = $book->getElementsByTagName( "author" );
$author = $authors->item(0)->nodeValue;
$publishers = $book->getElementsByTagName( "publisher" );
$publisher = $publishers->item(0)->nodeValue;
$titles = $book->getElementsByTagName( "title" );
$title = $titles->item(0)->nodeValue;
echo "$title - $author - $publishern";
xml_parser и XMLReader.
Предыдущие 2 нам не подходят из-за работы с целым файлом, т.к. файлы у нас бывают по 20-30 Mb, и во время работы с ними некоторые блоки образуют цепочку (массив) в 100> Mb
Оба способа работают чтением файла построчно что подходит идеально для поставленной задачи.
Разница между xml_parser и XMLReader в том что, в первом случае вам нужно будет писать собственные функции которые будут реагировать на начало и конец тэга.
Проще говоря, xml_parser работает через 2 триггера – тэг открыт, тэг закрыт. Его не волнует что там идёт дальше, какие данные используются и т.д. Для работы вы задаёте 2 триггера указывающие на функции обработки.
Пример работы xml_parser
class Simple_Parser
{
var $parser;
var $error_code;
var $error_string;
var $current_line;
var $current_column;
var $data = array();
var $datas = array();
function parse($data)
{
$this->parser = xml_parser_create('UTF-8');
xml_set_object($this->parser, $this);
xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1);
xml_set_element_handler($this->parser, 'tag_open', 'tag_close');
xml_set_character_data_handler($this->parser, 'cdata');
if (!xml_parse($this->parser, $data))
{
$this->data = array();
$this->error_code = xml_get_error_code($this->parser);
$this->error_string = xml_error_string($this->error_code);
$this->current_line = xml_get_current_line_number($this->parser);
$this->current_column = xml_get_current_column_number($this->parser);
}
else
{
$this->data = $this->data['child'];
}
xml_parser_free($this->parser);
}
function tag_open($parser, $tag, $attribs)
{
$this->data['child'][$tag][] = array('data' => '', 'attribs' => $attribs, 'child' => array());
$this->datas[] =& $this->data;
$this->data =& $this->data['child'][$tag][count($this->data['child'][$tag])-1];
}
function cdata($parser, $cdata)
{
$this->data['data'] .= $cdata;
}
function tag_close($parser, $tag)
{
$this->data =& $this->datas[count($this->datas)-1];
array_pop($this->datas);
}
}
$xml_parser = new Simple_Parser;
$xml_parser->parse('<foo><bar>test</bar></foo>');
В XMLReader всё проще. Во первых, это класс. Все триггеры уже заданы константами (их всего 17), чтение осуществляется функцией read() которая читает первое вхождение подходящее под заданные триггеры. Далее мы получаем объект в который заносится тип данных (аля триггер), название тэга, его значение. Также XMLReader отлично работает с аттрибутами тэгов.
Пример использования XMLReader
<?php
<?php
Class StoreXMLReader
{
private $reader;
private $tag;
// if $ignoreDepth == 1 then will parse just first level, else parse 2th level too
private function parseBlock($name, $ignoreDepth = 1) {
if ($this->reader->name == $name && $this->reader->nodeType == XMLReader::ELEMENT) {
$result = array();
while (!($this->reader->name == $name && $this->reader->nodeType == XMLReader::END_ELEMENT)) {
//echo $this->reader->name. ' - '.$this->reader->nodeType." - ".$this->reader->depth."n";
switch ($this->reader->nodeType) {
case 1:
if ($this->reader->depth > 3 && !$ignoreDepth) {
$result[$nodeName] = (isset($result[$nodeName]) ? $result[$nodeName] : array());
while (!($this->reader->name == $nodeName && $this->reader->nodeType == XMLReader::END_ELEMENT)) {
$resultSubBlock = $this->parseBlock($this->reader->name, 1);
if (!empty($resultSubBlock))
$result[$nodeName][] = $resultSubBlock;
unset($resultSubBlock);
$this->reader->read();
}
}
$nodeName = $this->reader->name;
if ($this->reader->hasAttributes) {
$attributeCount = $this->reader->attributeCount;
for ($i = 0; $i < $attributeCount; $i++) {
$this->reader->moveToAttributeNo($i);
$result['attr'][$this->reader->name] = $this->reader->value;
}
$this->reader->moveToElement();
}
break;
case 3:
case 4:
$result[$nodeName] = $this->reader->value;
$this->reader->read();
break;
}
$this->reader->read();
}
return $result;
}
}
public function parse($filename) {
if (!$filename) return array();
$this->reader = new XMLReader();
$this->reader->open($filename);
// begin read XML
while ($this->reader->read()) {
if ($this->reader->name == 'store_categories') {
// while not found end tag read blocks
while (!($this->reader->name == 'store_categories' && $this->reader->nodeType == XMLReader::END_ELEMENT)) {
$store_category = $this->parseBlock('store_category');
/*
Do some code
*/
$this->reader->read();
}
$this->reader->read();
}
} // while
} // func
}
$xmlr = new StoreXMLReader();
$r = $xmlr->parse('example.xml');
Тест производительности
Код генератора example.xml
<?php
$xmlWriter = new XMLWriter();
$xmlWriter->openMemory();
$xmlWriter->startDocument('1.0', 'UTF-8');
$xmlWriter->startElement('shop');
for ($i=0; $i<=1000000; ++$i) {
$productId = uniqid();
$xmlWriter->startElement('product');
$xmlWriter->writeElement('id', $productId);
$xmlWriter->writeElement('name', 'Some product name. ID:' . $productId);
$xmlWriter->endElement();
// Flush XML in memory to file every 1000 iterations
if (0 == $i%1000) {
file_put_contents('example.xml', $xmlWriter->flush(true), FILE_APPEND);
}
}
$xmlWriter->endElement();
// Final flush to make sure we haven't missed anything
file_put_contents('example.xml', $xmlWriter->flush(true), FILE_APPEND);
Результаты тестирования (чтение без разбора данных)
Характеристики тестовой среды
Ubuntu 16.04.1 LTS
PHP 7.0.15
Intel® Core(TM) i5-3550 CPU @ 3.30GHz, 16 Gb RAM, 256 SSD
Метод | Время выполнения (19 Mb) | Время выполнения (190 Mb) |
---|---|---|
Simple XML | 0.46 сек | 4.56 сек |
DOM | 0.52 сек | 4.09 сек |
xml_parse | 0.22 сек | 2.25 сек |
XML Reader | 0.26 сек | 2.18 сек |
P.S. Советы и комментарии с удовольствием выслушаю. Прошу сильно не пинать
Существуют ли программы способные отображать большие (гигабайт и больше) XML-файлы? Желательно конечно с возможностью применения XSLT
задан 1 фев 2011 в 15:17
3
Боюсь только утилиты вроде less могут открывать такие файлы для просмотра..
Что же до преобразования, то попробуйте saxon с какими-нибудь жуткими параметрами запуска, чтобы памяти хватило.
ответ дан 1 фев 2011 в 15:33
cy6erGn0mcy6erGn0m
19.7k1 золотой знак31 серебряный знак38 бронзовых знаков
Парсить:
http://sax.sourceforge.net/
Посмотреть можно, например через cat:
cat filename |more
Под виндами я полагаю, что через far
ответ дан 1 фев 2011 в 15:31
Alex SilaevAlex Silaev
4,0421 золотой знак16 серебряных знаков26 бронзовых знаков
Notepad2
ответ дан 1 фев 2011 в 18:00
СергейСергей
3,3223 золотых знака28 серебряных знаков56 бронзовых знаков
За последние 24 часа нас посетили 13748 программистов и 949 роботов. Сейчас ищут 476 программистов …
Страница 1 из 2
-
Мне нужно спарсить большие XML файлы размером от ~ 500 до ~ 1700 мб.
Собственно я и юзаю XMLReader
-
include_once ‘inc/Misc.php’;
-
include_once ‘inc/Database.php’;
-
$files = array(‘xml/large_file.xml’);
-
foreach($files as $file) {
-
echo ‘Filesize: ‘.convert(filesize($file)).«n«;
-
echo ‘Start parsing…’.«n«;
-
$reader = new XMLReader();
-
while ($reader->read()) {
-
switch ($reader->nodeType) {
-
case (XMLREADER::ELEMENT):
-
if ($reader->localName == «element-name») {
-
$dom = new DomDocument();
-
$n = $dom->importNode($reader->expand(),true);
-
$tess->file_big->insert($sxe);
-
echo «Insert done! «; benchmark();
все нормально сначала… парсится потихоньку файл и вставляются нужные мне данные, но постепенно растет потребление памяти и пока не заканчиваются ресурсы только парсится. То есть я взял файл на 400 метров и пока его парсило то израсходовало 2000 метров оперативки и все ресурсы кончились и скрипт остановился.
Как быть с большими файлами ? ~ 500 до ~ 1700 мб. поможет ли тут XML Parser ? да и как им нормально парсить то что мне надо как в моем скрипте выше, примеров толковых нет… Еще варианты может есть ?
-
-
Gromo
Активный пользователь- С нами с:
- 24 май 2010
- Сообщения:
- 2.786
- Симпатии:
- 2
- Адрес:
- Ташкент
Awilum
решение «в лоб» — загонять файл в базу для более удобной работы, построчно считывая файл в память и обрабатывая каждую строку отдельно — грубо говоря, писать собственный парсер для большого файла.Держать в памяти 2 Гб файл XML в виде объектной структуры — это нереально.
-
Psih
Активный пользовательКоманда форума
МодераторПоскольку сам по себе парсинг работает, то явно всё в память не грузится. Насколько я знаю XMLReader потоковый.
Проблема в том, что в таких случаях надо забочитстя об очисте памяти, т.е. делать unset переменным, которые больше не нужны.
Ну и желательно использовать PHP 5.3+ в включённым сборщиком мусора. -
дело в том что у меня могут повторяться названия элементов и количество как оказалось тоже вот например
-
<party-name>Guess? IP Holder L.P.</party-name>
-
<postcode>90021</postcode>
и сработает только один флажок state
-
-
Psih
Активный пользовательКоманда форума
МодераторС SAX парсером не подскажу — я с ним работал, но давненько. А вот XMLReader скрипт вполне есть куда улучшить.
-
// Try to enable garbage collection on 5.3+
-
include_once ‘inc/Misc.php’;
-
include_once ‘inc/Database.php’;
-
$files = array(‘xml/large_file.xml’);
-
foreach($files as $file) {
-
echo ‘Filesize: ‘.convert(filesize($file)).«n«;
-
echo ‘Start parsing…’.«n«;
-
$reader = new XMLReader();
-
while ($reader->read()) {
-
switch ($reader->nodeType) {
-
case (XMLREADER::ELEMENT):
-
if ($reader->localName == «element-name») {
-
$dom = new DomDocument();
-
$n = $dom->importNode($reader->expand(),true);
-
* Database insert? What is $tess and what’s inside it?
-
$tess->file_big->insert($sxe);
-
echo «Insert done! «; benchmark();
-
// Delete the object to free memory
-
-
да это mongoDB почему то течет. уже сделал и так, но все равно течет с каждой вставкой
-
case (XMLREADER::ELEMENT):
-
if ($reader->localName == «case-file») {
-
$dom = new DomDocument();
-
$n = $dom->importNode($reader->expand(),true);
-
$sxe = simplexml_import_dom($n);
-
* Database insert? What is $tess and what’s inside it?
-
//$tess->file_big->insert($sxe);
-
$tess = $mongo->selectDB(‘tess’);
-
$tess->file_big->insert($sxe);
-
echo «Insert done! «; benchmark();
-
unset($n, $dom, $sxe, $mongo, $tess);
-
-
хотя в варианте с САКСОМ такой утечки не наблюдаю. а тут прям с каждой вставкой оперативка отжирается.
без этого
$mongo = new Mongo();
$tess = $mongo->selectDB(‘tess’);
$tess->file_big->insert($sxe);норм а с этой вставкой сильно жрутся ресурсы и не очищаются.
-
Psih
Активный пользовательКоманда форума
МодераторAwilum
А вы забываете закрыть соединение с MongoDB — ресурс то кушается с каждым новым объектом. Бережнее надо, бережнее. -
-
case (XMLREADER::ELEMENT):
-
if ($reader->localName == «case-file») {
-
$dom = new DomDocument();
-
$n = $dom->importNode($reader->expand(),true);
-
$sxe = simplexml_import_dom($n);
-
* Database insert? What is $tess and what’s inside it?
-
//$tess->file_big->insert($sxe);
-
$tess = $mongo->selectDB(‘tess’);
-
$tess->file_big->insert($sxe);
-
echo «Insert done! «; benchmark();
-
unset($n, $dom, $sxe, $mongo, $tess);
потребление памяти все растет с каждой вставкой. тут уже и unset и close есть.
-
-
Psih
Активный пользовательКоманда форума
МодераторAwilum
Могу покопаться на досуге, но нужен приличный XML файл и скрипт, которым вы его парсите. Только тестировать буду на PHP 5.3 а не 5.2 (под 7-ку нету нормальных толковых версий 5.2). У 5.2 есть проблемы с памятью и их решить нереально иногда. -
Psih
Активный пользовательКоманда форума
МодераторВы мне, пожайлуста, перешлите всё же все файлы скрипта — Misc.php, Database.php — может проблема утечек вообще где-то в них. Тут нужно всё пересматривать, а не отдельные части
Эх, надо будет ещё MongoDB поставить себе…
-
утром тестил в холостую без вставки ничего не жрало, а со вставкой жрало. Щас чего то пофиг как: и так и так жрет зараза (что в холостую что со вставкой) жесть какая та.
-
Database.php и Misc.php можно не брать во внимание оно и без них жрет
Database.php
-
$tess = $mongo->selectDB(‘tess’);
Misc.php
-
* Convert bytes in ‘kb’,’mb’,’gb’,’tb’,’pb’
-
* @param integer $size Data to convert
-
function convert($size) {
-
$unit=array(‘b’,’kb’,’mb’,’gb’,’tb’,’pb’);
-
return @round($size/pow(1024,($i=floor(log($size,1024)))),2).’ ‘.$unit[$i];
-
* @param boolean $render Displays the result of the function in the browser or not
-
function getMemoryUsage($render=true) {
-
if (function_exists(‘memory_get_usage’)) {
-
$memory_usage = memory_get_usage();
-
} else if (substr(PHP_OS,0,3) == ‘WIN’) {
-
// Windows 2000 workaround
-
exec(‘pslist ‘ . getmypid() , $output);
-
$memory_usage = trim(substr($output[8],38,10));
-
printf(‘Memory usage: ‘.convert($memory_usage));
-
* @global integer $start_time Start time value
-
* @param boolean $render Displays the result of the function in the browser or not
-
function getElapsedTime($render=true) {
-
$result_time = microtime(true) — $start_time;
-
if($render) printf(«Elapsed time %.3f seconds»,$result_time); else return sprintf(«%.3f», $result_time);
-
getMemoryUsage(); echo » — «; getElapsedTime(); echo «n»;
-
// Try to enable garbage collection on 5.3+
-
if (function_exists(‘gc_enable’) && !gc_enabled()) {
-
$files = array(‘xml/apc101231-42.xml’);
-
foreach($files as $file) {
-
echo ‘Filename: ‘.basename($file).»n»;
-
//echo ‘Filesize: ‘.convert(filesize($file)).»n»;
-
echo ‘Start parsing…’.»n»;
-
$reader = new XMLReader();
-
while ($reader->read()) {
-
switch ($reader->nodeType) {
-
case (XMLREADER::ELEMENT):
-
if ($reader->localName == «case-file») {
-
$dom = new DomDocument();
-
$n = $dom->importNode($reader->expand(),true);
-
$sxe = simplexml_import_dom($n);
-
$tess = $mongo->selectDB(‘tess’);
-
$tess->file_big->insert($sxe);
-
//unset($n, $dom, $sxe, $mongo, $tess);
-
// Delete the object to free memory
-
-
$reader->open($file,’LIBXML_PARSEHUGE’);
потребление памяти растет.
-
Psih
Активный пользовательКоманда форума
МодераторAwilum
Эээ, ну вы хоть читайте мануал и параметры для функций то…$reader->open($file, null, LIBXML_PARSEHUGE);
либо как советуют в комментах к XMLReader::read():
$xmlreader->open($uri, null, 1<<19);
-
$reader->open($file, null, ‘LIBXML_PARSEHUGE’);
Warning: XMLReader:pen() expects parameter 3 to be long$reader->open($file, null, LIBXML_PARSEHUGE);
Notice: Use of undefined constant LIBXML_PARSEHUGE — assumed ‘LIBXML_PARSEHUGE’ -
-
while ($reader->read()) {
а это место течь не может ? потому что больше некуда смотреть, так как что в холостую что нет одинаково.
прологировал
-
while ($reader->read()) {
-
switch ($reader->nodeType) {
-
case (XMLREADER::ELEMENT):
-
if ($reader->localName == «case-file») {
-
logAdd(‘case-file found’);
-
$dom = new DomDocument();
-
$n = $dom->importNode($reader->expand(),true);
-
$sxe = simplexml_import_dom($n);
-
logAdd(‘case-file in $sxe’);
-
$mongo->$db->$collection->insert($sxe);
-
logAdd(‘Clear the memory’);
не вижу ни каких проблем, но процесс расходует память.
-
-
я уже и так сделал. но все равно у процесса растет память! жесть. то ли действительно этот ридер копит весь файл и по этому потребление растет.
-
$start_time = microtime(true);
-
// Try to enable garbage collection on 5.3+
-
if (function_exists(‘gc_enable’) && !gc_enabled()) {
-
$files = array(/*’xml/apc101231-42.xml’,*/
-
foreach($files as $file) {
-
echo ‘Filename: ‘.basename($file).»n»;
-
echo ‘Start parsing…’.»n»;
-
$reader = new XMLReader();
-
if(!($fp = fopen($file, «r»)));
-
while ($data = fread($fp, 4096)) {
-
//while ($reader->read()) {
-
switch ($reader->nodeType) {
-
case (XMLREADER::ELEMENT):
-
if ($reader->localName == «case-file») {
-
logAdd(‘case-file found’);
-
$dom = new DomDocument();
-
$n = $dom->importNode($reader->expand(),true);
-
$sxe = simplexml_import_dom($n);
-
logAdd(‘case-file in $sxe’);
-
//$mongo->$db->$collection->insert($sxe);
-
logAdd(‘Clear the memory’);
-
// Delete the object to free memory
-
-
Psih
Активный пользовательКоманда форума
МодераторAwilum
Сегодня будет вечером время, попробую разобраться. Но если память так и кушаться будет — надо будет смотреть базу багов PHP и репортить, если такового нету. -
Скачал исходник php что бы посмотреть как же все такие устроен этот ридер.
$Id: php_xmlreader.c 306939 2011-01-01 02:19:59Z felipe $
-
#include «ext/standard/info.h»
-
#include «php_xmlreader.h»
-
#include «ext/dom/xml_common.h»
-
zend_class_entry *xmlreader_class_entry;
-
static zend_object_handlers xmlreader_object_handlers;
-
static HashTable xmlreader_prop_handlers;
-
typedef int (*xmlreader_read_int_t)(xmlTextReaderPtr reader);
-
typedef unsigned char *(*xmlreader_read_char_t)(xmlTextReaderPtr reader);
-
typedef const unsigned char *(*xmlreader_read_const_char_t)(xmlTextReaderPtr reader);
-
typedef int (*xmlreader_write_t)(xmlreader_object *obj, zval *newval TSRMLS_DC);
-
typedef unsigned char *(*xmlreader_read_one_char_t)(xmlTextReaderPtr reader, const unsigned char *);
-
typedef struct _xmlreader_prop_handler {
-
xmlreader_read_int_t read_int_func;
-
xmlreader_read_const_char_t read_char_func;
-
xmlreader_write_t write_func;
-
} xmlreader_prop_handler;
-
#define XMLREADER_LOAD_STRING 0
-
#define XMLREADER_LOAD_FILE 1
-
/* {{{ xmlreader_register_prop_handler */
-
static void xmlreader_register_prop_handler(HashTable *prop_handler, char *name, xmlreader_read_int_t read_int_func, xmlreader_read_const_char_t read_char_func, int rettype TSRMLS_DC)
-
xmlreader_prop_handler hnd;
-
hnd.read_char_func = read_char_func;
-
hnd.read_int_func = read_int_func;
-
zend_hash_add(prop_handler, name, strlen(name)+1, &hnd, sizeof(xmlreader_prop_handler), NULL);
-
/* {{{ xmlreader_property_reader */
-
static int xmlreader_property_reader(xmlreader_object *obj, xmlreader_prop_handler *hnd, zval **retval TSRMLS_DC)
-
const xmlChar *retchar = NULL;
-
if (hnd->read_char_func) {
-
retchar = hnd->read_char_func(obj->ptr);
-
if (hnd->read_int_func) {
-
retint = hnd->read_int_func(obj->ptr);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Internal libxml error returned»);
-
ZVAL_STRING(*retval, (char *) retchar, 1);
-
ZVAL_EMPTY_STRING(*retval);
-
ZVAL_BOOL(*retval, retint);
-
ZVAL_LONG(*retval, retint);
-
/* {{{ xmlreader_get_property_ptr_ptr */
-
zval **xmlreader_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC)
-
xmlreader_prop_handler *hnd;
-
zend_object_handlers *std_hnd;
-
if (member->type != IS_STRING) {
-
zval_copy_ctor(&tmp_member);
-
convert_to_string(&tmp_member);
-
obj = (xmlreader_object *)zend_objects_get_address(object TSRMLS_CC);
-
if (obj->prop_handler != NULL) {
-
ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
-
std_hnd = zend_get_std_object_handlers();
-
retval = std_hnd->get_property_ptr_ptr(object, member TSRMLS_CC);
-
if (member == &tmp_member) {
-
/* {{{ xmlreader_read_property */
-
zval *xmlreader_read_property(zval *object, zval *member, int type TSRMLS_DC)
-
xmlreader_prop_handler *hnd;
-
zend_object_handlers *std_hnd;
-
if (member->type != IS_STRING) {
-
zval_copy_ctor(&tmp_member);
-
convert_to_string(&tmp_member);
-
obj = (xmlreader_object *)zend_objects_get_address(object TSRMLS_CC);
-
if (obj->prop_handler != NULL) {
-
ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
-
ret = xmlreader_property_reader(obj, hnd, &retval TSRMLS_CC);
-
/* ensure we’re creating a temporary variable */
-
Z_SET_REFCOUNT_P(retval, 0);
-
retval = EG(uninitialized_zval_ptr);
-
std_hnd = zend_get_std_object_handlers();
-
retval = std_hnd->read_property(object, member, type TSRMLS_CC);
-
if (member == &tmp_member) {
-
/* {{{ xmlreader_write_property */
-
void xmlreader_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
-
xmlreader_prop_handler *hnd;
-
zend_object_handlers *std_hnd;
-
if (member->type != IS_STRING) {
-
zval_copy_ctor(&tmp_member);
-
convert_to_string(&tmp_member);
-
obj = (xmlreader_object *)zend_objects_get_address(object TSRMLS_CC);
-
if (obj->prop_handler != NULL) {
-
ret = zend_hash_find((HashTable *)obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Cannot write to read-only property»);
-
std_hnd = zend_get_std_object_handlers();
-
std_hnd->write_property(object, member, value TSRMLS_CC);
-
if (member == &tmp_member) {
-
/* {{{ _xmlreader_get_valid_file_path */
-
/* _xmlreader_get_valid_file_path and _xmlreader_get_relaxNG should be made a
-
common function in libxml extension as code is common to a few xml extensions */
-
char *_xmlreader_get_valid_file_path(char *source, char *resolved_path, int resolved_path_len TSRMLS_DC) {
-
escsource = xmlURIEscapeStr((xmlChar *)source, (xmlChar *)»:»);
-
xmlParseURIReference(uri, (const char *)escsource);
-
if (uri->scheme != NULL) {
-
/* absolute file uris — libxml only supports localhost or empty host */
-
if (strncasecmp(source, «file:///»,8) == 0) {
-
} else if (strncasecmp(source, «file://localhost/»,17) == 0) {
-
if ((uri->scheme == NULL || isFileUri)) {
-
if (!VCWD_REALPATH(source, resolved_path) && !expand_filepath(source, resolved_path TSRMLS_CC)) {
-
file_dest = resolved_path;
-
#ifdef LIBXML_SCHEMAS_ENABLED
-
/* {{{ _xmlreader_get_relaxNG */
-
static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, int source_len, int type,
-
xmlRelaxNGValidityErrorFunc error_func,
-
xmlRelaxNGValidityWarningFunc warn_func TSRMLS_DC)
-
xmlRelaxNGParserCtxtPtr parser = NULL;
-
char resolved_path[MAXPATHLEN + 1];
-
case XMLREADER_LOAD_FILE:
-
valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC);
-
parser = xmlRelaxNGNewParserCtxt(valid_file);
-
case XMLREADER_LOAD_STRING:
-
parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
-
/* If loading from memory, we need to set the base directory for the document
-
but it is not apparent how to do that for schema’s */
-
if (error_func || warn_func) {
-
xmlRelaxNGSetParserErrors(parser,
-
(xmlRelaxNGValidityErrorFunc) error_func,
-
(xmlRelaxNGValidityWarningFunc) warn_func,
-
sptr = xmlRelaxNGParse(parser);
-
xmlRelaxNGFreeParserCtxt(parser);
-
static const zend_module_dep xmlreader_deps[] = {
-
ZEND_MOD_REQUIRED(«libxml»)
-
/* {{{ xmlreader_module_entry
-
zend_module_entry xmlreader_module_entry = {
-
STANDARD_MODULE_HEADER_EX, NULL,
-
PHP_MSHUTDOWN(xmlreader),
-
«0.1», /* Replace with version number for your extension */
-
STANDARD_MODULE_PROPERTIES
-
#ifdef COMPILE_DL_XMLREADER
-
ZEND_GET_MODULE(xmlreader)
-
/* {{{ xmlreader_objects_clone */
-
void xmlreader_objects_clone(void *object, void **object_clone TSRMLS_DC)
-
/* {{{ xmlreader_free_resources */
-
static void xmlreader_free_resources(xmlreader_object *intern) {
-
xmlFreeParserInputBuffer(intern->input);
-
xmlFreeTextReader(intern->ptr);
-
#ifdef LIBXML_SCHEMAS_ENABLED
-
xmlRelaxNGFree((xmlRelaxNGPtr) intern->schema);
-
/* {{{ xmlreader_objects_free_storage */
-
void xmlreader_objects_free_storage(void *object TSRMLS_DC)
-
xmlreader_object *intern = (xmlreader_object *)object;
-
zend_object_std_dtor(&intern->std TSRMLS_CC);
-
xmlreader_free_resources(intern);
-
/* {{{ xmlreader_objects_new */
-
zend_object_value xmlreader_objects_new(zend_class_entry *class_type TSRMLS_DC)
-
zend_object_value retval;
-
xmlreader_object *intern;
-
intern = emalloc(sizeof(xmlreader_object));
-
memset(&intern->std, 0, sizeof(zend_object));
-
intern->prop_handler = &xmlreader_prop_handlers;
-
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
-
zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
-
retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) xmlreader_objects_free_storage, xmlreader_objects_clone TSRMLS_CC);
-
intern->handle = retval.handle;
-
retval.handlers = &xmlreader_object_handlers;
-
/* {{{ php_xmlreader_string_arg */
-
static void php_xmlreader_string_arg(INTERNAL_FUNCTION_PARAMETERS, xmlreader_read_one_char_t internal_function) {
-
xmlreader_object *intern;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «s», &name, &name_len) == FAILURE) {
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Argument cannot be an empty string»);
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retchar = (char *)internal_function(intern->ptr, (const unsigned char *)name);
-
RETVAL_STRING(retchar, 1);
-
/* {{{ php_xmlreader_no_arg */
-
static void php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAMETERS, xmlreader_read_int_t internal_function) {
-
xmlreader_object *intern;
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retval = internal_function(intern->ptr);
-
#if LIBXML_VERSION >= 20620
-
/* {{{ php_xmlreader_no_arg_string */
-
static void php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAMETERS, xmlreader_read_char_t internal_function) {
-
xmlreader_object *intern;
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retchar = (char *)internal_function(intern->ptr);
-
RETVAL_STRING(retchar, 1);
-
/* {{{ php_xmlreader_set_relaxng_schema */
-
static void php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAMETERS, int type) {
-
#ifdef LIBXML_SCHEMAS_ENABLED
-
int source_len = 0, retval = -1;
-
xmlreader_object *intern;
-
xmlRelaxNGPtr schema = NULL;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «s!», &source, &source_len) == FAILURE) {
-
if (source != NULL && !source_len) {
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Schema data source is required»);
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
schema = _xmlreader_get_relaxNG(source, source_len, type, NULL, NULL TSRMLS_CC);
-
retval = xmlTextReaderRelaxNGSetSchema(intern->ptr, schema);
-
/* unset the associated relaxNG context and schema if one exists */
-
retval = xmlTextReaderRelaxNGSetSchema(intern->ptr, NULL);
-
xmlRelaxNGFree((xmlRelaxNGPtr) intern->schema);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Unable to set schema. This must be set prior to reading or schema contains errors.»);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «No Schema support built into libxml.»);
-
/* {{{ proto boolean XMLReader::close()
-
Closes xmlreader — current frees resources until xmlTextReaderClose is fixed in libxml */
-
PHP_METHOD(xmlreader, close)
-
xmlreader_object *intern;
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
/* libxml is segfaulting in versions up to 2.6.8 using xmlTextReaderClose so for
-
now we will free the whole reader when close is called as it would get rebuilt on
-
xmlreader_free_resources(intern);
-
/* {{{ proto string XMLReader::getAttribute(string name)
-
Get value of an attribute from current element */
-
PHP_METHOD(xmlreader, getAttribute)
-
php_xmlreader_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderGetAttribute);
-
/* {{{ proto string XMLReader::getAttributeNo(int index)
-
Get value of an attribute at index from current element */
-
PHP_METHOD(xmlreader, getAttributeNo)
-
xmlreader_object *intern;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «l», &attr_pos) == FAILURE) {
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retchar = (char *)xmlTextReaderGetAttributeNo(intern->ptr, attr_pos);
-
RETVAL_STRING(retchar, 1);
-
/* {{{ proto string XMLReader::getAttributeNs(string name, string namespaceURI)
-
Get value of a attribute via name and namespace from current element */
-
PHP_METHOD(xmlreader, getAttributeNs)
-
int name_len = 0, ns_uri_len = 0;
-
xmlreader_object *intern;
-
char *name, *ns_uri, *retchar = NULL;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «ss», &name, &name_len, &ns_uri, &ns_uri_len) == FAILURE) {
-
if (name_len == 0 || ns_uri_len == 0) {
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Attribute Name and Namespace URI cannot be empty»);
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retchar = (char *)xmlTextReaderGetAttributeNs(intern->ptr, (xmlChar *)name, (xmlChar *)ns_uri);
-
RETVAL_STRING(retchar, 1);
-
/* {{{ proto boolean XMLReader::getParserProperty(int property)
-
Indicates whether given property (one of the parser option constants) is set or not on parser */
-
PHP_METHOD(xmlreader, getParserProperty)
-
xmlreader_object *intern;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «l», &property) == FAILURE) {
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retval = xmlTextReaderGetParserProp(intern->ptr,property);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Invalid parser property»);
-
/* {{{ proto boolean XMLReader::isValid()
-
Returns boolean indicating if parsed document is valid or not.
-
Must set XMLREADER_LOADDTD or XMLREADER_VALIDATE parser option prior to the first call to read
-
or this method will always return FALSE */
-
PHP_METHOD(xmlreader, isValid)
-
php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderIsValid);
-
/* {{{ proto string XMLReader::lookupNamespace(string prefix)
-
Return namespaceURI for associated prefix on current node */
-
PHP_METHOD(xmlreader, lookupNamespace)
-
php_xmlreader_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderLookupNamespace);
-
/* {{{ proto boolean XMLReader::moveToAttribute(string name)
-
Positions reader at specified attribute — Returns TRUE on success and FALSE on failure */
-
PHP_METHOD(xmlreader, moveToAttribute)
-
int name_len = 0, retval;
-
xmlreader_object *intern;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «s», &name, &name_len) == FAILURE) {
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Attribute Name is required»);
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retval = xmlTextReaderMoveToAttribute(intern->ptr, (xmlChar *)name);
-
/* {{{ proto boolean XMLReader::moveToAttributeNo(int index)
-
Positions reader at attribute at spcecified index.
-
Returns TRUE on success and FALSE on failure */
-
PHP_METHOD(xmlreader, moveToAttributeNo)
-
xmlreader_object *intern;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «l», &attr_pos) == FAILURE) {
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retval = xmlTextReaderMoveToAttributeNo(intern->ptr, attr_pos);
-
/* {{{ proto boolean XMLReader::moveToAttributeNs(string name, string namespaceURI)
-
Positions reader at attribute spcified by name and namespaceURI.
-
Returns TRUE on success and FALSE on failure */
-
PHP_METHOD(xmlreader, moveToAttributeNs)
-
int name_len=0, ns_uri_len=0, retval;
-
xmlreader_object *intern;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «ss», &name, &name_len, &ns_uri, &ns_uri_len) == FAILURE) {
-
if (name_len == 0 || ns_uri_len == 0) {
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Attribute Name and Namespace URI cannot be empty»);
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retval = xmlTextReaderMoveToAttributeNs(intern->ptr, (xmlChar *)name, (xmlChar *)ns_uri);
-
/* {{{ proto boolean XMLReader::moveToElement()
-
Moves the position of the current instance to the node that contains the current Attribute node. */
-
PHP_METHOD(xmlreader, moveToElement)
-
php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderMoveToElement);
-
/* {{{ proto boolean XMLReader::moveToFirstAttribute()
-
Moves the position of the current instance to the first attribute associated with the current node. */
-
PHP_METHOD(xmlreader, moveToFirstAttribute)
-
php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderMoveToFirstAttribute);
-
/* {{{ proto boolean XMLReader::moveToNextAttribute()
-
Moves the position of the current instance to the next attribute associated with the current node. */
-
PHP_METHOD(xmlreader, moveToNextAttribute)
-
php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderMoveToNextAttribute);
-
/* {{{ proto boolean XMLReader::read()
-
Moves the position of the current instance to the next node in the stream. */
-
PHP_METHOD(xmlreader, read)
-
xmlreader_object *intern;
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern != NULL && intern->ptr != NULL) {
-
retval = xmlTextReaderRead(intern->ptr);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «An Error Occured while reading»);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Load Data before trying to read»);
-
/* {{{ proto boolean XMLReader::next([string localname])
-
Moves the position of the current instance to the next node in the stream. */
-
PHP_METHOD(xmlreader, next)
-
xmlreader_object *intern;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «|s», &name, &name_len) == FAILURE) {
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern != NULL && intern->ptr != NULL) {
-
#if LIBXML_VERSION <= 20617
-
/* Bug in libxml prevents a next in certain cases when positioned on end of element */
-
if (xmlTextReaderNodeType(intern->ptr) == XML_READER_TYPE_END_ELEMENT) {
-
retval = xmlTextReaderRead(intern->ptr);
-
retval = xmlTextReaderNext(intern->ptr);
-
while (name != NULL && retval == 1) {
-
if (xmlStrEqual(xmlTextReaderConstLocalName(intern->ptr), (xmlChar *)name)) {
-
retval = xmlTextReaderNext(intern->ptr);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «An Error Occured while reading»);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Load Data before trying to read»);
-
/* {{{ proto boolean XMLReader::open(string URI [, string encoding [, int options]])
-
Sets the URI that the the XMLReader will parse. */
-
PHP_METHOD(xmlreader, open)
-
int source_len = 0, encoding_len = 0;
-
xmlreader_object *intern = NULL;
-
char *source, *valid_file = NULL;
-
char resolved_path[MAXPATHLEN + 1];
-
xmlTextReaderPtr reader = NULL;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «s|s!l», &source, &source_len, &encoding, &encoding_len, &options) == FAILURE) {
-
if (! instanceof_function(Z_OBJCE_P(id), xmlreader_class_entry TSRMLS_CC)) {
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
xmlreader_free_resources(intern);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Empty string supplied as input»);
-
valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC);
-
reader = xmlReaderForFile(valid_file, encoding, options);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Unable to open source data»);
-
object_init_ex(return_value, xmlreader_class_entry);
-
intern = (xmlreader_object *)zend_objects_get_address(return_value TSRMLS_CC);
-
/* Not Yet Implemented in libxml — functions exist just not coded
-
PHP_METHOD(xmlreader, resetState)
-
#if LIBXML_VERSION >= 20620
-
/* {{{ proto string XMLReader::readInnerXml()
-
Reads the contents of the current node, including child nodes and markup. */
-
PHP_METHOD(xmlreader, readInnerXml)
-
php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderReadInnerXml);
-
/* {{{ proto boolean XMLReader::readOuterXml()
-
Reads the contents of the current node, including child nodes and markup. */
-
PHP_METHOD(xmlreader, readOuterXml)
-
php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderReadOuterXml);
-
/* {{{ proto boolean XMLReader::readString()
-
Reads the contents of an element or a text node as a string. */
-
PHP_METHOD(xmlreader, readString)
-
php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderReadString);
-
/* {{{ proto boolean XMLReader::setSchema(string filename)
-
Use W3C XSD schema to validate the document as it is processed. Activation is only possible before the first Read(). */
-
PHP_METHOD(xmlreader, setSchema)
-
#ifdef LIBXML_SCHEMAS_ENABLED
-
int source_len = 0, retval = -1;
-
xmlreader_object *intern;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «s!», &source, &source_len) == FAILURE) {
-
if (source != NULL && !source_len) {
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Schema data source is required»);
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retval = xmlTextReaderSchemaValidate(intern->ptr, source);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Unable to set schema. This must be set prior to reading or schema contains errors.»);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «No Schema support built into libxml.»);
-
/* {{{ proto boolean XMLReader::setParserProperty(int property, boolean value)
-
Sets parser property (one of the parser option constants).
-
Properties must be set after open() or XML() and before the first read() is called */
-
PHP_METHOD(xmlreader, setParserProperty)
-
xmlreader_object *intern;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «lb», &property, &value) == FAILURE) {
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
retval = xmlTextReaderSetParserProp(intern->ptr,property, value);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Invalid parser property»);
-
/* {{{ proto boolean XMLReader::setRelaxNGSchema(string filename)
-
Sets the string that the the XMLReader will parse. */
-
PHP_METHOD(xmlreader, setRelaxNGSchema)
-
php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAM_PASSTHRU, XMLREADER_LOAD_FILE);
-
/* {{{ proto boolean XMLReader::setRelaxNGSchemaSource(string source)
-
Sets the string that the the XMLReader will parse. */
-
PHP_METHOD(xmlreader, setRelaxNGSchemaSource)
-
php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAM_PASSTHRU, XMLREADER_LOAD_STRING);
-
xmlTextReaderSetSchema (xmlTextReaderPtr reader,
-
/* {{{ proto boolean XMLReader::XML(string source [, string encoding [, int options]])
-
Sets the string that the the XMLReader will parse. */
-
PHP_METHOD(xmlreader, XML)
-
int source_len = 0, encoding_len = 0;
-
xmlreader_object *intern = NULL;
-
char *source, *uri = NULL, *encoding = NULL;
-
int resolved_path_len, ret = 0;
-
char *directory=NULL, resolved_path[MAXPATHLEN];
-
xmlParserInputBufferPtr inputbfr;
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, «s|s!l», &source, &source_len, &encoding, &encoding_len, &options) == FAILURE) {
-
if (id != NULL && ! instanceof_function(Z_OBJCE_P(id), xmlreader_class_entry TSRMLS_CC)) {
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
xmlreader_free_resources(intern);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Empty string supplied as input»);
-
inputbfr = xmlParserInputBufferCreateMem(source, source_len, XML_CHAR_ENCODING_NONE);
-
/* Get the URI of the current script so that we can set the base directory in libxml */
-
directory = VCWD_GETCWD(resolved_path, MAXPATHLEN);
-
directory = VCWD_GETWD(resolved_path);
-
resolved_path_len = strlen(resolved_path);
-
if (resolved_path[resolved_path_len — 1] != DEFAULT_SLASH) {
-
resolved_path[resolved_path_len] = DEFAULT_SLASH;
-
resolved_path[++resolved_path_len] = »;
-
uri = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
-
reader = xmlNewTextReader(inputbfr, uri);
-
#if LIBXML_VERSION >= 20628
-
ret = xmlTextReaderSetup(reader, NULL, uri, encoding, options);
-
object_init_ex(return_value, xmlreader_class_entry);
-
intern = (xmlreader_object *)zend_objects_get_address(return_value TSRMLS_CC);
-
intern->input = inputbfr;
-
xmlFreeParserInputBuffer(inputbfr);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Unable to load source data»);
-
/* {{{ proto boolean XMLReader::expand()
-
Moves the position of the current instance to the next node in the stream. */
-
PHP_METHOD(xmlreader, expand)
-
zval *id, *rv = NULL, *basenode = NULL;
-
xmlreader_object *intern;
-
php_libxml_node_object *domobj = NULL;
-
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), «O|O!», &id, xmlreader_class_entry, &basenode, dom_node_class_entry) == FAILURE) {
-
NODE_GET_OBJ(node, basenode, xmlNodePtr, domobj);
-
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
-
if (intern && intern->ptr) {
-
node = xmlTextReaderExpand(intern->ptr);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «An Error Occured while expanding «);
-
nodec = xmlDocCopyNode(node, docp, 1);
-
php_error_docref(NULL TSRMLS_CC, E_NOTICE, «Cannot expand this node type»);
-
DOM_RET_OBJ(rv, nodec, &ret, (dom_object *)domobj);
-
php_error_docref(NULL TSRMLS_CC, E_WARNING, «Load Data before trying to expand»);
-
php_error(E_WARNING, «DOM support is not enabled»);
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_close, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_getAttribute, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_getAttributeNo, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_getAttributeNs, 0)
-
ZEND_ARG_INFO(0, namespaceURI)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_getParserProperty, 0)
-
ZEND_ARG_INFO(0, property)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_isValid, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_lookupNamespace, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_moveToAttribute, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_moveToAttributeNo, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_moveToAttributeNs, 0)
-
ZEND_ARG_INFO(0, namespaceURI)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_moveToElement, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_moveToFirstAttribute, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_moveToNextAttribute, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_read, 0)
-
ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlreader_next, 0, 0, 0)
-
ZEND_ARG_INFO(0, localname)
-
ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlreader_open, 0, 0, 1)
-
ZEND_ARG_INFO(0, encoding)
-
ZEND_ARG_INFO(0, options)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_readInnerXml, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_readOuterXml, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_readString, 0)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_setSchema, 0)
-
ZEND_ARG_INFO(0, filename)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_setParserProperty, 0)
-
ZEND_ARG_INFO(0, property)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_setRelaxNGSchema, 0)
-
ZEND_ARG_INFO(0, filename)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_setRelaxNGSchemaSource, 0)
-
ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlreader_XML, 0, 0, 1)
-
ZEND_ARG_INFO(0, encoding)
-
ZEND_ARG_INFO(0, options)
-
ZEND_BEGIN_ARG_INFO(arginfo_xmlreader_expand, 0)
-
static const zend_function_entry xmlreader_functions[] = {
-
PHP_ME(xmlreader, close, arginfo_xmlreader_close, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, getAttribute, arginfo_xmlreader_getAttribute, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, getAttributeNo, arginfo_xmlreader_getAttributeNo, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, getAttributeNs, arginfo_xmlreader_getAttributeNs, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, getParserProperty, arginfo_xmlreader_getParserProperty, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, isValid, arginfo_xmlreader_isValid, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, lookupNamespace, arginfo_xmlreader_lookupNamespace, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, moveToAttributeNo, arginfo_xmlreader_moveToAttributeNo, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, moveToAttribute, arginfo_xmlreader_moveToAttribute, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, moveToAttributeNs, arginfo_xmlreader_moveToAttributeNs, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, moveToElement, arginfo_xmlreader_moveToElement, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, moveToFirstAttribute, arginfo_xmlreader_moveToFirstAttribute, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, moveToNextAttribute, arginfo_xmlreader_moveToNextAttribute, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, open, arginfo_xmlreader_open, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
-
PHP_ME(xmlreader, read, arginfo_xmlreader_read, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, next, arginfo_xmlreader_next, ZEND_ACC_PUBLIC)
-
#if LIBXML_VERSION >= 20620
-
PHP_ME(xmlreader, readInnerXml, arginfo_xmlreader_readInnerXml, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, readOuterXml, arginfo_xmlreader_readOuterXml, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, readString, arginfo_xmlreader_readString, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, setSchema, arginfo_xmlreader_setSchema, ZEND_ACC_PUBLIC)
-
/* Not Yet Implemented though defined in libxml as of 2.6.9dev
-
PHP_ME(xmlreader, resetState, NULL, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, setParserProperty, arginfo_xmlreader_setParserProperty, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, setRelaxNGSchema, arginfo_xmlreader_setRelaxNGSchema, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, setRelaxNGSchemaSource, arginfo_xmlreader_setRelaxNGSchemaSource, ZEND_ACC_PUBLIC)
-
PHP_ME(xmlreader, XML, arginfo_xmlreader_XML, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
-
PHP_ME(xmlreader, expand, arginfo_xmlreader_expand, ZEND_ACC_PUBLIC)
-
/* {{{ PHP_MINIT_FUNCTION
-
PHP_MINIT_FUNCTION(xmlreader)
-
memcpy(&xmlreader_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
-
xmlreader_object_handlers.read_property = xmlreader_read_property;
-
xmlreader_object_handlers.write_property = xmlreader_write_property;
-
xmlreader_object_handlers.get_property_ptr_ptr = xmlreader_get_property_ptr_ptr;
-
INIT_CLASS_ENTRY(ce, «XMLReader», xmlreader_functions);
-
ce.create_object = xmlreader_objects_new;
-
xmlreader_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
-
zend_hash_init(&xmlreader_prop_handlers, 0, NULL, NULL, 1);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «attributeCount», xmlTextReaderAttributeCount, NULL, IS_LONG TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «baseURI», NULL, xmlTextReaderConstBaseUri, IS_STRING TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «depth», xmlTextReaderDepth, NULL, IS_LONG TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «hasAttributes», xmlTextReaderHasAttributes, NULL, IS_BOOL TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «hasValue», xmlTextReaderHasValue, NULL, IS_BOOL TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «isDefault», xmlTextReaderIsDefault, NULL, IS_BOOL TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «isEmptyElement», xmlTextReaderIsEmptyElement, NULL, IS_BOOL TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «localName», NULL, xmlTextReaderConstLocalName, IS_STRING TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «name», NULL, xmlTextReaderConstName, IS_STRING TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «namespaceURI», NULL, xmlTextReaderConstNamespaceUri, IS_STRING TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «nodeType», xmlTextReaderNodeType, NULL, IS_LONG TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «prefix», NULL, xmlTextReaderConstPrefix, IS_STRING TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «value», NULL, xmlTextReaderConstValue, IS_STRING TSRMLS_CC);
-
xmlreader_register_prop_handler(&xmlreader_prop_handlers, «xmlLang», NULL, xmlTextReaderConstXmlLang, IS_STRING TSRMLS_CC);
-
/* Constants for NodeType — cannot define common types to share with dom as there are differences in these types */
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«NONE», XML_READER_TYPE_NONE);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«ELEMENT», XML_READER_TYPE_ELEMENT);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«ATTRIBUTE», XML_READER_TYPE_ATTRIBUTE);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«TEXT», XML_READER_TYPE_TEXT);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«CDATA», XML_READER_TYPE_CDATA);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«ENTITY_REF», XML_READER_TYPE_ENTITY_REFERENCE);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«ENTITY», XML_READER_TYPE_ENTITY);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«PI», XML_READER_TYPE_PROCESSING_INSTRUCTION);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«COMMENT», XML_READER_TYPE_COMMENT);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«DOC», XML_READER_TYPE_DOCUMENT);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«DOC_TYPE», XML_READER_TYPE_DOCUMENT_TYPE);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«DOC_FRAGMENT», XML_READER_TYPE_DOCUMENT_FRAGMENT);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«NOTATION», XML_READER_TYPE_NOTATION);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«WHITESPACE», XML_READER_TYPE_WHITESPACE);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«SIGNIFICANT_WHITESPACE», XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«END_ELEMENT», XML_READER_TYPE_END_ELEMENT);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«END_ENTITY», XML_READER_TYPE_END_ENTITY);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«XML_DECLARATION», XML_READER_TYPE_XML_DECLARATION);
-
/* Constants for Parser options */
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«LOADDTD», XML_PARSER_LOADDTD);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«DEFAULTATTRS», XML_PARSER_DEFAULTATTRS);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«VALIDATE», XML_PARSER_VALIDATE);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«SUBST_ENTITIES», XML_PARSER_SUBST_ENTITIES);
-
/* Constants for Errors when loading — not yet used until we implement custom error handling
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«VALIDITY_WARNING», XML_PARSER_SEVERITY_VALIDITY_WARNING, CONST_CS | CONST_PERSISTENT);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«VALIDITY_ERROR», XML_PARSER_SEVERITY_VALIDITY_ERROR, CONST_CS | CONST_PERSISTENT);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«WARNING», XML_PARSER_SEVERITY_WARNING, CONST_CS | CONST_PERSISTENT);
-
REGISTER_XMLREADER_CLASS_CONST_LONG(«ERROR», XML_PARSER_SEVERITY_ERROR, CONST_CS | CONST_PERSISTENT);
-
/* {{{ PHP_MSHUTDOWN_FUNCTION
-
PHP_MSHUTDOWN_FUNCTION(xmlreader)
-
zend_hash_destroy(&xmlreader_prop_handlers);
-
/* {{{ PHP_MINFO_FUNCTION
-
PHP_MINFO_FUNCTION(xmlreader)
-
php_info_print_table_start();
-
php_info_print_table_row(2, «XMLReader», «enabled»);
-
php_info_print_table_end();
-
* vim600: noet sw=4 ts=4 fdm=marker
-
* vim<600: noet sw=4 ts=4
-
Страница 1 из 2