这两天研究 HTML 的 DOM 需要寻找某个 Element 元素的完整 XPath 路径,由于使用的是 PHP Simple HTML DOM Parser 开源库,这个库类的使用方法几乎兼容 Javascript 的 DOM 语法并附带 DOM 选择器。虽然功能强大但是并不能直接获取 Element 的 XPath。这个怎么办呢,依稀记得 Firebug 有一个功能,选择某个元素在它的控制台可以显示 XPath。嗯,着手实践一下发现不仅可以显示而且还可以复制 XPath。

于是想,如果可以找到 Javascript 版的相关代码就一定可以改成 PHP 版本的,结果在 Google 搜索找到了…

 1var elt = document.getElementById('table');
 2var xpath = getElementXPath(elt);alert(xpath);
 3
 4// Get full XPath of an element
 5function getElementXPath(elt){
 6	var path = "";
 7	for (; elt && elt.nodeType == 1; elt = elt.parentNode)
 8	{
 9		idx = getElementIdx(elt);
10		xname = elt.tagName;
11		if (idx > 1) xname += "[" + idx + "]";
12		path = "/" + xname + path;
13	}
14	return path;
15}
16
17// Get Idx of an element
18function getElementIdx(elt){
19	var count = 1;
20	for (var sib = elt.previousSibling; sib ; sib = sib.previousSibling)
21	{
22		if(sib.nodeType == 1 && sib.tagName == elt.tagName)  count++
23	}
24	return count;
25}

PHP 改进版:

 1// Use it before import PHP Simple HTML DOM Parser
 2$html = file_get_html('http://www.google.com/');
 3
 4// find a sample element by id
 5$elt1 = $html->find('#footer', 0);
 6
 7// find a sample element by tag name
 8$elt2= $html->find('div', 10);
 9
10// it will return if found it: [@id="footer"]
11$xpath = getElementXPath($elt1);
12
13// it will return if found it: html/body/div[10]
14$xpath = getElementXPath($elt2);
15
16function getElementXPath($elt){
17	$path = '';
18	$first = TRUE;
19	for(; ($elt AND $elt->nodetype == 1); $elt = $elt->parent())
20	{
21		$xname = $elt->tag;
22		$idx = getElementIdx($elt);
23		if ($first AND isset($elt->attr['id']))
24		{
25			$path = '//*[@id="' . $elt->attr['id'] . '"]';
26			break;
27		}
28
29		if ($idx > 1)
30		{
31			%xname .= '[' . $idx . ']';
32		}
33
34		$path = '/'.$xname.$path;
35		$first = FALSE;
36	}
37
38	return $path;
39}
40
41function getElementIdx($elt){
42	$count = 1;
43	for($sib = $elt->prev_sibling(); $sib ; $sib = $sib->prev_sibling())
44	{
45		if($sib->nodetype == 1 && $sib->tag == $elt->tag)
46		{
47			$count++;
48		}
49	}
50	return $count;
51}

大家同样可以把上面的代码直接 crack 到 PHP Simple HTML DOM Parser 库中。