Не удалось извлечь ссылку в узле "<enc:enclosure rdf:resource..." из XML-файла с помощью PHP

в настоящее время я хотел бы проанализировать строку из 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) не привел меня к желаемому результату. Если кто-то найдет время, чтобы помочь мне найти ответ, я был бы очень признателен. Заранее спасибо.

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

IMSoP 20.02.2023 16:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
1
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Известно, что 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, очень эффективное и элегантное решение в кратчайшие сроки!

SamuElias 21.02.2023 17:35

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)
    }
  }
}

Другие вопросы по теме