Я пытаюсь получить значение следующих узлов из [этого URL (загрузка занимает довольно много времени)] [1]. Интересующие меня элементы:
title, g:price and g:gtin
XML начинается так:
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
<channel>
<title>PhotoSpecialist.de</title>
<link>http://www.photospecialist.de</link>
<description/>
<item>
<g:id>BEN107C</g:id>
<title>Benbo Trekker Mk3 + Kugelkopf + Tasche</title>
<description>
Benbo Trekker Mk3 + Kugelkopf + Tasche Das Benbo Trekker Mk3 ist eine leichte Variante des beliebten Benbo 1. Sein geringes Gewicht macht das Trekker Mk3 zum idealen Stativ, wenn Sie viel draußen fotografieren und viel unterwegs sind. Sollten Sie in eine Situation kommen, in der maximale Stabilität zählt, verfügt das Benbo Trekker Mk3 über einen Haken an der Mittelsäule. An diesem können Sie das Stativ mit zusätzlichem Gewicht bei Bedarf beschweren. Dank der zwei besonderen Kamera-Befestigungsschrauben können Sie mit dem Benbo Trekker Mk3 sehr nah am Boden fotografieren. So nah, dass in vielen Fällen die einzige Einschränkung die Größe Ihrer Kamera darstellt. In diesem Set erhalten Sie das Benbo Trekker Mk3 zusammen mit einem Kugelkopf, Socket und einer Tasche für den sicheren und komfortablen Transport.
</description>
<link>
http://www.photospecialist.de/benbo-trekker-mk3-kugelkopf-tasche?dfw_tracker=2469-16
</link>
<g:image_link>http://static.fotokonijnenberg.nl/media/catalog/product/b/e/benbo_trekker_mk3_tripod_kit_with_b__s_head__bag_ben107c1.jpg</g:image_link>
<g:price>199.00 EUR</g:price>
<g:condition>new</g:condition>
<g:availability>in stock</g:availability>
<g:identifier_exists>TRUE</g:identifier_exists>
<g:brand>Benbo</g:brand>
<g:gtin>5022361100576</g:gtin>
<g:item_group_id>0</g:item_group_id>
<g:product_type>Tripod</g:product_type>
<g:mpn/>
<g:google_product_category>Kameras & Optik</g:google_product_category>
</item>
...
</channel>
</rss>
Чтобы получить это, я написал следующий код:
$z = new XMLReader;
$z->open('https://my.datafeedwatch.com/static/files/1248/8222ebd3847fbfdc119abc9ba9d562b2cdb95818.xml');
$doc = new DOMDocument;
while ($z->read() && $z->name !== 'item')
;
while ($z->name === 'item')
{
$node = new SimpleXMLElement($z->readOuterXML());
$a = $node->title;
$b = $node->price;
$c = $node->gtin;
echo $a . $b . $c . "<br />";
$z->next('item');
}
Это возвращает мне только название … цена и гтин не отображаются.
Элементы, о которых вы спрашиваете, не являются частью пространства имен по умолчанию, а находятся в другом. Вы можете видеть это, потому что у них есть префикс в их имени, отделенный двоеточием:
...
<channel>
<title>PhotoSpecialist.de</title>
<!-- title is in the default namespace, no colon in the name -->
...
<g:price>199.00 EUR</g:price>
...
<g:gtin>5022361100576</g:gtin>
<!-- price and gtin are in a different namespace, colon in the name and prefixed by "g" -->
...
Пространство имен дается с префиксом, здесь «g» в вашем случае. И префикс, который обозначает пространство имен, определен в элементе документа здесь:
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
Так что пространство именhttp://base.google.com/ns/1.0
».
При доступе к дочерним элементам по их имени с SimpleXMLElement как вы сейчас делаете:
$a = $node->title;
$b = $node->price;
$c = $node->gtin;
вы ищете только в пространстве имен по умолчанию. Таким образом, только первый элемент на самом деле содержит текст, остальные два созданы на-твоему лета и еще пусто.
Чтобы получить доступ к пространству имен дочерних элементов, вы должны сообщить SimpleXMLElement явно с children()
метод. Это создает новый SimpleXMLElement со всеми дочерними элементами в этом пространстве имен вместо одного по умолчанию:
$google = $node->children("http://base.google.com/ns/1.0");
$a = $node->title;
$b = $google->price;
$c = $google->gtin;
Вот вам и отдельный пример (да, это уже так).
Полный пример может выглядеть так (включая расширение узла в считывателе, код, который у вас был немного ржавым):
<?php
/**
* How to parse an XML node with a colon tag using PHP
*
* @link http://stackoverflow.com/q/29876898/367456
*/
const HTTP_BASE_GOOGLE_COM_NS_1_0 = "http://base.google.com/ns/1.0";
$url = 'https://my.datafeedwatch.com/static/files/1248/8222ebd3847fbfdc119abc9ba9d562b2cdb95818.xml';
$reader = new XMLReader;
$reader->open($url);
$doc = new DOMDocument;
// move to first item element
while (($valid = $reader->read()) && $reader->name !== 'item') ;
while ($valid) {
$default = simplexml_import_dom($reader->expand($doc));
$googleBase = $default->children(HTTP_BASE_GOOGLE_COM_NS_1_0);
printf(
"%s - %s - %s<br />\n", htmlspecialchars($default->title)
, htmlspecialchars($googleBase->price)
, htmlspecialchars($googleBase->gtin)
);
// move to next item element
$valid = $reader->next('item');
};
Я надеюсь, что это дает объяснение и немного расширяет представление о XMLReader используйте также.
Других решений пока нет …