Php simplexml functions
Содержание:
- Parameter Values
- Another XML File
- Смешанный контент
- XPath
- PHP SimpleXML — Получить значения узлов — цикл
- XML другой файл
- Load data from a relational database
- XPath
- More Examples
- PHP SimpleXML — Get Node Values — Loop
- Резюме файла LOAD
- PHP SimpleXML — Read From String
- Error handling
- Parameter Values
- Handling namespaces
Parameter Values
Parameter | Description |
---|---|
data | Required. Specifies a well-formed XML string |
class | Optional. Specifies the class of the new object |
options | Optional. Specifies additional Libxml parameters. Is set by specifying the option and 1 or 0 (TRUE or FALSE, e.g. LIBXML_NOBLANKS(1))
Possible values:
|
ns | Optional. Specifies a namespace prefix or URI |
is_prefix | Optional. Specifies a Boolean value. TRUE if ns is a prefix. FALSE if ns is a URI. Default is FALSE |
Another XML File
Assume we have an XML file called «books.xml»,
that looks like this:
<?xml version=»1.0″ encoding=»utf-8″?><bookstore> <book category=»COOKING»> <title lang=»en»>Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year>
<price>30.00</price> </book> <book category=»CHILDREN»> <title lang=»en»>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year>
<price>29.99</price> </book> <book category=»WEB»> <title lang=»en-us»>XQuery Kick Start</title> <author>James McGovern</author> <year>2003</year> <price>49.99</price> </book>
<book category=»WEB»> <title lang=»en-us»>Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year> <price>39.95</price> </book></bookstore>
Смешанный контент
Почему я показал только заголовки в этом примере? Потому что в Atom контент любого списка может содержать полный текст фрагмента и не только сам текст, но и всю разметку. Это — повествовательная структура: слова в ряду предназначены для чтения людьми. Как и в большинстве данных подобного рода здесь смешанный контент. XML уже не упрощенный, и поэтому подход SimpleXML начинает давать сбои. Он не может корректно работать со смешанным контентом, и этот пропуск данных препятствует использованию во многих случаях.
Вы можете сделать одну вещь, но это только частичное решение проблемы. Она сработает только потому, что элемент содержит реальный XHTML. Вы можете скопировать этот XHTML, как непроанализированный исходный код непосредственно в конечный продукт, используя функцию , например, следующим образом:
echo "<p>". $details->content->asXML(). "</p>";
В результате получится что-то вроде .
Листинг 7. Выходные данные XML
<content type="xhtml"> <div xmlns="http://www.w3.org/1999/xhtml" id="August_7_2006_31098" class="2006-08-07T09:38:18Z"> <p> Nikolai Grigoriev has released <a shape="rect" href="http://www.grigoriev.ru/svgmath">SVGMath 0.3</a>, 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." </p> </div> </content>
Это не чистый XHTML. Элемент извлекается из Atom документа, и вам бы, на самом деле, лучше его не иметь. Даже хуже, он проникает в неправильное пространство имени, поэтому он не может быть распознан таким, какой он есть. К счастью на практике этот дополнительный элемент не очень сильно вредит, потому что Web-браузеры просто игнорируют любые теги, которые они не распознают. Законченный документ неисправен, но это не имеет большого значения. Если это действительно вас беспокоит, сведите это на нет с помощью строковых операций, например, следующим образом:
$description = $details->content->asXML(); $tags = array('<content type="xhtml"'>", "</content>"); $notags = array("", ""); $description = str_replace($tags, $notags, $description);
Чтобы сделать код немного более надежным, используйте регулярное выражение, а не допущение, что начальный тег именно такой, как он показан выше. Особенно вы можете просчитать множество возможных атрибутов:
// тег конца имеет фиксированную форму, поэтому его легко заменить $description = str_replace("</content>", "", $description); // удалите тег начала, по возможности включая атрибуты и пробел $description = ereg_replace("<content*>", "", $description);
Даже с этой модификацией ваш код может выдавать комментарии, вычислительные команды и отрезки CDATA. Так или иначе, вы срезаете это, хотя боюсь, что это больше не так просто. Смешанный контент просто переходит границы, для работы в которых был разработан SimpleXML.
XPath
Expressions such as
are great as long as you know exactly which elements are in the document and exactly
where they are. However, you don’t always know that. For instance, in XHTML, heading
elements (, , , and so on) can be children of the , a , a , and several other elements. Furthermore, s, s, s, and other elements can nest inside each other multiple
times. For many less-determinate use cases, it’s easier to use XPath expressions
such as or . SimpleXML enables this functionality through the
function.
shows a PHP page that lists all the titles in an RSS
document — both the title of the feed itself and the titles of the individual
items.
Listing 8. Using XPath to find
title elements
<html xml:lang="en" lang="en"> <head> <title>XPath Example</title> </head> <body> <?php $rss = simplexml_load_file('http://partners.userland.com/nytRss/nytHomepage.xml'); foreach ($rss->xpath('//title') as $title) { echo "<h2>" . $title . "</h2>"; } ?> </body> </html>
SimpleXML only supports XPath location paths and unions of location paths. It does
not support XPath expressions that do not return node-sets, such as or .
Starting in PHP version 5.1, SimpleXML can make XPath queries against namespaced
documents. As always in XPath, the location path must use namespace prefixes even if
the searched document uses the default namespace. The function associates a prefix with a namespace
URI for use in the next query. For example, if you wanted to find all the elements in an Atom document, you’d use code like
that in .
Listing 9. Using XPath with
namespaces
$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 "<h2>" . $title . "</h2>"; }
One final warning: XPath in PHP is quite slow. Page loads went from essentially
unnoticeable to several seconds when I switched over to this XPath expression, even
on an unloaded local server. If you use these techniques, you must use some sort of
caching to get reasonable performance. Dynamically generating every page just won’t
work.
PHP SimpleXML — Получить значения узлов — цикл
Следующий пример перебирает все элементы <book> в файле «books.xml»,
и получает значения узла элементов <title>, <author>, <year>, и <price>:
Пример
<?php$xml=simplexml_load_file(«books.xml») or die(«Ошибка: Невозможно создать объект»);
foreach($xml->children() as $books) { echo $books->title . «, «;
echo $books->author . «, «; echo $books->year . «, «;
echo $books->price . «<br>»; } ?>
Вывод данных приведенного выше кода:
Everyday Italian, Giada De Laurentiis, 2005, 30.00
Harry Potter, J K. Rowling, 2005, 29.99
XQuery Kick Start, James McGovern, 2003, 49.99
Learning XML, Erik T. Ray, 2003, 39.95
XML другой файл
Предположим, у нас есть XML файл «books.xml»,
он выглядит так:
<?xml version=»1.0″ encoding=»utf-8″?><bookstore>
<book category=»COOKING»>
<title lang=»en»>Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price> </book> <book category=»CHILDREN»>
<title lang=»en»>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price> </book> <book category=»WEB»>
<title lang=»en-us»>XQuery Kick Start</title>
<author>James McGovern</author>
<year>2003</year>
<price>49.99</price> </book> <book category=»WEB»>
<title lang=»en-us»>Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year> <price>39.95</price> </book></bookstore>
Load data from a relational database
ML.NET supports loading data from a variety of relational databases supported by that include SQL Server, Azure SQL Database, Oracle, SQLite, PostgreSQL, Progress, IBM DB2, and many more.
Note
To use , reference the System.Data.SqlClient NuGet package.
Given a database with a table named and the following schema:
The data can be modeled by a class like .
Then, inside of your application, create a .
Define your connection string as well as the SQL command to be executed on the database and create a instance. This sample uses a LocalDB SQL Server database with a file path. However, DatabaseLoader supports any other valid connection string for databases on-premises and in the cloud.
Numerical data that is not of type has to be converted to . The type is represented as a single-precision floating-point value or , the input type expected by ML.NET algorithms. In this sample, the column is an integer in the database. Using the built-in function, it’s converted to . Because the property is already of type it is loaded as is.
Use the method to load the data into an .
XPath
Такие выражения как великолепны, только если вы точно знаете, какие элементы находятся в документе, и где точно они находятся. Однако вы далеко не всегда это знаете. Например, в XHTML элементы в заголовке (,,, и т.д.) могут быть дочерними от , , и от нескольких других элементов. Более того, , , и другие элементы могут быть вложены друг в друга множество раз. Для многих менее определенных случаев использования, легче использовать выражения XPath, такие как или . SimpleXML имеет этот набор функциональных возможностей через функцию .
показывает страницу PHP, которая содержит все заголовки в документе RSS – как заголовок самого канала, так и заголовки отдельных групп элементов.
Листинг 8. Использование XPath для нахождения элементов заголовков
<html xml:lang="en" lang="en"> <head> <title>XPath Example</title> </head> <body> <?php $rss = simplexml_load_file('http://partners.userland.com/nytRss/nytHomepage.xml'); foreach ($rss->xpath('//title') as $title) { echo "<h2>". $title. "</h2>"; } ?> </body> </html>
SimpleXML поддерживает только строковые выражения XPath, задающие местонахождении файла и объединения этих выражений. Он не поддерживает выражения XPath, которые не возвращают множества узлов, таких как или.
Начиная с PHP версии 5.1, SimpleXML может создавать XPath-запросы относительно документов с пространствами имен. Как обычно в XPath, строковое выражение, задающее местонахождение файла, должно использовать префиксы пространств имен, даже если искомый документ использует пространство имен по умолчанию. Функция ассоциирует префикс с пространством имени URI для использования в следующем запросе. Например, если вы хотите найти все элементы в документе, вы используете код подобный представленному в .
Листинг 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 "<h2>". $title. "</h2>"; }
Еще одно последнее предупреждение: XPath в PHP работает довольно медленно. Загрузка страницы может занимать от мгновения до нескольких секунд, когда я переключился на это XPath выражение, даже на незагруженном местном сервере. Если вы используете эти приемы, вы должны использовать какого-то рода кэширование для разумной работы. Динамическое генерирование каждой страницы просто не сработает.
More Examples
Assume we have the following XML file, «note.xml»:
<?xml version=»1.0″ encoding=»UTF-8″?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don’t forget me this weekend!</body>
</note>
Example
Output the data from each element in the XML file:
<?php$xml=simplexml_load_file(«note.xml»);echo $xml->to . «<br>»;
echo $xml->from . «<br>»;echo $xml->heading . «<br>»;echo $xml->body;?>
Example
Output the element’s name and data for each child node in the XML file:
<?php
$xml=simplexml_load_file(«note.xml»);
echo $xml->getName() . «<br>»;
foreach($xml->children() as $child)
{
echo $child->getName() . «: » . $child . «<br>»;
}
?>
PHP SimpleXML — Get Node Values — Loop
The following example loops through all the <book> elements in the «books.xml» file,
and gets the node values of the <title>, <author>, <year>, and <price> elements:
Example
<?php$xml=simplexml_load_file(«books.xml») or die(«Error: Cannot create object»);foreach($xml->children() as $books) { echo $books->title . «, «;
echo $books->author . «, «; echo $books->year . «, «;
echo $books->price . «<br>»; } ?>
The output of the code above will be:
Everyday Italian, Giada De Laurentiis, 2005, 30.00Harry Potter, J K. Rowling, 2005, 29.99XQuery Kick Start, James McGovern, 2003, 49.99
Learning XML, Erik T. Ray, 2003, 39.95
Резюме файла LOAD
Расширение файла LOAD включает в себя один основных типов файлов и его можно открыть с помощью Apple OS X (разработчик — Apple). В общей сложности с этим форматом связано всего два программное (-ых) обеспечение (-я). Чаще всего они имеют тип формата Golden Orchard Apple II CD Rom File.
Основную часть этих фацлов классифицируют, как Data Files.
Файлы с расширением LOAD были идентифицированы на настольных компьютерах (и некоторых мобильных устройствах). Они полностью или частично поддерживаются Mac и Windows.
Рейтинг популярности файлов LOAD составляет «Низкий». Это означает, что они не часто встречаются на большинстве устройств.
PHP SimpleXML — Read From String
The PHP function is used to read XML data from a string.
Assume we have a variable that contains XML data, like this:
$myXMLData = «<?xml version=’1.0′ encoding=’UTF-8′?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don’t forget me this weekend!</body>
</note>»;
The example below shows how to use the function to
read XML data from a string:
<?php$myXMLData =»<?xml version=’1.0′ encoding=’UTF-8′?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don’t forget me this weekend!</body>
</note>»;
$xml=simplexml_load_string($myXMLData) or die(«Error: Cannot create object»);print_r($xml);
?>
SimpleXMLElement Object ( => Tove => Jani => Reminder => Don’t forget me this weekend! )
Error Handling Tip: Use the libxml functionality to retrieve
all XML errors when loading the document and then iterate over the errors. The
following example tries to load a broken XML string:
Error handling
Not all RSS feeds are as well formed as they’re supposed to be. The XML specification
requires processors to stop processing documents as soon as a well-formedness error
is detected, and SimpleXML is a conforming XML processor. However, it doesn’t give
you a lot of help when it finds an error. Generally, it logs a warning in the
php-errors file (but without a detailed error message), and the function returns FALSE. If you aren’t confident
that the file you’re parsing is well formed, check for this error before using the
file’s data, as shown in .
Listing 4. Watching out for
malformed input
<?php $rss = simplexml_load_file('http://www.cafeaulait.org/today.rss'); if ($rss) { foreach ($rss->xpath('//title') as $title) { echo "<h2>" . $title . "</h2>"; } } else { echo "Oops! The input is malformed!"; } ?>
The method will return more helpful,
debugging information about what went wrong, though these are usually not details
you want to show to the end-reader.
The other common error case is where the document is indeed well formed but doesn’t
contain exactly the elements you expect exactly where you expect them. What happens
to an expression such as when an item does not have a
title (as is the case in at least one top-100 RSS feed)? The simplest approach is
always to treat the return value as an array and loop over it. In this case, you’re
covered whether there are more or fewer elements than you expect. However, if you
know that you only want the first element in the document — even if there are more
than one — you can ask for it by index, starting at zero. For example, to request
the first item’s title, you could write:
$doc->rss->channel->item->title
If there is no first item, or if the first item does not have a title, this item is
treated the same as any other out-of-bounds index in a PHP array. That is, the
result is null, which is converted to the empty string when you try to insert it
into the output HTML.
Recognizing and rejecting unexpected formats you aren’t prepared to handle is
typically the province of a validating XML parser. However SimpleXML cannot validate
against a Document Type Definition (DTD) or schema. It checks only for
well-formedness.
Parameter Values
Parameter | Description |
---|---|
file | Required. Specifies the path to the XML file |
class | Optional. Specifies the class of the new object |
options | Optional. Specifies additional Libxml parameters. Is set by specifying the option and 1 or 0 (TRUE or FALSE, e.g. LIBXML_NOBLANKS(1))
Possible values:
|
ns | Optional. Specifies a namespace prefix or URI |
is_prefix | Optional. Specifies a Boolean value. TRUE if ns is a prefix. FALSE if ns is a URI. Default is FALSE |
Handling namespaces
Many sites are now switching from RSS to Atom. shows
an example of an Atom document. In many ways, this document is similar to the RSS
example. However, there’s more metadata, and the root element is instead of . The element has entries instead of items. The element replaces the
element. Most significantly, the Atom document uses a namespace, while the RSS
document does not. In this way, the Atom document can embed real, un-escaped
Extensible HTML (XHTML) in its content.
Listing 5. An Atom
document
<?xml version="1.0"?> <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US" xml:base="http://www.cafeconleche.org/today.atom"> <updated>2006-08-04T16:00:04-04:00</updated> <id>http://www.cafeconleche.org/</id> <title>Cafe con Leche XML News and Resources</title> <link rel="self" type="application/atom+xml" href="/today.atom"/> <rights>Copyright 2006 Elliotte Rusty Harold</rights> <entry> <title>Steve Palmer has posted a beta of Vienna 2.1, an open source RSS/Atom client for Mac OS X. </title> <content type="xhtml"> <div xmlns="http://www.w3.org/1999/xhtml" id="August_1_2006_25279" class="2006-08-01T07:01:19Z"> <p> Steve Palmer has posted a beta of <a shape="rect" href="http://www.opencommunity.co.uk/vienna21.php">Vienna 2.1</a>, 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. </p> </div> </content> <link href="/#August_1_2006_25279"/> <id>http://www.cafeconleche.org/#August_1_2006_25279</id> <updated>2006-08-01T07:01:19Z</updated> </entry> <entry> <title>Matt Mullenweg has released WordPress 2.0.4, a blog engine based on PHP and MySQL. </title> <content type="xhtml"> <div xmlns="http://www.w3.org/1999/xhtml" id="August_1_2006_21750" class="2006-08-01T06:02:30Z"> <p> Matt Mullenweg has released <a shape="rect" href="http://wordpress.org/development/2006/07/wordpress-204 /">Wordpress 2.0.4</a>, a blog engine based on PHP and MySQL. 2.0.4 plugs various security holes, mostly involving plugins. </p> </div> </content> <link href="/#August_1_2006_21750"/> <id>http://www.cafeconleche.org/#August_1_2006_21750</id> <updated>2006-08-01T06:02:30Z</updated> </entry> </feed>
Although the element names have changed, the basic approach to handling an Atom
document with SimpleXML is the same as for handling RSS. The one difference is that
you must now specify a namespace Uniform Resource Identifier (URI) when requesting a
named element as well as a local name. This is a two-step process: First, request
the child elements in a given namespace by passing the namespace URI to the function. Then, request the elements with the
right local name in that namespace. Suppose you first load the Atom feed into the
variable , like so:
$feed = simplexml_load_file('http://www.cafeconleche.org/today.atom');
These two lines now find the element:
$children = $feed->children('http://www.w3.org/2005/Atom'); $title = $children->title;
You can condense this code into a single statement if you like, though the line gets
a bit long. All other elements in namespaces must be handled similarly. shows a complete PHP page that displays the titles
from a namespaced Atom feed.
Listing 6. A simple PHP Atom
headline reader
<?php $feed = simplexml_load_file('http://www.cafeconleche.org/today.atom'); $children = $feed->children('http://www.w3.org/2005/Atom'); $title = $children->title; ?> <html xml:lang="en" lang="en"> <head> <title><?php echo $title; ?></title> </head> <body> <h1><?php echo $title; ?></h1> <?php $entries = $children->entry; foreach ($entries as $entry) { $details = $entry->children('http://www.w3.org/2005/Atom'); echo "<h2>" . $details->title . "</h2>"; } ?> </body> </html>