SimpleXML возвращает несколько объектов, как я могу получить данные?

Я использую simpleXML для анализа этот XML-файл. Это фид, который я использую для доступа к API YouTube. Я хочу встроить самое последнее видео в объект и отобразить следующие четыре эскиза.

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

Я могу получить доступ к значениям без проблем, но столкнулся с проблемой, что каждое видео хранится в отдельном файле SimpleXMLElement Object. У меня нет никакого контроля над тем, к какому объекту я обращаюсь, поскольку они не хранятся в массиве. Так что я не могу получить, скажем, $thumb[4] или $entry[4]->thumb.

Я пытался использовать SimpleXMLIterator, но по какой-то причине любые значения с одинаковым началом отображаются как пустые. Например, видео может иметь одиннадцать вариантов:

And these would each render as [1]="", [2]="", [3]="", etc.

Я с радостью предоставлю дополнительную информацию всем, кто может помочь!

Изменить

Вот print_r моих результатов. Это делается для одной переменной, чтобы дать вам представление о проблеме со структурой, с которой я столкнулся. Весь print_r($entry) будет содержать переменные для каждого узла в файле XML.

SimpleXMLElement Object
(
    [0] => 159
)
SimpleXMLElement Object
(
    [0] => 44
)

Кроме того, print_r просто находится внутри блока PHP для тестирования. На самом деле я хочу получить доступ к переменным внутри эха в HTML.


person Joshua Cody    schedule 06.02.2010    source источник
comment
Не могли бы вы дать нам print_r или var_dump часть конструкции? Не все это, но достаточно, чтобы мы могли видеть, как это выглядит.   -  person Tyler Carter    schedule 06.02.2010
comment
Точно, чача. Добавлен. Дайте мне знать, если что-то еще даст больше ясности.   -  person Joshua Cody    schedule 06.02.2010
comment
В чем состоят объекты?   -  person Tyler Carter    schedule 06.02.2010
comment
Ничего, это print_r переменной. Возможно, я неправильно понимаю ваш вопрос. Контекст (вероятно, избыточный): это (droplr.com/lMQ70) является print_r записи $entry, которая загружается с этого (droplr.com/lMR2X) PHP.   -  person Joshua Cody    schedule 06.02.2010


Ответы (3)


Вы столкнулись с проблемой пространств имен и SimpleXML. Лента начинается с

<feed xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gd='http://schemas.google.com/g/2005' xmlns:yt='http://gdata.youtube.com/schemas/2007'>

xmlns='http://www.w3.org/2005/Atom' устанавливает пространство имен по умолчанию на http://www.w3.org/2005/Atom. т.е. его дочерние элементы на самом деле не id, updated, category, а http://www.w3.org/2005/Atom:id, http://www.w3.org/2005/Atom:updated и так далее...
Таким образом, вы не можете получить доступ к элементу id через $feed->id, вам нужен метод SimpleXMLELement::children(). Он позволяет вам указать пространство имен дочерних элементов, которые вы хотите получить.

Например,

$feed = simplexml_load_file('http://gdata.youtube.com/feeds/api/videos?author=ofcoursegolf&max-results=5&prettyprint=true');
$children = $feed->children('http://www.w3.org/2005/Atom');
echo $children->updated;

В настоящее время печатает 2010-02-06T05:23:33.858Z.

Чтобы получить идентификатор первого элемента записи, вы можете использовать echo $children->entry[0]->id;.
Но тогда вы попадете в элемент <media:group> и его дочерние элементы <media:category, <media:player> и т. д., которые находятся в пространстве имен xmlns:media='http://search.yahoo.com/mrss/'.

$feed = simplexml_load_file('http://gdata.youtube.com/feeds/api/videos?author=ofcoursegolf&max-results=5&prettyprint=true');
$group = $feed->children('http://www.w3.org/2005/Atom')
  ->entry[0]
  ->children('http://search.yahoo.com/mrss/')
  ->group
  ->children('http://search.yahoo.com/mrss/')
;
echo $group->player->attributes()->url, "\n";
foreach( $group->thumbnail as $thumb) {
  echo 'thumb: ', $thumb->attributes()->url, "\n";
}

(В настоящее время) печатает

http://www.youtube.com/watch?v=ikACkCpJ-js&feature=youtube_gdata
thumb: http://i.ytimg.com/vi/ikACkCpJ-js/2.jpg
thumb: http://i.ytimg.com/vi/ikACkCpJ-js/1.jpg
thumb: http://i.ytimg.com/vi/ikACkCpJ-js/3.jpg
thumb: http://i.ytimg.com/vi/ikACkCpJ-js/0.jpg

Редактировать: я бы, вероятно, сделал это в браузере с гораздо большим количеством JavaScript, но вот пример (простого, уродливого) приложения.

<?php
//define('TESTENV' , true);
function getFeed($author) {
  // <-- add caching here if needed -->
  if ( !defined('TESTENV') ) {
    $url = sprintf('http://gdata.youtube.com/feeds/api/videos?author=%s&max-results=5',
      urlencode($author)
    );
  }
  else {
    $url = 'feed.xml';
  }
  return simplexml_load_file($url);
}
$feed = getFeed('jonlajoie');

if ( !isset($_GET['id']) ) {
  $selected = '';
}
else {
  $selected =  $_GET['id'];
  printf ('
    <object width="425" height="344">
      <param name="movie" value="http://www.youtube.com/v/%s"></param>
      <param name="allowFullScreen" value="true"></param>
      <param name="allowscriptaccess" value="always">
      </param>
      <embed src="http://www.youtube.com/v/%s" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed>
    </object>',
    htmlspcialchars($selected), htmlspcialchars($selected)
  );
}

$item = 0;
foreach( $feed->children('http://www.w3.org/2005/Atom')->entry as $entry ) {
  $entryElements = $entry->children('http://www.w3.org/2005/Atom');
  $groupElements = $entry
    ->children('http://search.yahoo.com/mrss/')
    ->group
    ->children('http://search.yahoo.com/mrss/')
  ;

  if ( !preg_match('!^http://gdata.youtube.com/feeds/api/videos/([^/]+)!', $entryElements->id, $m) ) {
    // google can choose whatever id they want. But this is only a simple example....
    die('unexpected id: '.htmlspecialchars($entryElements->id));
  }
  $id = $m[1];
  if ( $selected!==$id ) {
    printf('<a href="?id=%s"><img src="%s" /></a>',
      urlencode($id),
      $groupElements->thumbnail[0]->attributes()->url
    );
  }
}

Изменить 2: "И когда я нажму на миниатюры, я буду использовать jQuery для загрузки видео в основное пространство. Похоже, мне понадобится точный доступ к node[#], верно?"
Если вы уже используя JavaScript/jQuery, ваш PHP-скрипт (если это вообще необходимо) может просто вернуть (закодированный JSON) массив всех данных для всего видео, и ваш jQuery-скрипт может выяснить, что делать с данными.

person VolkerK    schedule 06.02.2010
comment
Это лучшее объяснение пространства имен, которое я видел. В моем PHP я в настоящее время обращаюсь к данным таким образом — указываю дочерние элементы ('пространство имен'), но вы вложили замечательные слова в учебник, которому я следую. Одна вещь, которую я не понимаю, - это как вызывать конкретные примеры в моем HTML. Должен ли я просто генерировать весь свой HTML из PHP? Я хочу загрузить самое последнее видео в основное пространство по умолчанию, а затем четыре миниатюры 2-5 видео. И когда я нажимаю миниатюры, я использую jQuery для загрузки видео в основное пространство. Похоже, мне понадобится точный доступ к узлу [#], верно? - person Joshua Cody; 06.02.2010
comment
Я чувствую, что я получаю что-то возиться с этим. Я хочу посмотреть, прав ли я. В нем говорится, что для группы переменных ищите дочерние элементы пространства имен w3.org, которые являются первой записью в массиве. Затем найдите дочерние элементы пространства имен yahoo для узла группы. Затем получить детей группы в пространстве имен yahoo? - person Joshua Cody; 06.02.2010
comment
У меня все работает, вплоть до отображения одного видео и его собственной миниатюры с использованием вашего синтаксиса, но я столкнулся с той же проблемой. Мне нужно сделать запись foreach, сохранить эти значения. Затем в моем HTML сделайте $entry[1]->$url или что-то в этом роде, но я не могу понять синтаксис, чтобы это работало. Есть еще идеи? Вот текущий актуальный PHP и HTML: droplr.com/lOEd0 - person Joshua Cody; 06.02.2010
comment
Ух ты, ваши правки исчерпывающие. Я собираюсь спать на этом. Я не решаюсь отказаться от работы с PHP, которую я проделал до сих пор, и начать с нуля. Но опять же, ваше PHP-решение выше, честно говоря, потеряно для меня. Мне действительно нужно передать это клиенту завтра. Разочарован непониманием того, почему я не могу понять этот API YouTube и возврат XML. Я собираюсь спать на этом, но я вернусь завтра, чтобы отметить этот ответ как правильный, а также любой другой, который может помочь мне разобраться в этом. Большое спасибо за Вашу помощь; это было неоценимо до сих пор. - person Joshua Cody; 06.02.2010

Попробуйте $sxml->entry[4]->thumb или что-то в этом роде.

АКА, чтобы получить доступ к идентификатору первой записи, вы должны пойти $sxml->entry[4]->id

В основном $sxml->entry представляет собой массив SimpleXMLElement Objects. Когда вы их foreach, вы просматриваете каждый объект и назначаете его $entry, так что $entry = $sxml->entry[0] и выше.

Вы можете пойти следующим образом:

print_r($sxml);

чтобы увидеть ВСЮ структуру. И это скажет вам, что вам нужно использовать, чтобы получить к нему доступ.

person Tyler Carter    schedule 06.02.2010
comment
Я отредактировал свой вопрос, чтобы уточнить одну вещь. На самом деле я делаю вызовы в HTML за пределами PHP, используя встроенные эхо. Я только что получил print_r в блоке PHP для тестирования. Извиняюсь, что не разъяснил это раньше. Большое спасибо за вашу помощь до сих пор. - person Joshua Cody; 06.02.2010
comment
Отлично, большое спасибо за разъяснение того, что здесь происходит. Если вы еще не заметили, я немного выше своего уровня зарплаты, но мне очень интересно узнать, почему, а не как. Хорошо знать, что foreach проходит через отдельные объекты. - person Joshua Cody; 06.02.2010
comment
Мне 16 лет, делать нечего. Моя зарплата ниже :) - person Tyler Carter; 06.02.2010
comment
Я попытался выполнить print_r для $sxml-›entry[0]-›id и получил белый экран PHP. Я выполнил print_r для $sxml и могу получить значения, но не могу получить конкретное значение. Например, URL из третьего экземпляра ‹media:content url='youtube.com/v/ikACkCpJ-js?f=videosapp=youtube_gdata' type='application/x-shockwave-flash' medium='video' isDefault='true' выражение = 'полная' длительность = '159' yt:format = '5'/›. Я также включу часть моего HTML-кода (droplr.com/lN2dC) и скриншот того, что я у меня есть до сих пор (droplr.com/lN34u) для контекста, если это поможет. - person Joshua Cody; 06.02.2010
comment
Я не совсем уверен, в чем проблема. Просто поиграйте с ним, и я уверен, вы сможете его найти. - person Tyler Carter; 06.02.2010

В конце концов, я сделал два цикла foreach, один из которых проходил через XML-канал, показывающий самую последнюю запись one. Затем я повторил объект вокруг этого, чтобы воспроизвести видео.

В другом я просмотрел последние четыре записи, вернув элементы списка для списка миниатюр.

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

person Joshua Cody    schedule 07.02.2010