关于PHP SimpleXML和xpath的一些初学者问题

时间:2012-10-30 12:10:10

标签: php xpath simplexml

我正在学习PHP SimpleXML,我有一些问题。 我一直在玩我的工作内联网中的网络代码。我可以随时使用通用代码,因为代码可能随时发生变化。 在我的例子中,我选择了一个div标签及其所有子节点。

...
  <div class="cabTabs">
      <ul>
          <li><a href="/link1">Info1</a></li>
          <li><a href="/link2">Info2</a></li>
          <li><a href="/link3">Info3</a></li>
      </ul>
  </div>
...


//Get all web content:
$b = new sfWebBrowser(); //using symfony 1.4.17 sfWebBrower to get a SimpleXML object.
$b->get('http://intranetwebexample'); //returns a sfWebBrower object.
$xml = $b->getResponseXML(); //returns a SimpleXMLElement

//[Eclipse xdebug Watch - $xml]
"$xml"    SimpleXMLElement     
  @attributes Array [3]   
  head    SimpleXMLElement    
  body    SimpleXMLElement


//Get the div class="cabTabs".
$result = $xml->xpath('//descendant::div[@class="cabTabs"]'); 

//[Eclipse xdebug Watch - $result]
"$result" Array [1]   
  0   SimpleXMLElement    
      @attributes Array [1]   
          class   cabTabs 
      ul  SimpleXMLElement    
          li  Array [6]


问题:

  1. 使用descendant :: prefix:
    我已经读过其他stackoverflow主题,不建议使用descendant :: prefix。 为了选择标签及其所有内容,应该采用哪种方式? 我使用上面的代码,但不知道它是否是正确的方法。

  2. 检查Eclipse xdebug变量的一些问题观察:
  3. 2.1有时我无法将SimpleXML树扩展为多个或多个级别。在上面的示例中,我无法访问/查看下面的“li”节点,并查看其子节点 它可能是使用SimpleXML对象的xdebug调试器的限制,还是Eclipse Watch的限制? 当我使用通常的循环访问其父级时,我可以完美地展开/查看“li”节点:foreach($ ul-&gt; li as $ li)。
    然而,它不是一个关键的错误,我认为直接看到它并在适当的论坛上报告是完美的。

    2.2我不理解$ xml-&gt; xpath的所有结果代码:
    如果我们看看Eclipse Watch,“div”标签已被转换为0索引键,但“ul”和“li”标签有原始名称,为什么?

    2.3如何使用通用代码访问/循环xpath内容:
    我使用以下非通用代码来访问它:

    foreach ($result as $record) {        
        foreach($record->ul as $ul) { 
            foreach($ul->li as $li) {
                foreach($li->a as $a) {
                    echo ' ' . $a->name;
                }
            }
        }
    }
    

    上述代码有效,但前提是我们编写正确的标记名称。 ( - &gt; ul, - &gt; li, - &gt; a ..)
    循环遍历其所有内容而不必每次都指定子名称的通用方法是什么? ( - &gt; ul, - &gt; li, - &gt; a ..)
    此外,我宁愿不必将其转换为数组,除非它是正确的方式 我一直在尝试使用children()属性,但它不起作用,它会在该行停止并崩溃:foreach($ result-&gt; children()为$ ul)

    非常感谢你花时间阅读我的问题。任何帮助真的很受欢迎:)

    系统信息:
    symfony 1.4.17 with sfWebBrowserPlugin,cURL dadapter。
    启用了cURL支持的PHP 5.4.0,cURL信息7.24.0

3 个答案:

答案 0 :(得分:1)

  1. 我不知道自己从未使用过它

  2. 不知道我通常使用Zend Debug - 但我还是不明白你的问题......我想你遗漏了一些话: - )

  3. 2.1可能xdebug / eclipse。 Id检查首选项可能是一个限制递归量以帮助管理内存的设置。

    2.2 SimpleXML::xpath始终返回匹配节点的数组。这就是为什么你有结果的整数索引数组。因此,如果您执行//someelement,则会获得所有someelement个标记的数组。然后,您可以像$someelement->itschildelement一样以正常方式访问其后代。

    2.3 $result->children()是获得一般意义上的事物的好方法。如果Xdebug崩溃只是xdebug。要么关闭它,忽略它,要么找到一个不同的调试器:-) Xdebug是一个工具,但不应该决定你如何实现。

答案 1 :(得分:0)

我认为现在我完全理解问题2.2和2.3。

由于它的xpath返回一个Array [1],如你所解释的,而不是SimpleXML对象,我不能使用$ result-&gt; children()因为php数组没有child()属性。 (我有点白痴哈哈)。

解决方案很简单,正如您所解释的那样,计算数组的元素数量,循环到元素中,然后使用children属性再次循环,如果它是SimpleXML对象。我会在下面添加正确的代码。

我还会将Eclipse Watch或xdebug的第1点问题提交到他们的论坛,以便猜测真正的问题。

谢谢prodigitalson,非常有用的答案:)

答案 2 :(得分:0)

像魅力嘿嘿一样工作。

这里我添加一个完整的函数,它以递归的方式在节点的所有属性中搜索子字符串,并返回找到它的完整字符串。

在我的情况下,它非常适合搜索某些值,例如href =和其他dinamically生成的标记值。 还显示了我们上面谈到的内容的实现。可能它可以改进,可以添加更安全的检查。

/* public function bSimpleXMLfindfullstringwithsubstring($node, $sSearchforsubstring, &$sFullstringfound, &$bfoundsubstring)
 * Recursive function to search for the first substring in a list of SimpleXML objects, looking in all its children, in all their attributes.
 * Returns true if the substring has been found.
 * Parameter return:
 *   $sFullstringfound: returns the full string where the substring has been found.
 *   $bfoundsubstring: returns true if the substring has been found.
*/

public function bSimpleXMLfindfullstringwithsubstring($node, $sSearchforsubstring, &$sFullstringfound, &$bfoundsubstring=false)
{
  $bRet = false; 
  if ((isset($node) && ($bfoundsubstring == false)))
  {
      //If the node has attributes
      if ($node->attributes()->count() > 0)
      {
          //Search the string in all the elements of the current SimpleXML object.
          foreach ($node->attributes() AS $name => $attribute)  //[$name = class , (string)$attribute = cabTabs, $attribute = SimpleXML object]
          {
              //(Take care of charset if necessary).
              if (stripos((string)$attribute, $sSearchforsubstring) !== false)
              {
                  //substring found in one of the attributes.
                  $sFullstringfound = (string)$attribute;
                  $bfoundsubstring = true;
                  $bRet = true;
                  break;
              }
          }
      }

      //If the node has childrens (subnodes)
      if (($node->count() > 0) && ($bfoundsubstring == false))
      {
          foreach ($node->children() as $nodechildren)
          {
              if ($bfoundsubstring == false)
              {
                  //Search in the next children.
                  self::bSimpleXMLfindfullstringwithsubstring($nodechildren, $sSearchforsubstring, $sFullstringfound, $bfoundsubstring);
              }
              else
              {
                  break;
              }
          }
      }
  }
  return $bRet;
}

如何称呼它:

$b = new sfWebBrowser();
$b->get('http://www.example.com/example.html');
$xml = $b->getResponseXMLfixed();     
$result = $xml->xpath('//descendant::div[@class="cabTabs"]'); //example

$sFullString = "";
$bfoundsubstring = false;
foreach ($result as $record)
{
  self::bSimpleXMLfindfullstringwithsubstring($record, "/substring/tosearch", $sFullString, $bfoundsubstring);
}
相关问题