7

我正在编写一个脚本,该脚本需要一个网页并检测使用了多少次像 facebook like 按钮这样的东西。因为这最好用 DOM 来完成,所以我决定使用 PHP 的 DOMDocument。

不过,我遇到的一个问题是对于像 facebook 的点赞按钮这样的元素:

<fb:like send="true" width="450" show_faces="true"></fb:like>

由于此元素在技术上具有“fb”命名空间,因此 DOMDocument 会引发警告,指出未定义此命名空间前缀。然后它继续剥离前缀,所以当我到达所述元素时,它的标签不再是fb:like,而是like

有没有办法“预注册”一个命名空间?有什么建议么?

4

6 回答 6

4

在使用 xml 解析器之前,您可以使用tidy来修饰它。

$tidy = new tidy();
$config = array(
    'output-xml'   => true, 
    'input-xml'    => true, 
    'add-xml-decl' => true,
);
$tidy->ParseString($htmlSoup, $config);
$tidy->cleanRepair();
echo $tidy;
于 2012-06-11T19:27:18.363 回答
1

由于这从未“解决”,我决定继续为不喜欢弄清楚正则表达式的其他人实施syndance的解决方案。

// do this before you use loadHTML()    
// store any name spaced elements so we can re-add them later
$postContent = preg_replace('/<(\w+):(\w+)/', '<\1 data-namespace="\2"' , $postContent);

// once you are done using domdocument fix things up
// re-construct any name-spaced tags
$postContent = preg_replace('/<(\w+) data-namespace="(\w+)"/', '<\1:\2 ' , $postContent);
于 2015-08-12T19:02:10.877 回答
0

Is this what you are looking for?

You could try SimpleHTMLDOM. You can then run something like...

$html = new simple_html_dom();
$html->load_file('fileToParse.html');
$count=0;
foreach($html->find('fb:like') as $element){
    $count+=1
}
echo $count;

That should work.

I looked a bit further and found this. I took this from the DOMDocument on PHP.net.

$dom = new DOMDocument;
$dom->loadHTML('fileToParse.html'); // or $dom->loadXML('fileToParse.html'); 
$likes = $dom->getElementsByTagName('fb:like');
$count=0;
foreach ($likes as $like) {
    $count+=1;
}

After this one I am stuck

$file=file_get_contents("other.html");
$search = '/<fb:like[^>]*>/';
$count  = preg_match_all($search , $file, $matches);
echo $count;
//Below is not needed
print_r($matches);

That however is RegEx and is quite slow. I Tried:

$dom = new DOMDocument;
$xpath = new DOMXPath($dom);
$dom->load("other.html");
$xpath = new DOMXPath($dom);
$rootNamespace = $dom->lookupNamespaceUri($dom->namespaceURI); 
$xpath->registerNamespace('fb', $rootNamespace); 
$elementList = $xpath->query('//fb:like'); 

But got the same error as you.

于 2012-06-11T18:25:30.733 回答
0

一直无法找到一种方法来做到这一点DOM。我很惊讶正则表达式比DOMDocument我通常不是这样。 strpos不过应该是最快的:

strpos($dom, '<fb:like');

这只会找到第一次出现,但您可以编写一个简单的递归函数来适当地更改偏移量。

于 2012-06-12T16:35:32.850 回答
0

我遇到了同样的问题,我想出了以下解决方案/解决方法:

没有使用 DOMDocument 解析带有命名空间的 HTML 而不丢失命名空间的干净方法,但是有一些解决方法:

  • 使用另一个在 HMTL 代码中接受名称空间的解析器。在此处查找 HTML 解析器的详细列表。这可能是最有效的方法。
  • 如果你想坚持使用 DOMDocument,你基本上必须对代码进行预处理和后处理。

    • 在将代码发送到 DOMDocument->loadHTML 之前,请使用正则表达式、循环或任何您想要查找所有命名空间标记的方式,并将自定义属性添加到包含命名空间的开始标记。

      <fb:like send="true" width="450" show_faces="true"></fb:like>
      

      然后会导致

      <fb:like xmlNamespace="fb" send="true" width="450" show_faces="true"></fb:like>
      
    • 现在将编辑后的代码提供给 DOMDocument->loadHTML。它会去除命名空间,但会保留导致的属性

      <like xmlNamespace="fb" send="true" width="450" show_faces="true"></like>
      
    • 现在(再次使用正则表达式、循环或任何你想要的)找到所有带有属性 xmlNamespace 的标签,并用实际的命名空间替换该属性。不要忘记将命名空间也添加到结束标签中!

我不认为 OP 仍在寻找答案,我只是为在他们的研究中找到这篇文章的任何人发布这个。

于 2015-05-10T07:54:24.470 回答
-1

尝试了正则表达式解决方案...结束标签有问题,因为它们不接受属性!

<ns namespace="node">text</ns>

(最重要的是,正则表达式没有寻找结束标签......)所以最后我做了一些丑陋的东西,比如

$output = preg_replace('/<(\/?)(\w+):(\w+)/', '<\1\2thistaghasanamespace\3' , $output);

$output = preg_replace('/<(\/?)(\w+)thistaghasanamespace(\w+)/', '<\1\2:\3' , $output);
于 2016-02-16T16:14:55.890 回答