Вопрос Simple_DOM о поиске классов

#php #html #class #object #simpledom

#php #HTML #класс #объект #simpledom

Вопрос:

Я пытаюсь выполнить простое извлечение, но продолжаю получать непредсказуемые результаты.

У меня есть этот HTML-код

 <div class="thread" style="margin-bottom:25px;"> 

<div class="message"> 

<span class="profile">Suzy Creamcheese</span> 

<span class="time">December 22, 2010 at 11:10 pm</span> 

<div class="msgbody"> 

<div class="subject">New digs</div> 

Hello thank you for trying our soap. <BR>  Jim.

</div> 
</div> 


<div class="message reply"> 

<span class="profile">Lars Jörgenmeier</span> 

<span class="time">December 22, 2010 at 11:45 pm</span> 

<div class="msgbody"> 

I never sold you any soap.

</div> 

</div> 

</div> 
  

И я пытаюсь извлечь внешний текст из «msgbody», но только тогда, когда «профиль» чему-то равен. Вот так.

 $contents  = $html->find('.msgbody');
$elements = $html->find('.profile'); 

           $length = sizeof($contents);

           while($x != sizeof($elements)) {

            $var = $elements[$x]->outertext;

                        //If profile = the right name
            if ($var = $name) {

                                    $text = $contents[$x]->outertext;
                echo $text;

            }



            $x  ;
         }    
  

Я получаю текст из неправильных профилей, а не из тех, которые содержат нужные мне ассоциации.
Есть ли способ просто извлечь нужную информацию с помощью одной строки кода?

Например, если span-profile = «правильное имя», то извлеките его div-msgbody

Ответ №1:

Хорошо, я собираюсь использовать DOMXPath в этом вопросе. Я не уверен, что должен означать «внешний текст», но я соглашусь с этим требованием:

Например, если span-profile = «правильное имя», тогда извлеките его div-msgbody

Во-первых, вот сокращенный HTML-тестовый пример, который я использовал:

 <html>
<body>
<div class="thread" style="margin-bottom:25px;"> 

<div class="message"> 

<span class="profile">Suzy Creamcheese</span> 

<span class="time">December 22, 2010 at 11:10 pm</span> 

<div class="msgbody"> 

<div class="subject">New digs</div> 

Hello thank you for trying our soap. <BR>  Jim.

</div> 
</div> 


<div class="message reply"> 

<span class="profile">Lars Jörgenmeier</span> 

<span class="time">December 22, 2010 at 11:45 pm</span> 

<div class="msgbody"> 

I never sold you any soap.

</div> 

</div> 

</div>
</body>
</html>
  

Итак, мы создадим запрос XPath для этого. Давайте покажем все это целиком, а затем разберем:

 $messages = $xpath->query("//span[@class='profile' and contains(.,'$profile_name')]/../div[@class='msgbody']");
  

Разрушение:

//span

Дайте мне промежутки

//span[@class=’profile’]

Дайте мне интервалы, в которых класс является profile

//span[@class=’profile’ и содержит(.,’$profile_name’)]

Дайте мне интервалы, в которых класс является profile, а внутренняя часть интервала содержит $profile_name имя, которое вам нужно

//span[@class=’profile’ и содержит(.,’$profile_name’)]/../

Дайте мне промежутки, где класс является profile, а внутренняя часть промежутка содержит $profile_name , это имя, которое вам нужно, теперь поднимитесь на уровень, который приведет нас к <div
class="message">

//span[@class=’profile’ и содержит(.,’$profile_name’)]/../div[@class=’msgbody’]

Дайте мне промежутки, где класс является profile, а внутренняя часть промежутка содержит $profile_name , это имя, которое вам нужно, теперь поднимитесь на уровень, который приведет нас к <div
class="message">
и, наконец, дайте мне все разделы в разделе, <div class="message"> где класс — msgbody

Итак, вот пример кода PHP:

 $doc = new DOMDocument();
$doc->loadHTMLFile("test.html");

$xpath = new DOMXpath($doc);
$profile_name = 'Lars Jörgenmeier';
$messages = $xpath->query("//span[@class='profile' and contains(.,'$profile_name')]/../div[@class='msgbody']");
foreach ($messages as $message) {
  echo trim("{$message->nodeValue}") . "n";
}
  

XPath очень мощный, как это. Я рекомендую просмотреть базовый учебник, затем вы можете проверить стандарт XPath, если хотите увидеть более продвинутое использование.

Комментарии:

1. вау, чувак, это много краткой информации. спасибо за преобразование xpath. мне нравится Simple_DOM, но это приводит к потере памяти!

2. Кроме того, я заметил, что вам нужно вставить это в заголовок, чтобы получить эти специальные символы, такие Jörgenmeier как передача XPath.

3. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

4. @user734063 хм, интересно.. вероятно, вам нужен только <meta http-equiv="Content-Type" ....> бит, чтобы быть честным. Скорее всего, у меня это сработало, поскольку я сохранил файл локально и по умолчанию установил UTF-8.

Ответ №2:

Это простой рабочий пример HTML DOM.

Я изменил ваш пример html, чтобы было больше одного профиля для Suzy Creamcheese следующим образом: (файл: test_class_class.htm )

  <div class="message"> 
   <span class="profile">Suzy Creamcheese</span> 
   <span class="time">December 22, 2010 at 11:10 pm</span> 
   <div class="msgbody"> 
     <div class="subject">New digs</div> 
       Hello thank you for trying our soap. <BR>  Jim.
     </div> 
   </div> 

   <div class="message reply"> 
     <span class="profile">Lars Jörgenmeier</span> 
     <span class="time">December 22, 2010 at 11:45 pm</span> 
     <div class="msgbody"> 
       I never sold you any soap.
     </div> 
   </div> 
 </div>

 <div class="message"> 
   <span class="profile">Suzy Yogurt</span> 
   <span class="time">December 22, 2010 at 11:10 pm</span> 
   <div class="msgbody"> 
     <div class="subject">No Creamcheese</div> 
       This is not Suzy Creamcheese <BR>  Jim.
     </div> 
   </div> 

   <div class="message reply"> 
     <span class="profile">Suzy Creamcheese</span> 
     <span class="time">December 22, 2010 at 11:45 pm</span> 
     <div class="msgbody"> 
       A reply from Suzy Creamcheese.
     </div> 
   </div> 
 </div>

</div>
  

Вот мой тест с использованием простого HTML DOM:
включить(‘simple_html_dom.php ‘);

 function getMessage_for_profile($iUrl,$iProfile)
{
    // create HTML DOM
    $html = file_get_html($iUrl);

    // get text elements
    $aoProfile = $html->find('span[class=profile]'); 
    echo "Found ".count($aoProfile)." profiles.<br />";

    foreach ($aoProfile as $key=>$oProfile)
    {
      if ($oProfile->plaintext == $iProfile)
      {
        echo "<b>Profile ".$key.": ".$oProfile->plaintext."</b><br />";
// Using $e->next_sibling ()
        $oCurrent = $oProfile;
        while ($oNext = $oCurrent->next_sibling())
        {
           if ( $oNext->class == "msgbody" )
           {
             echo "<hr />";
             echo $oNext->outertext;
             echo "<hr />";
           }
           $oCurrent = $oNext;
        }
      }         
    }

    // clean up memory
    $html->clear();
    unset($html);

    return;
}
// --------------------------------------------
// test it!
// user_agent header...
ini_set('user_agent', 'My-Application/2.5');

getMessage_for_profile('test_class_class.htm','Suzy Creamcheese');
echo "<br /><br /><br />";
getMessage_for_profile('test_class_class.htm','Suzy Yogurt');
  

Мой вывод был:

 Found 4 profiles.
Profile 0: Suzy Creamcheese
--------------------------------
New digs
Hello thank you for trying our soap.
Jim.
---------------------------------
Profile 3: Suzy Creamcheese
---------------------------------
A reply from Suzy Creamcheese.
---------------------------------



Found 4 profiles.
Profile 2: Suzy Yogurt
---------------------------------
No Creamcheese
This is not Suzy Creamcheese
Jim.
---------------------------------
  

Смотрите, это можно сделать с помощью простого HTML DOM, и поскольку я уже знаю, как работает DOM … или достаточно, чтобы попасть в беду… Мне не нужно было изучать какой-либо известный синтаксис!