0

我正在学习 PHP SimpleXML,我有一些问题。我一直在玩从我工作的 Intranet 中的 web 获取代码。我尽可能需要通用代码,因为代码可能随时更改。在我的示例中,我选择了一个 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:: 前缀:
    我在其他 stackoverflow 主题中读到不推荐使用 descendant:: 前缀。为了选择标签及其所有内容,正确的方法应该是什么?我使用上面的代码,但不知道它是否正确。

  2. 检查 Eclipse xdebug 变量 Watch 的一些问题:

2.1 有时我不能将 SimpleXML 树扩展不止一层。在上面的示例中,我无法访问/查看下面的“li”节点,也无法查看其子节点。
可能是 xdebug 调试器与 SimpleXML 对象的限制,还是 Eclipse Watch 的限制?
当我使用通常的循环访问其父节点时,我可以完美地展开/查看“li”节点:foreach($ul->li as $li)。
然而它不是一个严重的错误,我认为直接看到它并在适当的论坛上报告它是完美的。

2.2 我完全看不懂$xml->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;
            }
        }
    }
}

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

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

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

4

3 回答 3

1
  1. 我不知道我自己没用过

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

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

2.2SimpleXML::xpath总是返回一个匹配的节点数组。这就是为什么你有整数索引数组作为你的结果。因此,如果您这样做,您将获得所有标签//someelement的数组。someelement然后,您可以以正常方式访问它们的后代,例如$someelement->itschildelement.

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

于 2012-10-30T12:32:09.697 回答
0

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

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

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

我还将向他们的论坛提交 Eclipse Watch 或 xdebug 的第 1 点问题,以猜测真正的问题是什么。

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

于 2012-10-30T13:04:23.130 回答
0

工作就像一个魅力呵呵。

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

在我的情况下,它非常适合搜索一些值,如 href=,以及其他动态生成的标签值。还显示了我们上面讨论的内容的实现。可能它可以改进并且可以添加更安全的检查。

/* 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);
}
于 2012-10-30T16:48:31.210 回答