Немного о компьютере

Обработка SimpleXML с помощью PHP. Обработка SimpleXML с помощью PHP Simplexml load string не работает

SimpleXMLElement->asXML

SimpleXMLElement->asXML -- Возвращает правильно сформированный XML-документ

Описание

Mixed SimpleXMLElement->asXML ()

Метод asXML формирует данные в XML версии 1.0.

Список параметров
filename
Если указан, то метод запишет данные в указанный файл.
Возвращаемые значения
Если имя файла задано, то метод запишет XML данные в указанный файл. В противном случае метод возвратит XML-данные в виде строки.
Замечания
Если в исходном документе в заголовках была указана кодировка XML-документа при помощи параметра encoding, то метод asXML возвратит XML-документ в указанной кодировке. Изменение кодировки XML-документа при помощи расширения SIMPLEXML невозможно.
Примеры
Пример 1. Вывести XML

$string = <<

text
stuff


code

XML;

echo $xml->asXML(); // textstuff
...?>

Метод asXML также может работать с Xpath:

Пример 2. Использование метода asXML() в работе с Xpath

// Продолжение примера, указанного выше.
/* Поиск */
$result = $xml->xpath("/a/b/c");
while(list(, $node) = each($result)) {
echo $node->asXML(); // text и stuff
}
?>

SimpleXMLElement->attributes

SimpleXMLElement->attributes -- Возвращает атрибуты элемента.

Описание

SimpleXMLElement simplexml_element->attributes ()

Эта функция возвращает названия и значения атрибутов выбранного xml-элемента. Замечание: SimpleXML содержит правило добавления итеративных свойств к большинству методов. Они не могут быть просмотрены с испольванием var_dump() или каких-либо других средств анализа объектов.

Пример 1. Интепретация XML-строки

$string = <<
[email protected]

XML;
$xml = simplexml_load_string($string);
foreach($xml->users->attributes() as $a => $b) {
echo $a,"="",$b,"\"\n";
}
?>

Данный пример выведет:

Name="Evgen"
age="27

SimpleXMLElement->children

SimpleXMLElement->children -- Возвращает дочерние элементы для заданного элемента

Описание

SimpleXMLElement simplexml_element->children ()

Данный метод находит дочерние элементы для заданного элемента.

Замечание: SimpleXML содержит правило добавления итеративных свойств к большинству методов. Они не могут быть просмотрены с использованием var_dump() или каких-либо других средств анализа объектов.

Пример 1. Использование метода children()

$xml = simplexml_load_string(
"










");
echo "

    ";
    foreach ($xml->children() as $site) {
    echo "
    " . $site["name"];
    foreach ($site->children() as $subsite) {
    echo "
    " . $subsite["name"];
    }
    }
    echo "
";
?>

Данный пример выведет:

Php-spravka.ru
links.php-spravka.ru
forum.php-spravka.ru
server.php-spravka.ruyandex.ru
money.yandex.ru
map.yandex.ru
market.yandex.ru

SimpleXMLElement->xpath

SimpleXMLElement->xpath -- Выполняет Xpath-запрос к XML-данным

Описание

Array SimpleXMLElement->xpath (string path)

Метод xpath ищет дочерние элементы элемента SimpleXML, путь к которому указан в параметре path. Метод возвращает массив объектов SimpleXMLElement.

Пример 1. Xpath

$string = <<

text
stuff


code

plain



XML;
$xml = simplexml_load_string($string);
/* Поиск по */
$result = $xml->xpath("/a/b/c");
foreach ($result as $node) {
echo "/a/b/c: " . $node . "
";
}
/* Относительные дорожки также работают... */
$result = $xml->xpath("b/c");
foreach ($result as $node) {
echo "b/c: " . $node . "
";
}
?>

Данный скрипт выведет:

/a/b/c: text
/a/b/c: stuffb/c: textb/c: stuff

Два результата в данном случае одинаковы.

simplexml_import_dom (PHP 5)

simplexml_import_dom -- Возвращает объект SimpleXMLElement, созданный из DOM-объекта.

Описание

SimpleXMLElement simplexml_import_dom (DOMNode node [, string class_name])

Данная функция берет объект DOM и создает на его основе объект SimpleXML.

Этот новый объект может быть использован как нормальный объект SimpleXML.

Если во время создания объекта произошли ошибки, метод вернет false.

Пример 1. Import DOM

$dom = new domDocument;
$dom->loadXML("php-spravka.ru");
if (!$dom) {
echo "Ошибка парсинга документа!";
exit;
}
$s = simplexml_import_dom($dom);
echo $s->site->url; // php-spravka.ru
?>

simplexml_load_file (PHP 5)

simplexml_load_file -- Интерпретирует XML-файл в объект

Описание

Object simplexml_load_file (string filename [, string class_name [, int options]])

Эта функция интерпретирует файл filename с правильно сформированными XML-данными в объект SimpleXMLElement. Если в XML-данных имеются ошибки, функция возвратит FALSE.

Вы можете использовать необязательный параметр class_name в функции simplexml_load_file() для того, чтобы функция вернула объект указанного класса. При этом класс должен быть расширением класса SimpleXMLElement.

Начиная с PHP 5.1.0 и Libxml 2.6.0 вы можете использовать необязательный параметр options, спецификация которого описана в additional Libxml parameters.

Замечание: Libxml 2 преобразовывает URL к правильному виду. Т.е. если вы хотите присвоить переменной а значение b&c в URL-строке, вам не обязательно делать:

Simplexml_load_file(rawurlencode("http://example.com/?a=" . urlencode("b&c"))).

Начиная с PHP 5.1.0 это делается в автоматическом режиме.

Пример 1. Интерпретация XML документа

// Файл test.xml содержит XML документ с корневым элементом
// и вложенным элементом title //title.if (file_exists("test.xml")) {
$xml = simplexml_load_file("test.xml");

Var_dump($xml);
} else {
exit("Ошибка открытия test.xml.");
}
?>
Этот пример выведет следующее: SimpleXMLElement Object(
=> Тестовый заголовок
...
)

В данном примере вы можете обратиться к элементу title следующим образом: $xml->title.

simplexml_load_string(PHP 5)

simplexml_load_string -- Интерпретирует строку с XML в объект

Описание

Object simplexml_load_string (string data [, string class_name [, int options]])

Эта функция берет "правильный" XML-документ, находящийся в строке data и возвращает объект класса SimpleXMLElement, имеющий свойства, равные содержимому xml-документа. Если XML-документ имеет ошибки, функция возвратит FALSE.

Вы можете использовать необязательный параметр class_name для того, чтобы функция simplexml_load_string() вернула объект заданного класса. Этот класс должен расширять класс SimpleXMLElement.

Начиная с PHP 5.1.0 и Libxml 2.6.0, вы можете также использовать необязательный параметр options, содержимое которого определено в additional Libxml parameters.

Пример 1. Преобразование XML-строки

$string = <<

Forty What?
Joe
Jane



XML;
$xml = simplexml_load_string($string);
var_dump($xml);
?>
Этот пример выведет: SimpleXMLElement Object(
=> Forty What?
=> Joe
=> Jane
=>
I know that"s the answer -- but what"s the question?
)

В этом примере вы можете также использовать конструкции $xml->body и т.д.

Библиотека для разметки для обработки XML с помощью PHP

PHP версии 5 представляет SimpleXML, новый интерфейс прикладного программирования (API) для чтения и письма в XML. Расширения SimpleXML, такие как

$doc->rss->channel->item->title

выбирают элементы из документа. Пока вы имеете хорошее представление о структуре вашего документа, писать эти выражения легко. Однако, если вы не знаете точно, где интересующие вас элементы появляются (как например, в случае с Docbook, HTML и другими подобными текстовыми документами), SimpleXML может пользоваться выражениями XPath для поиска этих элементов.

Начало работы с SimpleXML

Представим себе, что вы хотите создать страницу PHP, которая конвертирует канал RSS в HTML код. RSS является основным форматом XML для публикации содержания, взятого из нескольких источников. Корневой элемент этого документа – rss , который содержит единственный элемент channel . Элемент channel содержит метаданные о содержимом, включая его заголовок, язык и URL. Он также содержит разнообразные текстовые элементы, вложенные в элементы item . Каждый элемент item имеет элемент link , содержащий URL или title , или description (обычно оба), в которых находится читаемый текст. Области имен не используются. Конечно, ещё много чего можно сказать об RSS, но для целей этой статьи информации достаточно. показывает типичный пример с парой информационных сообщений.

Листинг 1. Канал RSS
Mokka mit Schlag http://www.elharo.com/blog en Penn Station: Gone but not Forgotten The old Penn Station in New York was torn down before I was born. Looking at these pictures, that feels like a mistake. The current site is functional, but no more; really just some office towers and underground corridors of no particular interest or beauty. The new Madison Square... http://www.elharo.com/blog/new-york/2006/07/31/penn-station Personal for Elliotte Harold Some people use very obnoxious spam filters that require you to type some random string in your subject such as E37T to get through. Needless to say neither I nor most other people bother to communicate with these paranoids. They are grossly overreacting to the spam problem. Personally I won"t... http://www.elharo.com/blog/tech/2006/07/28/personal-for-elliotte-harold/

Давайте сделаем страницу PHP, которая форматирует каждый RSS канал как HTML. показывает структуру будущей страницы.

Листинг 2. Статическая структура для PHP-кода
<?php // Заголовок будет читаться из RSS ?>

Анализ XML-документа

Первый шаг – анализ XML-документа и его сохранение в переменной. Это требует написания всего лишь одной строки кода, которая передает URL функции simplexml_load_file() :

$rss = simplexml_load_file("http://partners.userland.com/nytRss/nytHomepage.xml");
Предупреждение

Схема, использованная здесь, опасно далека от оптимальной. Мне, на самом деле, не следует загружать и анализировать канал RSS каждый раз, когда на страницу заходят. Это замедляет работу читателей страницы и грозит потенциальным отказом в обслуживании каналов RSS, которые я загружаю, так как большинство из них устанавливают максимальную частоту обновлений приблизительно один раз в час. Реальным решением этой проблемы является помещение в кэш-память или созданной страницы HTML, или каналов RSS или и того и другого. Однако этот вопрос идет в разрез с использованием SimpleXML библиотеки, поэтому я здесь немного приукрашиваю.

Для этого примера я взял страницу из Userland канала New York Times по адресу http://partners.userland.com/nytRss/nytHomepage.xml. Конечно, вы можете использовать вместо этого любой другой URL для другого канала RSS.

Заметьте, что несмотря на имя simplexml_load_file () , этой функции будет необходимо анализировать XML документ на удаленном HTTP URL. Но это не единственная неожиданность в этой функции. Возвращаемое значение функции, которое здесь хранится в переменной $rss , не указывает на весь документ, как вы могли бы ожидать, исходя из опыта работы с другими интерфейсами API, такими, как, например, Объектная модель документа (DOM). Скорее оно указывает на корневой элемент документа. Контент, который находится в прологе и эпилоге документа, недоступен из SimpleXML.

Нахождение имени канала

Имя всего канала (в отличие от заголовков отдельных текстовых фрагментов этого канала) находится в дочернем элементе title от элемента channel , порожденного корневым элементом rss . Вы можете загрузить этот заголовок, как будто бы XML-документ был бы просто последовательной формой объекта класса rss с полем channel , которое в свою очередь имело бы поле title . Используя регулярный PHP-синтаксис ссылки на объект, этот оператор находит заголовок:

$title = $rss->channel->title;

Найдя заголовок, вы должны добавить его к выходным данным HTML. Сделать это просто: повторите переменную $title:

<?php echo $title; ?>

Эта строка выводит строковое значение элемента, но не весь элемент. То есть текст записывается, а теги нет.

Вы можете даже полностью пропустить промежуточную переменную $title:

<?php echo $rss->channel->title; ?>

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

Выполнение итераций через элементы

$rss->channel->item

Однако каналы обычно содержат больше, чем один элемент. Или их даже может не быть вовсе. Соответственно, этот оператор возвращает массив, который вы можете повторить с помощью цикла for-each:

foreach ($rss->channel->item as $item) { echo "

". $item->title. "

"; echo "

". $item->description. "

"; }
Листинг 3. Простая, но полная программа считывания PHP RSS
channel->title; ?> <?php echo $title; ?>

channel->item as $item) { echo "

link. "">". $item->title. "

"; echo "

". $item->description. "

"; } ?>

Это все, что нужно, чтобы написать простую программу чтения RSS в PHP – несколько строк HTML и несколько строк PHP. Не считая пробелов, в общей сложности 20 строк. Конечно, это не самая широкофункциональная, оптимизированная или надежная разработка. Давайте посмотрим, что мы можем сделать, чтобы исправить это.

Обработка ошибок

Не все каналы RSS так хорошо сформированы, как это должно быть. Спецификация XML требует, чтобы процессоры прекратили обрабатывать документы, как только обнаружена формальная ошибка, а SimpleXML соответствовал программе обработки XML. Однако это вам особенно не поможет, когда будет обнаружена ошибка. Как правило, программа записывает предупреждение в файл php-ошибок (но без детального сообщения об ошибке), и функция simplexml-load-file() выдает ошибку. Если вы не уверены, что файл, который вы анализируете хорошо выстроен, проверьте на наличие этой ошибки, перед тем как использовать данные файла, как это показано в .

Листинг 4. Остерегайтесь деформированного ввода данных
xpath("//title") as $title) { echo "

". $title. "

"; } } else { echo "Упс! Ввод деформирован!"; } ?>

Другая распространенная ошибка случается, когда документ хорошо сформатирован, но не содержит те элементы, которые вы ожидаете там, где вы ожидаете их найти. Что происходит, например, с таким выражением $doc->rss->channel->item->title , когда элементная группа не имеет заголовка (как это случается, по меньшей мере, с одним из ста наиболее частотных RSS-каналов)? Самый простой подход – всегда обращаться с возвращаемым функцией значением как с массивом данных и заключать его в цикл. В этом случае вы защищены от факта наличия большего или меньшего количества элементов, чем вы ожидали. Однако, если вы знаете, что вы хотите первый элемент в документе, даже если там имеется больше чем один, вы можете запросить его через индекс, начинающийся с нуля. Например, для запроса заголовка первой группы элементов, вы можете написать:

$doc->rss->channel->item->title

Если первая группа элементов отсутствует, или не имеет названия, она рассматривается так же, как и любой другой, находящийся за установленными рамками индекс, в массиве PHP. То есть результат равен нулю, который превращается в пустую строку, когда вы попытаетесь вставить его в выходной код HTML.

Распознавание и отклонение неожиданных форматов, с которыми вы не готовы работать, обычно является сферой деятельности проверяющего на правильность парсера XML. Однако SimpleXML не может проверить относительно шаблона DTD (DTD) или схемы данных. Он проверяет только на формальную правильность.

Как работать с пространством имен

Многие сайты сегодня переходят с RSS на Atom. показывает пример документа в Atom. По многим параметрам этот документ идентичен примеру с RSS. Однако здесь больше метаданных, а корневой элемент - feed , вместо - rss . Элемент feed имеет списки вместо элементов. Элемент content заменяет элемент description . Гораздо важнее то, что документ Atom использует пространство имен, в то время как RSS нет. Таким образом, документ Atom может выводить реальное, не урезанное содержание Extensible HTML (XHTML).

Листинг 5. Документ в Atom
2006-08-04T16:00:04-04:00 http://www.cafeconleche.org/ Cafe con Leche XML News and Resources Copyright 2006 Elliotte Rusty Harold Steve Palmer has posted a beta of Vienna 2.1, an open source RSS/Atom client for Mac OS X.

Steve Palmer has posted a beta of Vienna 2.1, an open source RSS/Atom client for Mac OS X. Vienna is the first reader I"ve found acceptable for daily use; not great but good enough. (Of course my standards for "good enough" are pretty high.) 2.1 focuses on improving the user interface with a unified layout that lets you scroll through several articles, article filtering (e.g. read all articles since the last refresh), manual folder reordering, a new get info window, and an improved condensed layout.

http://www.cafeconleche.org/#August_1_2006_25279 2006-08-01T07:01:19Z
Matt Mullenweg has released Wordpress 2.0.4, a blog engine based on PHP and MySQL.

Matt Mullenweg has released Wordpress 2.0.4, a blog engine based on PHP and MySQL. 2.0.4 plugs various security holes, mostly involving plugins.

http://www.cafeconleche.org/#August_1_2006_21750 2006-08-01T06:02:30Z

Хотя имена элементов изменились, основной подход к работе с SimpleXML в документах в Atom такой же, как и с RSS. Единственная разница в том, что вам необходимо указать пространство имен, т.е. универсальный идентификатор ресурса (URI), когда вы запрашиваете элемент с именем, так же как и локальное имя. Это двухступенчатый процесс: во-первых, запросите дочерние элементы в данном пространстве имен, передав пространство имен URI функции children() . Затем запросите элементы с правильным местным именем в этом пространстве имени. Представьте, что вы сначала загрузили канал Atom в переменную $feed , следующим образом:

$feed = simplexml_load_file("http://www.cafeconleche.org/today.atom");

Эти две строки теперь находят элемент title:

$children = $feed->children("http://www.w3.org/2005/Atom"); $title = $children->title;

Вы можете сжать этот код в единое выражение, если хотите, хотя строка становится немного длинной. Все другие элементы в пространствах имен должны быть проработаны подобным же образом. показывает полную страницу PHP, которая отображает заголовки из поименованного канала Atom.

Листинг 6. Простой ридер PHP-заголовков Atom
children("http://www.w3.org/2005/Atom"); $title = $children->title; ?> <?php echo $title; ?>

entry; foreach ($entries as $entry) { $details = $entry->children("http://www.w3.org/2005/Atom"); echo "

". $details->title. "

"; } ?>

Смешанный контент

Почему я показал только заголовки в этом примере? Потому что в Atom контент любого списка может содержать полный текст фрагмента и не только сам текст, но и всю разметку. Это - повествовательная структура : слова в ряду предназначены для чтения людьми. Как и в большинстве данных подобного рода здесь смешанный контент. XML уже не упрощенный, и поэтому подход SimpleXML начинает давать сбои. Он не может корректно работать со смешанным контентом, и этот пропуск данных препятствует использованию во многих случаях.

Вы можете сделать одну вещь, но это только частичное решение проблемы. Она сработает только потому, что элемент content содержит реальный XHTML. Вы можете скопировать этот XHTML, как непроанализированный исходный код непосредственно в конечный продукт, используя функцию asXML() , например, следующим образом:

echo "

". $details->content->asXML(). "

";

В результате получится что-то вроде .

Листинг 7. Выходные данные XML

Nikolai Grigoriev has released SVGMath 0.3, a presentation MathML formatter that produces SVG written in pure Python and published under an MIT license. According to Grigoriev, "The new version can work with multiple-namespace documents (e.g. replace all MathML subtrees with SVG in an XSL-FO or XHTML document); configuration is made more flexible, and several bugs are fixed. There is also a stylesheet to adjust the vertical position of the resulting SVG image in XSL-FO."

Это не чистый XHTML. Элемент content извлекается из Atom документа, и вам бы, на самом деле, лучше его не иметь. Даже хуже, он проникает в неправильное пространство имени, поэтому он не может быть распознан таким, какой он есть. К счастью на практике этот дополнительный элемент не очень сильно вредит, потому что Web-браузеры просто игнорируют любые теги, которые они не распознают. Законченный документ неисправен, но это не имеет большого значения. Если это действительно вас беспокоит, сведите это на нет с помощью строковых операций, например, следующим образом:

$description = $details->content->asXML(); $tags = array("", ""); $notags = array("", ""); $description = str_replace($tags, $notags, $description);

Чтобы сделать код немного более надежным, используйте регулярное выражение, а не допущение, что начальный тег именно такой, как он показан выше. Особенно вы можете просчитать множество возможных атрибутов:

// тег конца имеет фиксированную форму, поэтому его легко заменить $description = str_replace("", "", $description); // удалите тег начала, по возможности включая атрибуты и пробел $description = ereg_replace("]*>", "", $description);

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

XPath

Такие выражения как $rss->channel->item->title великолепны, только если вы точно знаете, какие элементы находятся в документе, и где точно они находятся. Однако вы далеко не всегда это знаете. Например, в XHTML элементы в заголовке (h1 , h2 , h3 , и т.д.) могут быть дочерними от body , div , table и от нескольких других элементов. Более того, div , table , blockquote и другие элементы могут быть вложены друг в друга множество раз. Для многих менее определенных случаев использования, легче использовать выражения XPath, такие как //h1 или //h1 . SimpleXML имеет этот набор функциональных возможностей через функцию xpath() .

Листинг 9. Использование XPath с пространствами имен
$atom = simplexml_load_file("http://www.cafeconleche.org/today.atom"); $atom->registerXPathNamespace("atm", "http://www.w3.org/2005/Atom"); $titles = $atom->xpath("//atm:title"); foreach ($titles as $title) { echo "

". $title. "

"; }

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

Вывод

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

Я имею дело со сторонней библиотекой PHP, которую я не могу редактировать, и она работает нормально почти год. Он использует simplexml_load_string для ответа с удаленного сервера. В последнее время он задыхается от больших ответов. Это канал данных для объектов недвижимости, а также формат выглядит примерно так:

sysid 1 2 3 4 5 6 252370080 Residential 0.160 No ADDR0 06051 252370081 Residential 0.440 Yes ADDR0 06043 252370082 Residential 1.010 No ADDR0 06023 More tab delimited text

Я скачал пример файл ответ (около 22MB), вот где я закончил с моей отладкой и здравым смыслом. На обоих серверах работает PHP Version 5.3.8, но обратите внимание на разные результаты. Я уверен, что оба файла одинаковы (я полагаю, что разные типы файлов, strlen и последние 50 символов могут быть объяснены с помощью новых строк Windows, имеющих дополнительный символ возврата каретки). Тестовый сценарий:

Error_reporting(-1); ini_set("display_errors", 1); $file = "error-example.xml"; $xml = file_get_contents($file); echo "filesize: "; var_dump(filesize($file)); echo "strlen: "; var_dump(strlen($xml)); echo "simplexml object? "; var_dump(is_object(simplexml_load_string($xml))); echo "Last 50 characters: "; var_dump(substr($xml, -50));

Выход локально на Windows:

Filesize: int(21893604) strlen: int(21893604) simplexml object? bool(true) Last 50 characters: string(50) "RD DR CT Watertown 203-555-5555 "

Выход на удаленном сервере UNIX:

Filesize: int(21884093) strlen: int(21884093) simplexml object? Warning: simplexml_load_string(): Entity: line 9511: parser error: internal error in /path/to/test.php on line 19 Warning: simplexml_load_string(): AULTED CEILING IN FOYER, BRICK FP IN FR, NEW FLOORING IN LR DR FR FOYER KITCHEN in /path/to/test.php on line 19 Warning: simplexml_load_string(): ^in /path/to/test.php on line 19 Warning: simplexml_load_string(): Entity: line 9511: parser error: Extra content at the end of the document in /path/to/test.php on line 19 Warning: simplexml_load_string(): AULTED CEILING IN FOYER, BRICK FP IN FR, NEW FLOORING IN LR DR FR FOYER KITCHEN in /path/to/test.php on line 19 Warning: simplexml_load_string(): ^in /path/to/test.php on line 19 bool(false) Last 50 characters: string(50) "ORD DR CT Watertown 203-555-5555 "

Некоторые ответы на комментарии и дополнительная информация:

    Сам XML представляется действуйте, насколько я могу судить (и это делает работы на моей системе).

    magic_quotes_runtime определенно выключен.

    Рабочий сервер имеет версию libxml версии 2.7.7, а другой - 2.7.6. Может ли это действительно изменить ситуацию? Я не мог найти журнал изменений libxml, но это кажется маловероятным.

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

    Я не сталкиваюсь с проблемами памяти, тестовый скрипт запускается мгновенно.

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

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

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

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

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


>

> 1972>
> Dennis Ritchie>
>

> 1995>
> Rasmus Lerdorf>
>

> 1995>
> James Gosling>
>
>

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

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

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

SimpleXMLElement Object
[ lang] => Array
[ 0 ] => SimpleXMLElement Object
[ @ attributes] => Array
[ name] => C
[ appeared] => 1972
[ creator] => Dennis Ritchie
[ 1 ] => SimpleXMLElement Object
[ @ attributes] => Array
[ name] => PHP
[ appeared] => 1995
[ creator] => Rasmus Lerdorf
[ 2 ] => SimpleXMLElement Object
[ @ attributes] => Array
[ name] => Java
[ appeared] => 1995
[ creator] => James Gosling
)
)

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

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

$languages -> lang [ 0 ] -> appeared ;
$languages -> lang [ 0 ] -> creator ;

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

foreach ($languages -> lang as $lang ) {
printf (
"" ,
$lang [ "name" ] ,
$lang -> appeared ,
$lang -> creator
) ;
}

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

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

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



xmlns:dc =>

> 1972>
> Dennis Ritchie>
>

> 1995>
> Rasmus Lerdorf>
>

> 1995>
> James Gosling>
>
>

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

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

$dc = $languages -> lang [ 1 ] - > children("http://purl.org/dc/elements/1.1/" ) ;
echo $dc -> creator ;

Метод 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 и отображает ссылки на все видео из него. Для этого нужно обратится по следующему адресу:

http://gdata.youtube.com/feeds/api/users/xxx/uploads

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 :

>

>



Title…>

>

>

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

foreach ($feed -> entry as $entry ) {
$group = $entry -> children ($ns [ "media" ] ) ;
$group = $group -> group ;
$thumbnail_attrs = $group -> thumbnail [ 1 ] -> attributes () ;
$image = $thumbnail_attrs [ "url" ] ;
$player = $group -> player -> attributes () ;
$link = $player [ "url" ] ;
$title = $group -> title ;
printf ("

" ,
$player , $image , $title ) ;
}

Заключение

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


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

SimpleXML довольно простой и в тоже время довольно мощный способ обработки xml данных. Суть simpleXML заключается в том, что весь XML код конвертируется в PHP объект, что довольно сильно облегчает работу с ним. При работе с simpleXML все данные должны быть представлены в UTF-8 кодировке.

Чаще всего конвертация в PHP объект осуществляется при помощи функции simplexml_load_file , ниже представлены примеры работы с ним. Кроме того можно использовать функцию simplexml_load_string, создающую объект PHP из строки XML

Вначале создадим файл xml

В следующем примере будет выведена только цена второго автомобиля.

Для вывода сразу всего xml-кода или отдельного узла используется метод asXML().

simpleXML также поддерживает адресацию с помощью языка XPath . В следующем примере будут отобраны все узлы "year" и возвращен их массив.

Замена значений элементов осуществляется простым присвоением значения

При замене узлов, которые имеют дочерние узлы, следует быть осторожным, так как все дочерние узлы будут удалены.

В двух предыдущих примерах был изменены данные xml находящиеся в оперативной памяти, но они не были записаны на диск. Для перезаписи данных в файле используется функция file_put_contents()

Также допустима интеграция simpleXML и Dom при помощи функции Simplexml_import_dom()

В этом примере будет показано как получить значение атрибутов элементов

Похожие публикации