Php прочитать xml файл в массив
В этой статье я покажу простой пример того, как прочитать данные их CSV-файла, и записать их в массив для дальнейшей работы с данными. Мы напишем простой код по парсингу CSV на PHP, которую можно будет использовать конвертации CSV-данных в массив, или JSON.
Прежде всего, разберёмся, что за формата такой этот CSV. Это формат хранения данных в текстовом документе, где каждая запись записывается с новой строки, в которой все значения разделены запятой (отсюда и имеем название формата - Comma Separated Values).
Итогово, CSV-формат состоит из переносов на новую строку и запятых, и это всё, что вам нужно знать.
Формата записи CSV можно увидеть на примере:
На примере, первая колонка - это ID пользователя, вторая - логин, и последняя - возраст пользователя. Как можете видеть, каждый пользователь отделён переносом на новую строку.
Зная своего врага в лицоПонимая, что это обычная строка, мы уже можем распарсить CSV, используя PHP функции для работы со строкой. Забегая наперёд, скажу, что в PHP есть встроенные средства по парсингу CSV (её мы рассмотрим дальше, сравнивая 2 разных подхода).
Потому, для полного понимания, как происходит чтение CSV файла построчно, напишем код, без использования встроенных решений парсинга CSV на PHP:
И теперь, на просмотерв этот код, вы знаете, как читать CSV файлы на PHP, используя обычные функции работы со строкой.
Converter
Есть способ проще. Достаточно XML-документ привести к массиву. В работе с массивами нет ни каких подводных камней. Массив из XML делается в пару строчек кода:
Каждый XML-элемент будет представлен массивом, состоящим в свою очередь, из трёх других массивов.
массив с индексом '*value' содержит значение элемента,
'*attributes' - атрибуты элемента,
'*elements' - вложенные элементы.
Если элемент множественный, то есть встречается в документе несколько раз подряд, то все его вхождения будут в массиве с индексом '*multiple'.
Но и это ещё не всё.
Эпилог
Конечно у вас могут быть свои альтернативы для работы с XML. Предлагаю поделиться в комментариях.
Конечно, не могу сказать, что XmlNavigator поможет с любым XML - не проверял, но с обычными документами, без хитростей в схеме документа, проблем не было.
Если вам важен порядок следования элементов, то придётся пользоваться XMLReader. Потому что SimpleXMLElement приводит документ к объекту, а у объекта нет такого понятия как порядок следования элементов.
В личной практике задача разбирать XML средствами PHP возникла еще в 2005. Однако, при попытке разобраться и написать несложный скрипт, загружающий XML-файл в массив, я наткнулся на довольно серьёзную проблему – не существует нормальных программных средств и бинарных библиотек PHP для работы с XML. По мере работы с XML средствами PHP и эволюции PHP применялись различные технологии разбора XML кода, о них далее и пойдет речь.
Сперва приведу сводную таблицу совместимости средств PHP и библиотек XML.
Самым совместимым оказался SAX (Simple API for XML), он поддерживается даже в библиотеке EXPAT имеющейся во всех версиях PHP 4 и выше. Однако его возможности и способы применения вызвали резко негативную реакцию – нет возможности модификации XML, крайне громоздкий и сложный код с большим количеством мест для потенциальных ошибок.
DOMXML ужасная вещь, т.к. существовала в виде дополнительных экспериментальных библиотек для PHP 4. В PHP 5 не включена, т.к. PHP 5 по умолчанию обладает более универсальным средством DOM (Стандарт W3C DOM level 3). DOM наиболее документирован (English PHP & W3C) и завершен, однако не включен в PHP 4, т.к. был разработан только к началу 2006. Если выбор станет DOM или PHP4, однозначно следует сказать DOM, т.к. на сегодняшний день PHP 5 имеется у любого уважающего себя хостинг провайдера. Тем более у разработчика, есть возможность писать PHP 4 совместимый код, т.к. PHP 4 обладает базовой DOM и она поддерживает некоторые основные функции новой DOM.
Существуют ещё дополнительные библиотеки XML-RPC, но они являются экспериментальными, что говорит само за себя – их тестирование и пробы возможны не ранее чем в 2009 году.
В Рунете небыло никакой более-менее полезной литературы на тот момент (осень 2007), все разработчики наповал использовали SAX (часто даже свои библиотеки базирующиеся на SAX) либо DOMXML. О DOM ещё мало кто слышал, а те, кто слышал, отказывались от использования в пользу более старого и менее стандартного, но более привычного DOMXML. Таким образом, имелся крайне низкий уровень реализации и переносимость существующих WEB решений использующих XML. Решение использовать новое, удобное, одобренное W3C средство DOM, было единственно правильным. DOM в PHP по его совместимости и взаимопониманию идентичен DOM'у в JS.
Проведем сравнительный анализ производительности SAX PHP 4 и DOM PHP 5. Будет произведен замер времени разбора следующего XML-файла.
$GLOBALS['sax']['links'] = array(); // В этом массиве будут храниться блоки ссылок, полученные из XML файла
$GLOBALS['sax']['current_linksblock']=null;// Текущий блок ссылок. Используется в процессе импорта данных
$GLOBALS['sax']['page_r'] =0;
$GLOBALS['sax']['page_i'] =-1;
$GLOBALS['sax']['link_r'] =0;
$GLOBALS['sax']['link_i'] =-1;
$GLOBALS['sax']['index'] =null;// Текущий индекс в массиве ссылок.
// Используется в процессе импорта данных
if (xml_parse($parser,$xml,true))
// Уничтожаем парсер, освобождая занятые им ресурсы
xml_parser_free($parser);
//else
// Парсер возвращает значение FALSE, если произошла
// какая-либо ошибка. В этом случае мы также прекращаем
// выполнение скрипта и возвращаем ошибку.
// die(sprintf('AOW - Ошибка XML: %s в строке %d',
// xml_error_string(xml_get_error_code($parser)),
// xml_get_current_line_number($parser)));
//Получили массив из XML $GLOBALS['sax']['links']; содержащий полный набор необходимых данных
dbg($GLOBALS['sax']['links'],"results");
// Функция для обработки символьных данных
// На входе:
// - указатель на SAX парсер
// - символьные данные XML
function saxCharacterData($parser,$data) // Мы принимаем только данные для блоков ссылок, помещенные в
// какой-нибудь тег. Все остальные символьные данные
// (как правило это пустое пространство, использованное
// для форматирования) мы опускаем за ненадобностью.
if (is_array($GLOBALS['sax']['current_linksblock'])) //Если открыт тег page то пишем в массив строки, склеивая их
if($GLOBALS['sax']['page_r']) $GLOBALS['sax']['current_linksblock']['page'][$GLOBALS['sax']['page_i']].= iconv("UTF-8", "windows-1251", $data);
> elseif($GLOBALS['sax']['link_r']) //Если открыт тег link то пишем в массив строки, склеивая их
$GLOBALS['sax']['current_linksblock']['link'][$GLOBALS['sax']['link_i']].= iconv("UTF-8", "windows-1251", $data);
>
>
>
//-------------------------------------------------------------------------------------
Недостатки этого метода разбора XML очевидны: громоздкость, неудобочитаемость программного кода и необходимость использования глобальных переменных.
Приведем 2 метода разбора того же XML файла, базирующиеся на DOM PHP 5.
Метод 1
/* here we must specify the version of XML : i.e: 1.0 */
$xml = new DomDocument('1.0');
$xml->load($link_file);
$linksblocksa = array();
$i=0;
foreach($xml->documentElement->childNodes as $XMLlinksblock) if ($XMLlinksblock->nodeType == 1 && $XMLlinksblock->nodeName == "linksblock") $linksblocksa[$i]['attributes']=array();
foreach($XMLlinksblock->attributes as $attr)
$linksblocksa[$i]['attributes'][$attr->name]= $attr->value;
Метод использует физическую безадресную навигацию по дереву XML документа.
Метод 2
/* here we must specify the version of XML : i.e: 1.0 */
$xml = new DomDocument('1.0');
$xml->load($link_file);
$i=0;
foreach($xml->getElementsByTagName('linksblock') as $XMLlinksblock) $linksblocksb[$i]['attributes']=array();
foreach($XMLlinksblock->attributes as $attr)
$linksblocksb[$i]['attributes'][$attr->name]= $attr->value;
foreach($XMLlinksblock->getElementsByTagName('page') as $page)
$linksblocksb[$i]['page'][]= $page->nodeValue;
foreach($XMLlinksblock->getElementsByTagName('link') as $link)
$linksblocksb[$i]['link'][]= iconv("UTF-8", $GLOBALS['E_server_encoding'], $link->nodeValue);
$i++;
>
unset($xml);
dbg($linksblocksb,"linksblocksb");
Метод использует ассоциативно-адресную навигацию по дереву XML документа.
В заключении замечу, что все три алгоритма в результате получают абсолютно идентичные массивы данных:
Тесты производительности алгоритмов производились с учетом следующих условий:
Платформа AMD Athlon(tm) 64 X2 Dual Core Processor 4200+, DDR 2 1024 MB.
Веб-сервер Windows NT 5.1 build 2600, Apache/1.3.33 (Win32) PHP/5.1.6.
График производительности позволяет сделать следующие заключения: SAX наиболее стабилен и его производительность не зависит ни от положения в теле программы, ни от нагрузки на сервер.
Рассмотрим среднеквадратичные показатели производительности для каждой группы тестов.
1-SAX Произв 1
2-DOM 1 Произв 2
3-DOM 2 Произв 3
Make — режим сборки, Run 10 times — режим нагрузки.
1)Make 2-3-1(порядок следования)
2)Run 10 times 2-3-1(порядок следования)
3)Make 3-2-1(порядок следования)
4)Run 10 times 3-2-1(порядок следования)
5)Make 1-2-3(порядок следования)
6)Run 10 times 1-2-3(порядок следования)
7)Make 1-3-2(порядок следования)
8)Run 10 times 1-3-2(порядок следования)
Очевидно, что наиболее важным на данном этапе анализа является выявление наиболее производительного метода разбора XML основанного на DOM, SAX не рассматриваем, т.к. его отставание и недостатки очевидны.
Напомню, метод 1 использует физическую безадресную навигацию по дереву XML документа, менее удобочитаем, чем метод 2, который использует ассоциативно-адресную навигацию по дереву XML документа.
Для нас наиболее важны режимы результаты производительности при режимах нагрузки, такими являются четные тесты:
Тесты 2 и 6, тесты в которых метод 1 идет первым, тесты 4 и 8, тесты в которых метод 2 идет первым.
Из графика следует, что при своем удобстве метод 2 достигает наивысших показателей производительности, только при многочисленном использовании XML в программе.
Метод 1, при меньшей лаконичности и пиковой производительности относительно метода 2, является более стабильным в использовании для разбора в единственном месте работы PHP скрипта.
Таким образом, переход на DOM PHP 5, в независимости от способа разбора XML документа, вполне оправдан, как по удобству кода, так и по производительности, тем более, с учетом того, что в настоящее время PHP 4 практически не используется.
Все тесты проводились кустарно, их основной задачей было показать различие а не количественные характеристики производительности того или иного парсера, очевидно, что при грамотной настройке кэширующих механизмов результаты могут отличаться.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago .
So my adoption for an XML strings is like:
It works pretty well, but it seems a bit hacky? Is there a more efficient/robust way of doing this?
I know that the SimpleXML Object is close enough to an array because it makes use of the ArrayAccess interface in PHP but it still doesn't work great to use as an array with multi-dimensional arrays i.e. looping.
Thanks all for any help
What's the reason for it? Is it looping? Because in that case you should be able to loop parts of the SimpleXMLElement object without any problems. For example if you're parsing an ATOM feed with SimpleXML you'd be able to do the following: foreach($xml->entry as $entry) and then access $entry->title et.c. from within the loop.
Note that adding (array) to the above (i.e. @json_decode(@json_encode((array)$simple_xml_object ), 1); ) as noted in a later comment in the PHP manual may cause Node no longer exists errors.
what's this question about? json_encode does tree traversal on the simplexml element. What did you expect differently? How do you define "a bit hacky"? What is not robust with this approach in your eyes? What is not efficient?
Все методы класса XmlNavigator
Класс XmlNavigator реализует интерфейс IXmlNavigator.
Из названий методов очевидно их назначение. Не очевидные были рассмотрены выше.
Шаг 4: Конвертация XML-объекта в ассоциативный массив
Теперь текущий объект $xml_data нужно преобразовать в JSON с помощью функции json_encode() .
После чего, нужно выполнить обратные действия, т.е. декодировать JSON в массив, используя функция json_decode() :
Здесь может показаться немного нелогичным то, что сначала вызывается функция json_encode , а после чего, сразу json_decode . Но учитывая механику работы этих функций, всё сразу же становится на свои места.
json_encode - вырезает все лишние свойства, и конвертирует объект в JSON строку, оставляя только полезные данные
json_decode - преобразует JSON строку в массив
И, учитывая, что все ненужные данные были вырезаны, то ассоциатиыный массив, не содержит ничего лишнего:
Чего уже вполне достаточно для использования на практике, оперируя массивом.
Теперь в массиве все атрибуты элементов доступны под ключом @attributes, а элементы под ключом имени:
2 Answers 2
It could help you. However, if you convert XML to an array you will loose all attributes that might be present, so you cannot go back to XML and get the same XML.
@Arjan: You missed to do proper attribution of copyright holders and the author. I also added some licensing docblock tags for convenient reasons. Please take care when you copy over code-examples from the PHP manual here on the website. They are compatible from the license, but they require attribution. As CC are not specifically designed for software, the code-examples are most likely not usable in real-life occasions, they are just usable to show/explain something. If you do not attribute and hide the copyright holders, this often gets lost.
Работая над своим последним проектом, у меня появилась острая необходимость в парсинге xml-файла, и конвертации его в ассоциативный массив. Прежде всего хотелось сделать это всё без использования сторонних библиотек, исключительно нативными средствами PHP. И в этой статье я покажу, что у меня получилось, и как конвертировать xml в ассоциативный массив.
Решений этой проблемы, найденных в гугле было достаточно. Я нашел несколько разных способов, несколько библиотек, которые решали мои задачи. Но, как я уже написал выше, мне хотелось что-то простое, эффективное, и без использования сторонних библиотек. И, как мне кажется, я нашел оптимальный вариант конвертации XML в ассоциативный массив. И, для работы этого способа, достаточно будет всего одной PHP функции (для чтения файла) - file_get_contents().
В этой статье вы узнаете, как конвертировать XML в массив на PHP.
XMLReader
С помощью XMLReader парсинг будет выглядеть примерно так :
Внутри метода parse(XMLReader $xml) будут бесконечные:
Для небольших документов или когда нам из всего документа надо только пару элементов, это приемлемо, на больших объёмах - начинает в глазах рябить от однообразного кода, плюс совесть грызёт за оверхэд от перебора всех элементов документа.
Шаг 1: Исходный XML-файл
Хотелось сделать дефолтный пример, с дефолтным файлом, как делают в дефолтных статьях. Но сегодня я решил добавить в эту статью реальный пример из проекта.
Поставим перед собой задачу: нужно парсить курсы валют из API, которые отдаются в XML. Погуглив, я нашел API finance.ua, которое решает нашу задачу, и отдаёт такой XML-файл. И на его примере мы и будем рассматривать текущую тему.
Заключение
В работе приходиться использовать сначала SimpleXMLElement - с его помощью из всего документа получаем необходимый элемент, и уже с этим элементом работаем через XmlNavigator.
Желаю вам приятного использования.
Парсинг CSV на примере встроенной функции fgetcsv
В PHP есть встроенная функция fgetcsv, которая облегчает работу по парсингу CSV-файлов. Эта функция избавляет нас от лишней работы, от "низкоуровневого" парсинга строки. Эта функция автоматически распарсит CSV поля и строки, сохраняя данные в массив.
Перепишем код, написанный ранее, используя функцию fgetcsv:
Когда вы запустите этот код, вы сможете увидеть, что в переменной $row находится массив, содержащий данные каждой из колонок. И любое значение можно будет получить, работая как с обычным массивом, получая элемент по его соответствующему индексу.
Рассматривая на примере моих исходных данных, каждая строка CSV-данных имеет 3 колонки, данные из которых можно прочитать, вызвав: $row[0] , $row[1] , $row[2] .
Так же, можете заметить, что функция fgetcsv облегчила нам работу, выполняя всю чёрную работу по парсингу самостоятельно (в отличии от варианта, который рассматривался вначале).
Резюме
В этой статье я подробно рассказал, как можно работать с CSV в PHP, какими способами парсить, и как отображать данные, полученные из CSV. Писал максимально подробно и вариативно, надеюсь, вопросов не осталось ^^.
Всем привет. Хочу поделиться своим опытом в парсинге XML, хочу рассказать об инструменте который мне в этом помогает.
XML ещё жив и иногда его приходиться парсить. Особенно если вы работаете со СМЭВ (привет всем ребятам для которых "ФОИВ" не пустой звук :) ).
Цели у такого парсинга могут быть самые разные, от банального ответа на вопрос какое пространство имён используется в xml-документе, до необходимости получить структурированное представление для документа вцелом.
Инструмент для каждой цели будет свой. Пространство имён можно найти поиском подстроки или регулярным выражением. Что бы сделать из xml-документа структурированное представление (DTO) - придётся писать парсер.
Для работы с XML в PHP есть пара встроенных классов. Это XMLReader и SimpleXMLElement.
XmlNavigator
Если от работы с XML-документов как с массивом, у вас в глазах рябит от квадратных скобочек, то XmlNavigator - это ваш вариант, создаётся так же в две строки кода.
XmlNavigator делает, то же самое что и Converter, но предоставляет API, и с документом мы работаем как с объёктом.
Имя элемента, метод name()
Значение элемента, метод value()
Список атрибутов, метод attribs()
Значение атрибута, метод get()
Список вложенных элементов, метод elements()
Получить вложенный элемент, метод pull()
Перебрать все вхождения множественного элемента, метод next()
Шаг 3: конвертация XML строки в объект
Теперь, стандартными средствами PHP, можно XML-строку преобразовать в объект, в котором к тегам можно обращаться по цепочке свойств объекта, например:
Для этого воспользуемся функцией simplexml_load_string(), которой нужно передать XML строку:
И, обычно, в таком виде уже работают с XML-объектом, вызывая нужные методы/цепочки свойств. Но, в таком виде, работа с XML не всегда очевидна, особенно для новичков, потому, многие стремятся к тому, чтобы конвертировать XML в массив, так как это более привычный и удобный вариант работы с данными. И, к сожалению, в объекте $xml_data не существует магического метода ->toArray() , который конвертировал бы всю цепочку элементов в ассоциативный массив. Но, мы знаем, как сделать это самим.
Как установить?
Преобразование CSV в массив
Теперь, понимая, как парсить CSV, покажу код преобразования CSV в ассоциативный массив. Используем предыдущий код, немного его дополним:
На этом примере, я показал, как конвертировать csv в массив, а так же, как конвертировать CSV в JSON.
SimpleXMLElement
Провести анализ только нужных элементов помогает SimpleXMLElement. Этот класс из XML-документа делает объект, у которого все элементы и атрибуты становятся свойствами, то есть появляется возможность работать только с определёнными элементами, а не со всеми подряд, пример:
Удобно, да не совсем. Если имя элемента на кириллице, то обратиться к нему через свойство не получиться, придётся использовать SimpleXMLElement::xpath(). С множественными значениями так же приходиться работать через SimpleXMLElement::xpath(). Кроме того SimpleXMLElement имеет свои особенности и некоторые вещи далеко не очевидны.
Шаг 2: конвертируем содержимое XML-файла в строку
Для этого, как ранее и было написано, используется функция file_get_contents(). Присвоим содержимое файла переменной, для удобной работы с данными:
Резюме
Вот так, оказывается просто можно преобразовать XML в ассоциативный массив. Нам для этого понадобилось не больше, чем 4 строки:
И, помимо того, что вы теперь знаете, как происходит преобразование XML в массив, вы так же знаете, откуда спарсить курсы валют ^^.
Читайте также: