Php прочитать xml файл в массив
Эта функция разбирает XML строку и помещает данные в 2 массива. Массив index содержит указатели на размещение значений в массиве values . Аргументы, задающие массивы, должны передаваться в функцию по ссылке.
Список параметров
Ссылка на используемый XML анализатор.
Строка XML данных.
Массив значений XML данных.
Массив указателей на соответствующие значения в массиве $values.
Возвращаемые значения
xml_parse_into_struct() возвращает 0 при неудачном разборе строки и 1 при успешном. Это не тоже самое, что FALSE и TRUE , будьте осторожны с такими операторами, как ===.
Примеры
Ниже представлен пример, демонстрирующий внутреннее устройство массивов, генерируемых функцией. XML строка содержит простой тэг note вложенный в тэг para. Программа в примере разбирает эту строку и выводит построенные массивы:
<?php$simple = "<para><note>simple note</note></para>" ;
$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 файл представляет небольшую базу данных с информацией об аминокислотах:
Код, разбирающий документ и создающий подходящие объекты: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 в ассоциативный массив. И, для работы этого способа, достаточно будет всего одной PHP функции (для чтения файла) - file_get_contents().
В этой статье вы узнаете, как конвертировать XML в массив на PHP.
Шаг 1: Исходный XML-файл
Хотелось сделать дефолтный пример, с дефолтным файлом, как делают в дефолтных статьях. Но сегодня я решил добавить в эту статью реальный пример из проекта.
Поставим перед собой задачу: нужно парсить курсы валют из API, которые отдаются в XML. Погуглив, я нашел API finance.ua, которое решает нашу задачу, и отдаёт такой XML-файл. И на его примере мы и будем рассматривать текущую тему.
Шаг 2: конвертируем содержимое XML-файла в строку
Для этого, как ранее и было написано, используется функция file_get_contents(). Присвоим содержимое файла переменной, для удобной работы с данными:
Шаг 3: конвертация XML строки в объект
Теперь, стандартными средствами PHP, можно XML-строку преобразовать в объект, в котором к тегам можно обращаться по цепочке свойств объекта, например:
Для этого воспользуемся функцией simplexml_load_string(), которой нужно передать XML строку:
И, обычно, в таком виде уже работают с XML-объектом, вызывая нужные методы/цепочки свойств. Но, в таком виде, работа с XML не всегда очевидна, особенно для новичков, потому, многие стремятся к тому, чтобы конвертировать XML в массив, так как это более привычный и удобный вариант работы с данными. И, к сожалению, в объекте $xml_data не существует магического метода ->toArray() , который конвертировал бы всю цепочку элементов в ассоциативный массив. Но, мы знаем, как сделать это самим.
Шаг 4: Конвертация XML-объекта в ассоциативный массив
Теперь текущий объект $xml_data нужно преобразовать в JSON с помощью функции json_encode() .
После чего, нужно выполнить обратные действия, т.е. декодировать JSON в массив, используя функция json_decode() :
Здесь может показаться немного нелогичным то, что сначала вызывается функция json_encode , а после чего, сразу json_decode . Но учитывая механику работы этих функций, всё сразу же становится на свои места.
json_encode - вырезает все лишние свойства, и конвертирует объект в JSON строку, оставляя только полезные данные
json_decode - преобразует JSON строку в массив
И, учитывая, что все ненужные данные были вырезаны, то ассоциатиыный массив, не содержит ничего лишнего:
Чего уже вполне достаточно для использования на практике, оперируя массивом.
Теперь в массиве все атрибуты элементов доступны под ключом @attributes, а элементы под ключом имени:
Резюме
Вот так, оказывается просто можно преобразовать XML в ассоциативный массив. Нам для этого понадобилось не больше, чем 4 строки:
И, помимо того, что вы теперь знаете, как происходит преобразование XML в массив, вы так же знаете, откуда спарсить курсы валют ^^.
Я хочу преобразовать XML в массив PHP. Есть предложения, как я могу это сделать?
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd />
<eeee name="hearaman" age="24" />
</cccc>
</bbb>
</aaaa>
Ответ 1
Используя расширение SimpleXML (я считаю, что оно входит в стандартную комплектацию большинства установок php).
Синтаксис для вашего примера выглядит примерно так:
$xml = new SimpleXMLElement($xmlString);
echo $xml->bbb->cccc->dddd['Id'];
echo $xml->bbb->cccc->eeee['name'];
// или.
foreach ($xml->bbb->cccc as $element)
foreach($element as $key => $val)
echo ": ";
>
>
Ответ 2
Преобразование строки XML( $buffer ) в упрощенный массив без учета атрибутов и группировки дочерних элементов с одинаковыми именами:
function XML2Array(SimpleXMLElement $parent)
$array = array();
foreach ($parent as $name => $element)
($node = & $array[$name])
&& (1 === count($node) ? $node = array($node) : 1)
&& $node = & $node[];
$node = $element->count() ? XML2Array($element) : trim($element);
>
return $array;
>
xml = simplexml_load_string($buffer);
$array = XML2Array($xml);
$array = array($xml->getName() => $array);
Результат:
Array (
[aaaa] => Array (
[bbb] => Array (
[cccc] => Array (
[dddd] =>
[eeee] =>
)
)
)
)
Если вам также нужны атрибуты, они доступны через JSON-кодирование/декодирование SimpleXMLElement. Это часто является наиболее простым и быстрым решением:
$xml = simplexml_load_string($buffer);
$array = json_decode(json_encode((array) $xml), true);
$array = array($xml->getName() => $array);
Результат:
Array (
[aaaa] => Array (
[@attributes] => Array (
[Version] => 1.0
)
[bbb] => Array (
[cccc] => Array (
[dddd] => Array (
[@attributes] => Array (
[Id] => id:pass
)
)
[eeee] => Array (
[@attributes] => Array (
[name] => hearaman
[age] => 24
)
)
)
)
)
)
Обратите внимание, что все эти методы работают только в пространстве имен XML-документа.
Ответ 3
Метод, используемый в принятом ответе, отбрасывающий атрибуты при встрече с дочерними элементами, имеющими только текстовый узел. Например:
$xml = '<container><element attribute="123">abcd</element></container>';
print_r(json_decode(json_encode(simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA)),1));
Array (
[element] => abcd
)
Мое решение:
function XMLtoArray($xml)
$previous_value = libxml_use_internal_errors(true);
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false;
$dom->loadXml($xml);
libxml_use_internal_errors($previous_value);
if (libxml_get_errors())
return [];
>
return DOMtoArray($dom);
>
function DOMtoArray($root)
$result = array();
if ($root->hasAttributes())
$attrs = $root->attributes;
foreach ($attrs as $attr)
$result['@attributes'][$attr->name] = $attr->value;
>
>
if ($root->hasChildNodes())
$children = $root->childNodes;
if ($children->length == 1)
$child = $children->item(0);
if (in_array($child->nodeType,[XML_TEXT_NODE,XML_CDATA_SECTION_NODE]))
$result['_value'] = $child->nodeValue;
return count($result) == 1
? $result['_value']
: $result;
>
>
$groups = array();
foreach ($children as $child)
if (!isset($result[$child->nodeName]))
$result[$child->nodeName] = DOMtoArray($child);
> else
if (!isset($groups[$child->nodeName]))
$result[$child->nodeName] = array($result[$child->nodeName]);
$groups[$child->nodeName] = 1;
>
$result[$child->nodeName][] = DOMtoArray($child);
>
>
>
return $result;
>
$xml = '
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd />
<eeee name="john" age="24" />
<ffff type="employee">Supervisor</ffff>
</cccc>
</bbb>
</aaaa>
';
print_r(XMLtoArray($xml));
Array (
[aaaa] => Array (
[@attributes] => Array (
[Version] => 1.0
)
[bbb] => Array (
[cccc] => Array (
[dddd] => Array (
[@attributes] => Array (
[id] => 123
)
)
[eeee] => Array (
[@attributes] => Array (
[name] => john
[age] => 24
)
)
[ffff] => Array (
[@attributes] => Array (
[type] => employee
)
[_value] => Supervisor
)
)
)
)
)
Ответ 4
<?php
/**
* преобразование xml-строки в php-массив - для получения сериализуемого значения
*
* @param string $xmlstr
* @return array
*
*/
function xmlstr_to_array($xmlstr)
$doc = new DOMDocument();
$doc->loadXML($xmlstr);
$root = $doc->documentElement;
$output = domnode_to_array($root);
$output['@root'] = $root->tagName;
return $output;
>
function domnode_to_array($node)
$output = array();
switch ($node->nodeType)
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i=0, $m=$node->childNodes->length; $i<$m; $i++)
$child = $node->childNodes->item($i);
$v = domnode_to_array($child);
if(isset($child->tagName))
$t = $child->tagName;
if(!isset($output[$t]))
$output[$t] = array();
>
$output[$t][] = $v;
>
elseif($v || $v === '0')
$output = (string) $v;
>
>
if($node->attributes->length && !is_array($output)) < // Имеет атрибуты, но не является массивом
$output = array('@content'=>$output); //Измените вывод в массив.
>
if(is_array($output))
if($node->attributes->length)
$a = array();
foreach($node->attributes as $attrName => $attrNode)
$a[$attrName] = (string) $attrNode->value;
>
$output['@attributes'] = $a;
>
foreach ($output as $t => $v)
if(is_array($v) && count($v)==1 && $t!='@attributes')
$output[$t] = $v[0];
>
>
>
break;
>
return $output;
>
Ответ 5
Мне понравился этот вопрос, и некоторые ответы были мне полезны, но мне нужно преобразовать xml в один доминирующий массив, поэтому я опубликую свое решение, возможно, оно кому-то понадобится позже:
<?php
$xml = json_decode(json_encode((array)simplexml_load_string($xml)),1);
$finalItem = getChild($xml);
var_dump($finalItem);
function getChild($xml, $finalItem = [])
foreach($xml as $key=>$value)
if(!is_array($value))
$finalItem[$key] = $value;
>else
$finalItem = getChild($value, $finalItem);
>
>
return $finalItem;
>
?>
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
Зачем нужен XML при парсинге? Иногда бывает так, что сайт, который вам нужно спарсить, имеет API, с помощью которого можно получить желаемое, особо не напрягаясь. Поэтому сразу совет - перед тем, как парсить сайт, проверьте, нету ли у него API.
Что такое API? Это набор функций, с помощью которых вы можете слать запрос этому сайту и получать нужный ответ. Вот этот ответ чаще всего приходит в формате XML. Поэтому давайте приступим к его изучению.
Работа с XML в PHP
Пусть у вас есть XML. Он может быть в строке, либо хранится в файле или отдаваться по запросу к определенному URL.
Пусть XML хранится в строке. В этом случае из этой строки нужно создать объект с помощью new SimpleXMLElement:
Сейчас у нас в переменной $xml хранится объект с разобранным XML. Обращаясь к свойствам этого объекта можно получать доступ с содержимому тегов XML. Как именно - разберем чуть ниже.
Если же XML хранится в файле или отдается по обращению к URL (что чаще всего и бывает), то следует использовать функцию simplexml_load_file, которая делает тот же объект $xml:
Приемы работы
В примерах ниже наш XML хранится в файле или по URL.
Пусть дан следующий XML:
Давайте получим имя, возраст и зарплату работника:
Как вы видите, у объекта $xml есть свойства, соответствующие тегам.
Вы может обратили внимание, что тег <worker> нигде не фигурирует при обращении. Это потому, что он корневой тег. Можно переименовать его, например, на <root> - и ничего не поменяется:
Корневой тег в XML может быть только один, так же, как и тег <html> в обычном HTML.
Давайте чуть модифицируем наш XML:
В этом случае у нас получится цепочка обращений:
Работа с атрибутами
Пусть некоторые данные хранятся в атрибутах:
Теги с дефисами
В XML разрешены теги (и атрибуты) с дефисом. В этом случае обращение к таким тегам происходит так:
Перебор циклом
Пусть теперь у нас не один работник, а несколько. В этом случае мы можем перебрать наш объект с помощью цикла foreach:
Из объекта в нормальный массив
Если вам неудобно работать с объектом, вы можете преобразовать его в нормальный массив PHP с помощью следующего хитрого приема:
Больше информации
Парсинг на основе sitemap.xml
Зачастую на сайте есть файл sitemap.xml. В этом файле хранятся ссылки на все страницы сайта для удобства индексации их поисковыми системами (индексация - это по сути и есть парсинг сайта яндексом и гуглом).
В общем-то нас мало должно волновать, зачем нужен этот файл, главное, что если он есть - можно не лазить по страницам сайта какими-либо хитрыми методами, а просто воспользоваться этим файлом.
Если sitemap есть - то в нем содежатся ссылки на все страницы сайта в формате XML. Спокойно забираете этот XML, парсите его, отделяете ссылки на нужные вам страницы любым удобным вам способом (например, анализом URL, который был описан в методе паука).
В итоге вы получаете список ссылок для парсинга, остается только зайти на них и спарсить нужным вам контент.
Читайте также: