我正在使用PHP的SimpleXML解析XHTML文档。我需要在文档中查询包含特定值的节点的一系列ul,然后找到该节点的父节点的直接先前兄弟代码将有助于解释!
给出以下虚拟xhtml:
<html>
<head></head>
<body>
...
<ul class="attr-list">
<li>Active Life (active)</li>
<ul>
<li>Amateur Sports Teams (amateursportsteams)</li>
<li>Amusement Parks (amusementparks)</li>
<li>Fitness & Instruction (fitness)</li>
<ul>
<li>Dance Studios (dancestudio)</li>
<li>Gyms (gyms)</li>
<li>Martial Arts (martialarts)</li>
<li>Pilates (pilates)</li>
<li>Swimming Lessons/Schools (swimminglessons)</li>
</ul>
<li>Go Karts (gokarts)</li>
<li>Mini Golf (mini_golf)</li>
<li>Parks (parks)</li>
<ul>
<li>Dog Parks (dog_parks)</li>
<li>Skate Parks (skate_parks)</li>
</ul>
<li>Playgrounds (playgrounds)</li>
<li>Rafting/Kayaking (rafting)</li>
<li>Tennis (tennis)</li>
<li>Zoos (zoos)</li>
</ul>
<li>Arts & Entertainment (arts)</li>
<ul>
<li>Arcades (arcades)</li>
<li>Art Galleries (galleries)</li>
<li>Wineries (wineries)</li>
</ul>
<li>Automotive (auto)</li>
<ul>
<li>Auto Detailing (auto_detailing)</li>
<li>Auto Glass Services (autoglass)</li>
<li>Auto Parts & Supplies (autopartssupplies)</li>
</ul>
<li>Nightlife (nightlife)</li>
<ul>
<li>Bars (bars)</li>
<ul>
<li>Dive Bars (divebars)</li>
</ul>
</ul>
</ul>
...
</body>
</html>
我需要能够查询ul.attr-list中的子元素,并发现它的“根”类别。我不能改变不同形式的xhtml。
所以,如果我把“画廊”作为一个类别,我需要知道它属于“艺术”“根”类别。或者,如果我有“dog_parks”,我需要知道它处于“活动”类别。以下代码完成了工作,但只假设最多有两个嵌套级别:
function get_root_category($shortCategoryName){
$url = "http://www.yelp.com/developers/documentation/category_list";
$result = file_get_contents($url);
$dom = new domDocument();
@$dom->loadHTML($result);
$dom->preserveWhiteSpace = false;
$sxml = simplexml_import_dom($dom);
$lvl1 = $sxml->xpath("//li[contains(., '".$shortCategoryName."')]/parent::ul/preceding-sibling::li");
$lvl2 = $sxml->xpath("//li[contains(., '".$shortCategoryName."')]/parent::ul/preceding-sibling::li/parent::ul/preceding-sibling::li");
if($lvl2){
return array_pop($lvl2);
} else {
return array_pop($lvl1);
}
}
必须有一种更好的方法来编写XPath,因此只需要进行一次查询,并且对多个嵌套级别具有相对防弹性。
编辑::感谢那些指出此HTML无效的人。但是,页面的结构已设置,我无法编辑它;我只能将它作为一种资源使用,并且必须使它成为现实。
答案 0 :(得分:1)
怎么样:
/html/body/ul/ul[count(descendant::li[contains(.,'dog_parks')]) > 0]/preceding-sibling::li
这应该适用于深层嵌套列表。它总是成为最上层的类别。
顺便说一下:我认为嵌套ul
不是这样有效的。
答案 1 :(得分:1)
我需要查询一系列的ul 包含a的节点的文档 具体值,然后找到该节点 父母的直接上一个兄弟...
那就是(这里$v
是您要查找的值):
$p = "/html/body//ul[li[contains(text(), '$v')]]/preceding-sibling::li[1]";
$v
不包含单引号,因为这会破坏XPath表达式。[contains(concat(' ', text(), ' '), concat(' ', '$v', ' '))]
。…
缩写完整的字母):[contains(translate(text(), 'ABC…XYZ', 'abc…xyz'), '{strtolower($v)}')]
。text()
可确保仅考虑直接子文本节点。当您使用.
时,<li>
的整个“子树”将转换为字符串,您可能会获得比实际需要的更多结果。//
运算符(descendant
轴的快捷方式)限制在树的某个部分 - 如果您可以进一步限制它,请务必这样做。//
开头会比它需要的速度慢得多,因为检查整个文档的所有节点,即使那些在任何情况下都不会产生匹配的节点。