в настоящее время я хотел бы проанализировать строку из xml-файла (RSS), чтобы получить и отобразить ссылку на изображение в узле: "<enc:enclosure rdf:resource="https://www.science.org/... .jpg". Для меня это выглядит как что-то с двумя разными пространствами имен. И до сих пор я не нашел подобного вопроса или примера, чтобы заставить это работать. В прилагаемом упрощенном примере кода вы можете увидеть, что работает должным образом и что ссылка в узле: "<enc:enclosure rdf:resource="https://www.science.org/... .jpg" не отображается, что способ.
<?php
$xml_string = '<?xml version = "1.0" encoding = "UTF-8"?>
<rdf:RDF xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc = "http://purl.org/dc/elements/1.1/" xmlns:prism = "http://prismstandard.org/namespaces/basic/2.0/" xmlns:content = "http://purl.org/rss/1.0/modules/content/" xmlns:enc = "http://purl.oclc.org/net/rss_2.0/enc/" xmlns:cc = "http://web.resource.org/cc/" xmlns = "http://purl.org/rss/1.0/">
<item>
<title><![CDATA[Canada moves to ban funding for ‘risky’ foreign collaborations]]></title>
<link>https://www.science.org/content/article/canada-moves-ban-funding-risky-foreign-collaborations</link>
<description><![CDATA[China is seen as main target in rejecting joint projects with certain foreign entities]]></description>
<enc:enclosure rdf:resource = "https://www.science.org/do/10.1126/science.adh2317/rss/_20230217_nid_canada_china.jpg" enc:length = "165061" enc:type = "image/jpeg" />
<dc:title><![CDATA[Canada moves to ban funding for ‘risky’ foreign collaborations]]></dc:title>
<dc:identifier>doi:10.1126/science.adh2317</dc:identifier>
<dc:date>2023-02-17T05:55:00Z</dc:date>
<dc:creator>Jeffrey Mervis</dc:creator>
<prism:publicationName><![CDATA[Canada moves to ban funding for ‘risky’ foreign collaborations]]></prism:publicationName>
<prism:coverDate>2023-02-17T05:55:00Z</prism:coverDate>
<prism:coverDisplayDate>2023-02-17T05:55:00Z</prism:coverDisplayDate>
<prism:doi>10.1126/science.adh2317</prism:doi>
<prism:url>https://www.science.org/content/article/canada-moves-ban-funding-risky-foreign-collaborations</prism:url>
</item></rdf:RDF>';
$xml = simplexml_load_string($xml_string);
foreach ($xml->item as $item) {
if ($item->children('http://purl.oclc.org/net/rss_2.0/enc/')) {
foreach ($item->children('http://purl.oclc.org/net/rss_2.0/enc/') as $eintrag1) {
echo'<pre>';print_r($eintrag1);echo'</pre>'; // is working
echo 'Length: ' . $eintrag1['length'] . '<br />'; // is working
$eintrag2 = $eintrag1->children('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
echo'<pre>';print_r($eintrag2);echo'</pre>'; // is working
echo 'Resource: ' . $eintrag2['resource'] . '<br />'; // NOT working!!! Only empty output, but it's the link I would like to extract!
} }
}
?>
Это выглядит просто, и я думал, что уже справился с этими проблемами с моими небольшими навыками PHP, но ни один из моих подходов (например, DOM, SimpleXML, xpath) не привел меня к желаемому результату. Если кто-то найдет время, чтобы помочь мне найти ответ, я был бы очень признателен. Заранее спасибо.
Известно, что SimpleXML имеет проблемы с пространствами имен, вместо этого попробуйте DOM + DOMXPath.
$dom = new DOMDocument;
$dom->loadXML(file_get_contents('https://www.science.org/rss/news_current.xml'));
$dxp = new DOMXPath($dom);
foreach($dxp->query('//enc:enclosure') as $enclosure) {
echo 'Resource: ' . $enclosure->getAttribute('rdf:resource') . '<br />';
}
Хотя мне пришлось отредактировать свой вопрос, в основном это правильный ответ! Спасибо, @Kazz, очень эффективное и элегантное решение в кратчайшие сроки!
SimpleXML выполняет некоторое неявное переключение пространства имен. Вы уже использовали явный синтаксис для дочерних элементов, вы можете сделать то же самое для атрибутов.
Однако я предлагаю определить константу/переменную со всеми используемыми вами пространствами имен. Это сделает ваш код более читабельным. Ключи могут отличаться от префиксов в документе.
$xmlns = [
'enc' => 'http://purl.oclc.org/net/rss_2.0/enc/',
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
// defined in the XML as namespace for elements without a prefix
'rss' => 'http://purl.org/rss/1.0/',
];
$rdf = simplexml_load_string(getXMLString());
foreach ($rdf->children($xmlns['rss'])->item as $item) {
foreach ($item->children($xmlns['enc'])->enclosure as $enclosure) {
echo 'Length: ' . $enclosure->attributes($xmlns['enc'])['length'] . "\n";
echo 'Resource: ' . $enclosure->attributes($xmlns['rdf'])['resource'] . "\n";
}
}
function getXMLString() {
return <<<'XML'
<?xml version = "1.0" encoding = "UTF-8"?>
<rdf:RDF xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc = "http://purl.org/dc/elements/1.1/" xmlns:prism = "http://prismstandard.org/namespaces/basic/2.0/" xmlns:content = "http://purl.org/rss/1.0/modules/content/" xmlns:enc = "http://purl.oclc.org/net/rss_2.0/enc/" xmlns:cc = "http://web.resource.org/cc/" xmlns = "http://purl.org/rss/1.0/">
<item>
<title><![CDATA[Canada moves to ban funding for ‘risky’ foreign collaborations]]></title>
<link>https://www.science.org/content/article/canada-moves-ban-funding-risky-foreign-collaborations</link>
<description><![CDATA[China is seen as main target in rejecting joint projects with certain foreign entities]]></description>
<enc:enclosure rdf:resource = "https://www.science.org/do/10.1126/science.adh2317/rss/_20230217_nid_canada_china.jpg" enc:length = "165061" enc:type = "image/jpeg" />
<dc:title><![CDATA[Canada moves to ban funding for ‘risky’ foreign collaborations]]></dc:title>
<dc:identifier>doi:10.1126/science.adh2317</dc:identifier>
<dc:date>2023-02-17T05:55:00Z</dc:date>
<dc:creator>Jeffrey Mervis</dc:creator>
<prism:publicationName><![CDATA[Canada moves to ban funding for ‘risky’ foreign collaborations]]></prism:publicationName>
<prism:coverDate>2023-02-17T05:55:00Z</prism:coverDate>
<prism:coverDisplayDate>2023-02-17T05:55:00Z</prism:coverDisplayDate>
<prism:doi>10.1126/science.adh2317</prism:doi>
<prism:url>https://www.science.org/content/article/canada-moves-ban-funding-risky-foreign-collaborations</prism:url>
</item></rdf:RDF>
XML;
}
Выход:
Length: 165061
Resource: https://www.science.org/do/10.1126/science.adh2317/rss/_20230217_nid_canada_china.jpg
DOM более явный и имеет набор методов, учитывающих пространство имен, с суффиксом NS
(например, getAttributeNS()
).
DOMXpath::evaluate()
позволяет сложным выражениям извлекать узлы и скалярные значения:
$xmlns = [
'enc' => 'http://purl.oclc.org/net/rss_2.0/enc/',
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
// defined in the XML as namespace for elements without a prefix
'rss' => 'http://purl.org/rss/1.0/',
];
$document = new DOMDocument;
$document->loadXML(getXMLString());
$xpath = new DOMXPath($document);
// register the namespaces
foreach ($xmlns as $alias => $uri) {
$xpath->registerNamespace($alias, $uri);
}
$items = [];
foreach($xpath->evaluate('//rss:item') as $itemNode) {
$items[] = [
// fetch "{http://purl.org/rss/1.0/}title" as string
'title' => $xpath->evaluate('string(rss:title)', $itemNode),
'enclosure' => [
// fetch the attribute values
'resource' => $xpath->evaluate('string(enc:enclosure/@rdf:resource)', $itemNode),
'length' => $xpath->evaluate('number(enc:enclosure/@enc:length)', $itemNode)
],
];
}
var_dump($items);
Выход:
array(1) {
[0]=>
array(2) {
["title"]=>
string(66) "Canada moves to ban funding for ‘risky’ foreign collaborations"
["enclosure"]=>
array(2) {
["resource"]=>
string(85) "https://www.science.org/do/10.1126/science.adh2317/rss/_20230217_nid_canada_china.jpg"
["length"]=>
float(165061)
}
}
}
Пожалуйста, не могли бы вы отредактировать упрощенную версию XML, к которому вы обращаетесь (проверив, чтобы убедиться, что он по-прежнему ведет себя так же, как настоящий)? Таким образом, вопрос остается в силе, даже если данные на другом конце ссылки меняются, и проще скопировать пример в ответы. Кроме того, постарайтесь уточнить ожидаемый и фактический результат.