XML Paser Functions при работе с шаблонами.


Содержание

XML парсер

Все современные браузеры имеют встроенный XML парсер.

Этот XML парсер преобразует XML документ в объект XML DOM, которым затем можно манипулировать при помощи JavaScript.

Объект XMLHttpRequest

Объект XMLHttpRequest позволяет обмениваться данными в фоновом режиме.

Это настоящая сбывшаяся мечта разработчика, потому что вы можете:

  • Обновлять содержимое веб-страницы не перезагружая веб-страницу
  • Запрашивать данные с сервера, когда веб-страница уже загружена
  • Получать данные с сервера, когда веб-страница уже загружена
  • Посылать данные на сервер в фоновом режиме

Создание объекта XMLHttpRequest

Все современные браузеры (IE7+, Firefox, Chrome, Safari, Opera) уже имеют встроенный объект XMLHttpRequest.

Объект XMLHttpRequest создается следующим образом:

Старые версии браузера Internet Explorer (IE5 и IE6) используют объект ActiveXObject:

Работа с объектом XMLHttpRequest

Типичный синтаксис JavaScript для работы с объектом XMLHttpRequest выглядит следующим образом:

В строке var xhttp = new XMLHttpRequest(); создается объект XMLHttpRequest.

В строке xhttp.onreadystatechange = function() свойство onreadystatechange определяет функцию, которая будет выполняться каждый раз, когда статус объекта XMLHttpRequest изменится.

Строка if (this.readyState == 4 && this.status == 200). Когда свойство readyState равно 4, и свойство status равно 200, ответ готов.

Свойство responseText возвращает ответ сервера в виде текстовой строки.

Эта текстовая строка может использоваться для изменения кода веб-страницы. Строка document.getElementBy >

Парсинг XML документа

Следующий фрагмент кода парсит XML документ в объект XML DOM:

Парсинг XML строки

Следующий фрагмент кода парсит XML строку в объект XML DOM:

Замечение: Браузер Internet Explorer использует метод loadXML() для парсинга XML строки, в то время, как остальные браузеры используют объект DOMParser.

Доступ к данным на других доменах

Из-за соображения безопасности современные браузеры не допускают возможности обращаться к данным на других доменах.

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

ikfi.ru

Парсинг XML с помощью XMLReader на PHP

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

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

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

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

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

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

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

id contact number
1 kenny 9(999)-999-99-99
2 finny 8(888)-888-88-88

Dive into XMLReader

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

Для себя я нашел простое, но достаточно практичное решение — я написал несколько оберток для работы с XMLReader, и то что получилось, меня пока что полностью удовлетворяет.

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

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

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


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

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

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

Первое что нужно сделать — это объявить переменные-члены и создать конструктор:

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

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

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

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

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

Соответственно, теперь у нас есть два метода — onEvent и fireEvent — являющиеся по сути реализацией паттерна Pub/Sub.

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

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

Вот и все, базовый класс полностью готов!

Далее я покажу как можно использовать все это безобразие.

К примеру, реализуем класс, обрабатывающий два типа элементов нашей xml’ки — ConfigXMLReader:

Как видим, все просто и понятно.

Далее самое вкусное — вызывающий код:

Вот таким нехитрым способом можно парсить большие и достаточно сложные XML файлы.

H Парсинг XML для чайников в черновиках

Все знают что конечно же это XMLReader, но вдруг кто-то и не знает :)

В итоге получили множество вариантов:
1. Domit XML Class
2. Simple XML
3. DOM
4. xml_parser (SAX)
5. XMLReader

Domit XML Class

Минусы: работает очень медленно, собирает весь файл в память, дерево составляется в отдельных массив ( в итоге ошибка allowed memory size неизбежна)

Плюсы: распространённость (множество CMS, включая Joomle Mb

Теперь остановимся на следующих: xml_parser и XMLReader.

Оба способа работают чтением файла построчно что подходит идеально для поставленной задачи.

Разница между xml_parser и XMLReader в том что, в первом случае вам нужно будет писать собственные функции которые будут реагировать на начало и конец тэга.

Проще говоря, xml_parser работает через 2 триггера – тэг открыт, тэг закрыт. Его не волнует что там идёт дальше, какие данные используются и т.д. Для работы вы задаёте 2 триггера указывающие на функции обработки.

В XMLReader всё проще. Во первых, это класс. Все триггеры уже заданы константами (их всего 17), чтение осуществляется функцией read() которая читает первое вхождение подходящее под заданные триггеры. Далее мы получаем объект в который ханосится тип данны (аля триггер), название тэга, его значение. Также XMLReader отлично работает с аттрибутами тэгов.

Согласно найденным бенчмаркам с большими файлами XMLReader справляется лучше чем xml_parser.

Требования к xml_parser:
PHP 5.0 >
libxml

Требования к XMLReader:
PHP 5.1
libxml

Часть 2. Расширенные методы парсинга XML

Методы синтаксического анализа объемных или сложных XML-документов в PHP5

Серия контента:

Этот контент является частью # из серии # статей: XML для PHP-разработчиков

Этот контент является частью серии: XML для PHP-разработчиков

Следите за выходом новых статей этой серии.

В PHP5 увеличено разнообразие методов синтаксического анализа (парсинга) XML. Парсер Expat SAX Джеймса Кларка, который теперь основан на библиотеке libxml2, больше не является единственным полнофункциональным парсером. Нам уже знакома возможность парсинга посредством DOM в полном согласии со стандартом W3C. Дополнительные возможности предлагает SimpleXML, который мы рассмотрели в части 1 (см. Ресурсы), и XMLReader, который проще в понимании и быстрее в работе, чем SAX. Все расширения XML теперь основаны на библиотеке libxml2 проекта GNOME. Эта унифицированная библиотека позволяет разным расширениям взаимодействовать друг с другом. В настоящей статье обсуждаются методы парсинга XML в РНР5 с акцентом на объемные или сложные XML-документы. В ней рассказывается о методах парсинга и о критериях выбора, когда он есть, оптимального метода для синтаксического анализа XML-документов разного типа.

SimpleXML

Другие статьи этой серии

В первой статье этой серии содержится важная информация об XML и инструкции по началу работы с интерфейсами прикладных программ (API). В ней демонстрировалось, что SimpleXML в сочетании с Document Object Model (DOM) служит идеальным инструментом для разработчиков, имеющих дело с простыми, предсказуемыми и относительно компактными XML-документами.


XML и PHP5

Язык Extensible Markup Language (XML) можно назвать и языком разметки, и форматом хранения текстовых данных; он предоставляет текстовые средства для описания древовидных структур и их применения к информации.

В РНР5 имеются как новые, так и переписанные расширения для XML-парсинга. SimpleXML, DOM и процессор XSLT загружают в память весь XML-документ целиком. Simple API for XML (SAX) и XMLReader относятся к тем парсерам, которые обрабатывают XML-документ по частям. SAX функционирует так же, как в РНР4, но теперь он основан на библиотеке libxml2, а не expat. Тем, кто знаком с DOM по другим языкам, в РНР5 будет легче с ним работать, чем в предыдущих версиях РНР.

Основы XML-парсинга

Существует два основных способа XML-парсинга: на базе деревьев и на базе потоков. Метод дерева предусматривает загрузку в память всего XML-документа целиком. Древовидная структура файла позволяет произвольно обращаться к элементам документа и редактировать XML. Примерами парсеров по методу дерева служат DOM и SimpleXML. Они хранят древовидную структуру в памяти в разных, но взаимодействующих форматах. При поточном парсинге весь документ в память не загружается. В данном случае термин «поток» употребляется в том же смысле, что и при описании поточного аудио. Происходит то же самое и по тем же причинам: данные поступают мелкими порциями с целью экономии полосы пропускания и ресурсов памяти. При поточном парсинге доступен только тот узел, который анализируется в данный момент, а редактирование XML-документа целиком невозможно. Примерами поточных парсеров служат XMLReader и SAX.

Парсеры, работающие по методу дерева

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

Парсинг при помощи DOM

Стандарт DOM, согласно W3C, представляет собой «. не зависящий от платформы и языка программирования интерфейс, который позволяет программам и сценариям динамически обращаться к документам и редактировать их содержание, структуру и стиль». Библиотека libxml2 проекта GNOME реализует DOM вместе со всеми его методами на языке С. Так как все XML-расширения РНР5 основаны на libxml2, они поддерживают полное взаимодействие друг с другом. Это взаимодействие значительно улучшает их функциональность. Например, можно извлечь элемент при помощи поточного парсера XMLReader, импортировать его в DOM и извлечь данные с использованием XPath. Подтверждение подобной гибкости продемонстрировано листинге 5.

Парсер DOM работает по методу дерева. Он прост для понимания и применения, так как его структура в памяти напоминает оригинальный XML-документ. DOM передает информацию приложению, создавая дерево объектов, в точности повторяющее дерево элементов из XML-файла, так что каждый элемент XML служит узлом этого дерева. DOM – это стандарт W3C, что принесло ему признание разработчиков ввиду его согласованности с другими языками программирования. Так как DOM строит дерево всего документа, он потребляет большой объем памяти и много ресурсов процессора.

DOM в действии

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

В примере, приведенном в листинге 1, DOM применяется для парсинга документа и извлечения элемента при помощи функции getElementById . Перед ссылкой на идентификатор документ необходимо проверить, установив val >. Согласно стандарту DOM, для этого требуется DTD, который определяет атрибут ID как тип ID.

Листинг 1. Использование DOM с простым документом

Функция getElementsByTagName() возвращает новый экземпляр класса DOMNodeList , содержащий элементы с заданным именем тега. Конечно, нужно пролистать список. Изменение структуры документа во время работы со списком NodeList , выданным функцией getElementsByTagName() , влияет на список NodeList , с которым вы работаете (см. листинг 2). Проверка в данном случае не требуется.

Листинг 2. Метод DOM getElementsByTagName

В примере из листинга 3 DOM используется с XPath.

Листинг 3. Использование DOM и парсинг с применением XPath

Высказав все эти приятные вещи по поводу DOM, я хочу привести пример того, что не надо делать с DOM, а затем, в следующем примере, показать, как это обойти. Листинг 4 иллюстрирует загрузку объемного файла в DOM только с целью извлечения данных из одного атрибута при помощи DomXpath.

Листинг 4. Неправильное использование DOM с XPath при работе с объемным XML-документом

В последнем примере (листинг 5) DOM с XPath применяется точно так же, только данные передаются в XMLReader по одному элементу за раз с использованием метода expand() . При этом узел, переданный XMLReader , преобразуется в DOMElement .

Листинг 5. Правильное использование DOM с XPath при работе с объемным XML-документом

Парсинг при помощи SimpleXML

Расширение SimpleXML – еще один способ парсинга XML-документа. Для расширения SimpleXML требуется PHP5 и используется встроенная поддержка XPath. SimpleXML лучше всего работает с несложными данными XML. В том случае, если XML-документ не слишком сложен, глубок и не имеет смешанного контента, SimpleXML проще в применении, чем DOM, как и предполагает его название. Он интуитивно понятен, если вы работаете с известной структурой документа.

SimpleXML в действии

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

Код, приведенный в листинге 6, извлекает из примера XML-документа сюжет произведения, содержащийся в элементе

Листинг 6. Извлечение фрагмента текста

С другой стороны, может понадобиться извлечь многострочный адрес. Когда у одного родительского элемента имеется несколько экземпляров дочернего элемента, применяется обычная методика итерирования. Эта функциональность демонстрируется в листинге 7.

Илон Маск рекомендует:  jQuery - Описание библиотеки
Листинг 7. Извлечение нескольких экземпляров элемента

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

Листинг 8. Демонстрация обращения SimpleXML к атрибутам элемента

В последнем примере (см. листинг 9) SimpleXML и DOM используются с расширением XMLReader . При помощи XMLReader данные передаются последовательно, по одному элементу, с использованием метода expand() . Этим методом узел, переданный XMLReader , можно преобразовать в DOMElement , а затем передать SimpleXML.

Листинг 9. Использование SimpleXML и DOM с расширением XMLReader для анализа объемного XML-документа

Потоковые парсеры

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

Парсинг при помощи XMLReader

XMLReader — это потоковый парсер того типа, который часто называют курсорным или pull-парсером. XMLReader вытягивает информацию из XML-документа по требованию. Он основан на API, полученном из C# XmlTextReader. В PHP 5.1 он включен и задействован по умолчанию и основан на библиотеке libxml2. До выхода PHP 5.1 расширение XMLReader не было включено по умолчанию, но было доступно в PECL (см. Ресурсы). XMLReader поддерживает пространства имен и проверку, включая DTD и Relaxed NG.

XMLReader в действии

Как потоковый парсер, XMLReader хорошо подходит для работы с объемными XML-документами; программировать в нем намного легче и обычно быстрее, чем в SAX. Это лучший потоковый парсер.

В следующем примере (листинг 10) объемный XML-документ анализируется при помощи XMLReader.

Листинг 10. XMLReader с объемным XML-файлом


Парсинг при помощи SAX

Simple API for XML (SAX) представляет собой потоковый парсер. События связаны с читаемым XML-документом, поэтому SAX программируется в стиле обратных вызовов. Существуют события для открывающих и закрывающих тегов элемента, сущностей и ошибок парсинга. Главная причина использования парсера SAX вместо XMLReader заключается в том, что парсер SAX иногда более эффективен и обычно лучше знаком. Важный недостаток — код для парсера SAX получается сложнее, и его труднее писать, чем для XMLReader.

SAX в действии

SAX должен быть знаком тем, кто работал с XML в PHP4, а расширение SAX в PHP5 совместимо с версией, к которой они привыкли. Так как это потоковый парсер, он хорошо справляется с объемными файлами, но это не лучший выбор, чем XMLReader.

В листинге 11 приведен пример обработки объемного XML-документа парсером SAX.

Листинг 11. Использование SAX для анализа объемного XML-файла

Заключение

PHP5 предлагает большое разнообразие методов парсинга. Парсинг при помощи DOM, который теперь полностью совместим со стандартом W3C, — знакомый вариант, подходящий для сложных, но относительно компактных документов. SimpleXML — это способ работы с простыми и не слишком объемными документами, а потоковый парсер XMLReader, который легче и быстрее, чем SAX, предпочтителен для очень больших документов.

Ресурсы для скачивания

Похожие темы

  • Оригинал статьи (EN).
  • XML для PHP-разработчиков, часть 1: Работа с XML в PHPза 15 минут (Клифф Морган, developerWorks, февраль 2007 г.): В первой статье этой серии из трех частей рассказывается о реализации XML в РНР5 и о том, как легко работать с XML в среде РНР.
  • XML для PHP-разработчиков, часть 3: дополнительные методы чтения, организации и составления XML-документов (Клифф Морган, developerWorks, март 2007 г.): в заключительной части серии из трех статей об XML для РНР-разработчиков рассказывается о методах чтения, обработки и составления XML-документов в РНР5.(EN)
  • SAX, the power API (Benoît Marchal, developerWorks, август 2001 г.): Введение в SAX, сравнение DOM и SAX, инструкции по работе с SAX (EN).
  • Reading and writing the XML DOM in PHP (Jack Herrington, developerWorks, декабрь 2005 г.): Три метода чтения XML: библиотека DOM, синтаксический анализатор SAX и регулярные выражения. Также рассказывается, как писать XML с применением текстовых шаблонов DOM и PHP (EN).
  • What kind of language is XSLT (Michael Kay, developerWorks, апрель 2005 г.): Об истоках языка XSLT и его преимуществах (EN).
  • Tip: Implement XMLReader: An interface for XML converters (Benoît Marchal, developerWorks, ноябрь 2003 г.): В этой статье исследуются API для конвейеров XML и причины, по которым знакомый интерфейс XMLReader подходит для многих компонентов. (EN)
  • SimpleXML Processing with PHP (Elliotte Rusty Harold, developerWorks, октябрь 2006 г.): Расширение SimpleXML позволяет PHP-страницам обращаться к XML с запросами, вести в них поиск, модифицировать и повторно публиковать его (EN).
  • A PHP5 migration gu >

Комментарии

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

Как сделать xml parser (PHP).

Вот и лето пришло и первая неделя июля пролетела незаметно. Через две недели мне защищать свой диплом, а одна из частей его – XML parser. Но жалко, что не в пхп. Ну ниче, счас наверстаем

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

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

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

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

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

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

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

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

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

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

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

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

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

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

function endElement($parser, $name) <
global $depth;

$depth—; // уменьшаем глубину
>

$depth = 0;
$file = «data.xml»;


if (!($fp = fopen($file, «r»))) <
die(«could not open XML input»);
>

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

Попробуем испортить XML-файл, заменив тег

на , а закрывающий тег оставив прежним:

XML Error: Mismatched tag at line 5

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

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

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

Посмотрим теперь на вывод:

О! Теперь вывели все!

Кстати, кто-нибудь заметил, что имена тегов и атрибутов все большими буквами написаны? Странно… они же в нашем xml-файле малыми буквами обозначены. Видимо где-то какие-то настройки установлены, чтобы делать uppercase…

Ааа, нашел! Оказывается есть еще функция xml_parser_set_option:

xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0);

Таким вызовом мы отменяем вывод имен атрибутов и имен тегов большими буквами:

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

nika, Вам нужно вставить вызов
xml_set_character_data_handler($xml_parser, ’stringElement’);
после
xml_set_element_handler($xml_parser, “startElement”, “endElement”);

В общем для правильного отображения нужно соблюдать следующее:
1. нужно, чтобы xml-файл был в кодировке UTF-8
2. в xml-файле первая строчка должна быть такой:

3. нужно инициализировать парсер так:
xml_parser_create(”UTF-8?);
4. нужно перед выводом содержимого xml-файла в браузер настроить последний на кодировку UTF-8:
header( “Content-Type: text/html; charset=utf-8?);

Для отображения текста на русском языке используем
iconv(”UTF-8?,”windows-1251?, $attr), где $attr, то что нужно вывести.

Есть такие два класса интересных в стандартной библеотеке PHP5 – DOMDocument() и XSLTProcesor() использовал на довольно крупных проектах – не жалуюсь =)

Вообще у PHP есть еще одна библиотечка для разбора XML по принципу SAX – называется XMLReader.

Господа, как вывести из xml с помощью simplexml не стандартные теги, например ?
Переменная вида $text = $item->yandex:full-text не работает.

Все ОК, только обратите внимание на наличие следующего параметра,

function cdata($parser, $cdata)
<
var_dump($parser, $cdata);
>

Без него не хочет парсить XML с CDATA…. размером в 1.5 метра

2Nika, Функция header() работает только в том случае, если до нее не было ничего выведено, то бишь первым действие производили ее, т.к. мы отсылаем заголовки на эту страницу, которые говорят нам, что текст нужно переводить в кодировку UTF-8. Судя по вашей ошибке у вас есть пропуски строк, поэтому сделайте вот так:

Значение == порядковый номер строки

Также почитайте:

Комментарии к посту «Как сделать xml parser (PHP).»

Комментариев пока нет, будьте первым.

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.

Парсинг XML с использованием lxml

Ранее мы рассматривали некоторые встроенные в Python XML парсеры. В этой статье, мы рассмотрим один интересный сторонний пакет lxml от codespeak. Он, в частности, использует API ElementTree. Пакет lxml имеет поддержку XPath и XSLT, включая API для SAX и API уровня С для совместимости с модулями C/Pyrex. В статье мы рассмотрим следующее:

  • Парсинг XML используя lxml
  • Пример рефакторинга
  • Как выполнять парсинг XML с lxml.objectify
  • Как создавать XML с lxml.objectify

В этой статье, мы используем примеры, основанные на примерах парсинга minidom, и посмотрим, как выполнять парсинг при помощи lxml Python. Вот пример XML из программы, которая была написана для отслеживания назначений:

Давайте посмотрим, как происходит парсинг с использованием lxml.

Парсинг XML с lxml

Данный пример XML показывает два назначения. Время начинается спустя секунды после эпохи. Наш uid сгенерирован на основе хеша начала времени и ключа. Время сигнала – несколько секунд после эпохи, но не раньше начала времени. Состояние – если назначение было отменено или перенесено, или нет, так или иначе. Остальная часть XML, как мы видим, в пояснении не нуждается. Давайте взглянем на то, как делается парсинг:

XML Paser Functions при работе с шаблонами.

Я поначалу совсем не хотел останавливаться на том, что такое XML, но все-таки несколько слов сказать придется, чтобы те, кто про него услышали первый раз, прочитав эти строки, были в курсе основных идей.
По сути XML представляет собой обычный текст, который разделяется на логические группы с помощью специальных меток, которые называют “тэг”.
Тэг представляет собой слово, которое заключено в угловые скобки — например вот так:

Для того, чтобы начать группу вы указывает просто слово в скобках — еще раз повторим
Для окончание группы вы указываете такой же тэг, но слово предваряется символом “/”. Вот так:


В итоге группа внутри тэга test выглядит вот так:
Группа символов для тестирования

Тэги могу вкладываться один в другой — например вот так:

Группа символов для тестирования 01
Группа символов для тестирования 02
Группа символов для тестирования 03

Кроме вложений текста в тэгах можно указывать атрибуты — вот так:

Группа символов для тестирования 01

Назначение тэгов очень простое — надо отметить/выделить/сгруппировать какую-то информацию для того, чтобы потом ее можно было использовать. Это может быть список имен, список книг, список фирм, список вакансий и т.д.
Например, я хочу написать список контактов, с указанием имени, фамилии и e-mail. Можно сделать это так (но можно и по-другому — здесь все зависит от вашей фантазии и требований задачи):

Василий
Курочкин
vas@pisem.net

Георгий
Папанов
geogr@gmail.com

Семен
Баринов
barinov@yandex.ru

Не ищите тайного смысла — я просто сделал строку, в которой выделил нужные мне части — контакт (тэг contact) и внутри определил имя, фамилию и e-mail (тэги firstName, lastName, email). Также с помощью атрибута type я определи тип контакта — друг, коллега, однокурсник. Теперь просматривая строку я могу выделить нужные мне части информации. Это удобно и ничего более. Причем здесь больше удобства даже не для визуального восприятия (это спорно), а для программной обработки — достаточно несложно написать программу, которая найдет конкретные кусочки.

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

Работа с XML

В первую очередь я хотел бы высказать свою позицию по поводу самого XML и уже на основе этого продолжать повествование.
Для меня XML — очень мощная технология, которая позволяет хранить, передавать и обрабатывать сложноструктурированные данные. Т.е. если я хочу иметь: список фирм с их телефонами и счетами, каталог книг с авторами и отзывами, описание структуры страниц сайта с комментариями, состояние всех автобусов в городе с их координатами, водителями, номерами и прочая — все это может быть удобно сохранено в виде XML и, что крайне важно и удобно, может быть передано в любую систему, которая написана на любой платформе — на .NET, PHP, Object C, Delphi, C++.
Проведите мысленный эксперимент — попробуйте написать строку, в которой передать информацию о своих контактах (где у одной персоны может быть несколько телефонов, e-mail, любимые книги, места работы, места учебы и … да хватит пока). Что важно — это должна быть обычная строка (несколько строк), которая позволяет разбирать эту информацию в ту структуру, которую я описал — класс Java. Там надо предусмотреть какие-то разделители, информацию об именах полей (группах полей). Попробуйте — и вы придете к чему-то подобному XML.

Илон Маск рекомендует:  form в HTML

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

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

  1. Разбор. Надо уметь разобрать строку на что-то более удобное для обработки — пытаться вставить внутрь строки или находить какое-то поле определенной записи из строки — это достаточно неудобно. Значит нам надо иметь некоторый набор классов для представления нашей строки в виде структуры объектов.
  2. Поиск. По структуре данных надо уметь что-то искать. Причем не подстроку, а какую-то группу полей, которые относятся к определенному объекту — например полная информация о книге — наименование, авторы, отзывы. Или список контактов с фамилией “Сидоров”.
  3. Проверка. Данные должны быть корректными, т.е. там должны быть только определенные поля, с определенным наполнением и они должны быть правильно скомпанованы в нашей строке.
  4. Преобразование. Хоть XML достаточно удобно описывает структурированные данные, это не значит, что его удобно просматривать обычному человеку или всегда удобно обрабатывать. Нередко для решения этого вопроса требуется преобразовать XML в какое-либо другое текстовое представление — например в тот же HTML (который является частным воплощением XML). Или даже в обычный текст.

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

Разбор — Parsing

В слэнге программистов часто используется слова “парсинг”, который и обозначает разбор строки (или еще чего-нибудь) в какую-то структуру. Здесь надо выделить два момента:

  1. Разбор строки определенным алгоритмом
  2. Сохранение результатов разбора в какую-то структуру вместо строки — ибо со строкой многие операции делать просто неудобно.

Что касается второго пункта, то на сегодня существует по сути одна унифицированная структура, которая называется Document Object Model (DOM).
DOM представляет собой набор интерфейсов (и их реализаций), которые являются специализированными объектами для хранения “узлов” (node) XML-документа. По сути каждый тэг — это “узел” (нода — я буду использовать этот термин, т.к. очень привык). Информация внутри тэга — тоже нода. По сути любой разобранный XML — это набор элементов типа Node и еще более специализированных, построенных в дерево.
Почему дерево ? Да потому что у каждой ноды может быть список дочерних нод и у каждой из них тоже может быть “детки”. Так и строится дерево. Если вам сложно это увидеть, то советую посмотреть какую-либо классическую книгу по алгоритмам и структурам данных — можно старого доброго Никлауса Вирта «Алгоритмы и структуры данных». Книгу можно найти в интернете, ну или купить.

Давайте рассмотрим загрузку файла и редактирование построенного дерева на примере. Наша программа считывает XML-файл со списком книг и печатает их свойства. Сам XML-файл выглядит вот так:

xml_parse_into_struct — Разбор XML данных и помещение в массив

(PHP 4, PHP 5, PHP 7)

xml_parse_into_struct — Разбор XML данных и помещение в массив

Описание

Эта функция разбирает XML строку и помещает данные в 2 массива. Массив index содержит указатели на размещение значений в массиве values . Аргументы, задающие массивы, должны передаваться в функцию по ссылке.

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

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

Строка XML данных.

Массив значений XML данных.

Массив указателей на соответствующие значения в массиве $values.

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

xml_parse_into_struct() возвращает 0 при неудачном разборе строки и 1 при успешном. Это не тоже самое, что FALSE и TRUE , будьте осторожны с такими операторами, как ===.

Примеры

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

Пример #1 Пример использования xml_parse_into_struct()

» ;
$p = xml_parser_create ();
xml_parse_into_struct ( $p , $simple , $vals , $index );
xml_parser_free ( $p );
echo «Index array\n» ;
print_r ( $index );
echo «\nМассив Vals\n» ;
print_r ( $vals );
?>

После обработки программа выведет следующее:

Управляемый событиями разбор (основанный на expat библиотеке) может дать труднообрабатываемый результат в случае, если разбирается составной XML документ. Эта функция не создает DOM объектов, но создаваемые ею массивы можно преобразовать в древовидную структуру впоследствии. Таким образом можно довольно просто создавать объекты, представляющие содержимое XML файла. Предположим, что следующий XML файл представляет небольшую базу данных с информацией об аминокислотах:

Пример #2 moldb.xml — небольшая база данных с информацией о молекулах

Пример #3 parsemoldb.php — разбирает moldb.xml и помещает данные в массив молекул

class AminoAcid <
var $name ; // название аминокислоты
var $symbol ; // трехбуквенное обозначение
var $code ; // однобуквенный код
var $type ; // гидрофобная, заряженная, нейтральная


function AminoAcid ( $aa )
<
foreach ( $aa as $k => $v )
$this -> $k = $aa [ $k ];
>
>

function readDatabase ( $filename )
<
// чтение XML базы данных аминокислот
$data = implode ( «» , file ( $filename ));
$parser = xml_parser_create ();
xml_parser_set_option ( $parser , XML_OPTION_CASE_FOLDING , 0 );
xml_parser_set_option ( $parser , XML_OPTION_SKIP_WHITE , 1 );
xml_parse_into_struct ( $parser , $data , $values , $tags );
xml_parser_free ( $parser );

// проход через структуры
foreach ( $tags as $key => $val ) <
if ( $key == «molecule» ) <
$molranges = $val ;
// каждая смежная пара значений массивов является верхней и
// нижней границей определения молекулы
for ( $i = 0 ; $i count ( $molranges ); $i += 2 ) <
$offset = $molranges [ $i ] + 1 ;
$len = $molranges [ $i + 1 ] — $offset ;
$tdb [] = parseMol ( array_slice ( $values , $offset , $len ));
>
> else <
continue;
>
>
return $tdb ;
>

function parseMol ( $mvalues )
<
for ( $i = 0 ; $i count ( $mvalues ); $i ++) <
$mol [ $mvalues [ $i ][ «tag» ]] = $mvalues [ $i ][ «value» ];
>
return new AminoAcid ( $mol );
>

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

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

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

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

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

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

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

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

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

function webi_xml ( $file )
<

$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;>
// если закрывающий тег был найден, теперь отправим эти собранные данные в обработку

// проверяем, если это первый вход в файл, то удалим все, что находится до тега if( $perviy_vxod )

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

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

// после разбора скидываем собранные данные для следующего шага цикла.
$data = «» ;
>
fclose ( $fp );
xml_parser_free ( $xml_parser );

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

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

= «1.0» encoding = «windows-1251» ?>
= «хлеб» 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_parse ( $xml_parser , $data , feof ( $fp )) ;
После обработки данных строковая переменная сбрасыватеся и снова начинается сбор данных в строку и во второй раз сформируется строка

В третий

в четвертый
Простой хлеб

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

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

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

Начинаем с функции открывающих тегов 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’ ]). ‘
‘ ;
print_r ( $webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ ‘attrs’ ]);
print ‘
‘ ;
print_r ( $webi_tag_open ); // массив открытых тегов
print ‘ ‘ ;

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

Илон Маск рекомендует:  FormatDateTime - Функция Delphi

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

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

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

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

print ‘данные ‘ . $webi_tag_open [ $webi_depth ]. ‘—‘ .( $webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ ‘data’ ]). ‘
‘ ;
print_r ( $webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ ‘attrs’ ]);
print ‘
‘ ;
print_r ( $webi_tag_open );
print ‘ ‘ ;

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

$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;>
// если закрывающий тег был найден, теперь отправим эти собранные данные в обработку

// проверяем, если это первый вход в файл, то удалим все, что находится до тега if( $perviy_vxod )

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

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

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

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

Ну вот и все, теперь при обработке файла любого размера памяти хватит, а вот время работы скрипта увеличить можно несколькими способами.
В начало скрипта вставьте функцию
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 на мастерхосте, но об этом не в этой статье.

Комментарии

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
Как уже указывал — такие результаты были достигнуты в режиме чтения 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 Paser Functions при работе с шаблонами.

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

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

Основы использования

Давайте начнем со следующего примера languages.xml:

Данный XML-документ содержит список языков программирования с некоторой информацией о каждом языке: год его реализации и имя его создателя.

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

Обе функции считывают все дерево DOM в память и возвращают объект SimpleXMLElement. В приведенном выше примере, объект сохраняется в переменной $languages. Вы можете использовать функции var_dump() или print_r(), чтобы получить подробную информацию о возвращенном объект, если хотите.

Данный XML содержит корневой элемент languages, внутри которого находятся три элемента lang. Каждый элемент массива соответствует элементу lang в XML-документе.

Вы можете получить доступ к свойствам объекта при помощи оператора ->. Например, $languages->lang[0] вернет вам объект SimpleXMLElement, который соответствует первому элементу lang. Этот объект содержит два свойства: appeared и creator.

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

%s появился в %d и был создан %s .

» ,
$lang [ «name» ] ,
$lang -> appeared ,
$lang -> creator
) ;
>

Обратите внимание, как я получил доступ к имени атрибута элемента lang, чтобы получить название языка. Таким образом Вы можете получить доступ к любому атрибуту элемента представленого в виде объекта SimpleXMLElement.

Работа с пространствами имен

Во время работы с XML различных веб-сервисов вы не раз столкнетесь с пространствами имен элементов. Давайте изменим наш languages.xml, чтобы показать пример использования пространства имен:

Теперь элемент creator помещается в пространстве имен dc, который указывает на http://purl.org/dc/elements/1.1/. Если вы попытаетесь распечатать создателей языка, используя наш предыдущий код, то он не будет работать. Для того, чтобы читать пространства имен элементов вам необходимо использовать один из следующих подходов.

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

Метод children() принимает пространство имен и возвращает дочерние элементы, которые начинаются с префикса. Он принимает два аргумента, первый из которых является пространством имен XML, и второй необязательный аргумент, который по умолчанию равен false. Если второй аргумент установлен как TRUE, пространство имен будет рассмотрено как префикс. Если FALSE, то пространство имен будет рассмотрено как пространство имен URL.

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

$namespaces = $languages -> getNamespaces ( true ) ;
$dc = $languages -> lang [ 1 ] -> children ( $namespaces [ «dc» ] ) ;

echo $dc -> creator ;

Метод GetNamespaces() возвращает массив имен префиксов и связанные с ними URI. Он принимает дополнительный параметр, который по умолчанию равен false. Если вы установите его как true, то этот метод будет возвращать имена, используемые в родительских и дочерних узлах. В противном случае, он находит пространства имен, используемые только в родительском узле.

Теперь вы можете пройтись по списку языков следующим образом:

$languages = simplexml_load_file ( «languages.xml» ) ;
$ns = $languages -> getNamespaces ( true ) ;

foreach ( $languages -> lang as $lang ) <
$dc = $lang -> children ( $ns [ «dc» ] ) ;
printf (
«

%s появился в %d и был создан %s .

» ,
$lang [ «name» ] ,
$lang -> appeared ,
$dc -> creator
) ;
>

Практический пример — Парсинг видео-канала с YouTube

Давайте рассмотрим пример, который получает RSS-feed с канала YouTube и отображает ссылки на все видео из него. Для этого нужно обратится по следующему адресу:

URL возвращает список последних видео с данного канала в формате XML. Мы распарсим XML и получим следующую информацию для каждого видео:

Мы начнем с поиска и загрузки XML:

$channel = «Имя_канала» ;
$url = «http://gdata.youtube.com/feeds/api/users/» . $channel . «/uploads» ;
$xml = file_get_contents ( $url ) ;

$feed = simplexml_load_string ( $xml ) ;
$ns = $feed -> getNameSpaces ( true ) ;

Если вы посмотрите на XML-feed, то вы можете увидеть, что там есть несколько элементов entity, каждый из которых хранит подробную информацию о конкретном видео с канала. Но мы используем только миниатюры изображений, адрес видео и название. Эти три элемента являются потомками элемента group, который, в свою очередь, является дочерним для entry:

Мы просто пройдемся по всем элементам entry, и для каждого из них извлечем необходимую информацию. Обратите внимание, что player, thumbnail и title находятся в пространстве имен media. Таким образом, мы должны действовать, как в предыдущем примере. Мы получаем имена из документа и используем пространство имен при обращении к элементам.

Заключение

Теперь, когда вы знаете, как использовать SimpleXML для разбора XML-данных, вы можете улучшить свои навыки путем анализа различных XML-каналов с различными API. Но важно учитывать, что SimpleXML считывает весь DOM в память, так что если вы парсите большой набор данных, то вы можете столкнуться с нехваткой памяти. Чтобы узнать больше о SimpleXML прочтите документацию.

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

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL