刚开始使用XPath,并使用PHP的SimpleXML
对象实现它。现在我正在使用//zuq:*
在给定文档中创建SimpleXML
前缀zuq
的{{1}}对象数组。但是,我希望SimpleXML
个对象引用所有后代,而不管命名空间如何。我尝试使用//child::zuq:*
,但它创建的SimpleXML
树似乎并不完整。
基本上,捕获的对象应该是整个文档中zuq
命名空间的所有顶级对象,包含所有后代元素,无论命名空间如何,包括zuq
。
tl; dr:如何从给定文档创建SimpleXML
对象树,其中每个SimpleXML
根对象是给定命名空间的最高级别文档元素(例如{{ 1}})包含所述元素的所有后代,而不管后代名称空间? XPath不是必需的,但根据我的阅读似乎是最好的选择。
的test.html
zuq
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:zuq="http://localhost/zuq">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body>
<h1>Heading</h1>
<p>Paragraph</p>
<zuq:region name="myRegion">
<div class="myClass">
<h1><zuq:data name="myDataHeading" /></h1>
<p>
<zuq:data name="myDataParagraph">
<zuq:format type="trim">
<zuq:param name="length" value="200" />
<zuq:param name="append">
<span class="paragraphTrimOverflow">...</span>
</zuq:param>
</zuq:format>
</zuq:data>
</p>
</div>
</zuq:region>
</body>
</html>
产地:
$sxml = simplexml_load_file('test.html');
$sxml_zuq = $sxml->xpath('//zuq:*/descendant-or-self::node()');
print_r($sxml_zuq);
答案 0 :(得分:2)
不要相信print_r语句的输出......它似乎显示了一个空对象,但在我的测试中,孩子们实际上仍然存在。例如,从上面的代码开始:
$sxml = simplexml_load_file('test.html');
$sxml_zuq = $sxml->xpath('//zuq:*/descendant-or-self::node()');
如果我随后尝试这样的命令:
print_r($sxml_zuq[0]->div->h1);
我得到了这个输出:
SimpleXMLElement Object
(
)
似乎是空的,对吧?但是如果我修改命令看起来像这样:
echo $sxml_zuq[0]->div->h1->asXML();
我得到了带有命名空间子项的结果树:
<h1><zuq:data name="myDataHeading"/></h1>
我不是百分之百确定这是为什么;它可能与print_r语句有关,它试图压扁simplexml对象而不是正确处理命名空间。但是当你保留从xpath调用返回的simplexml对象本身时,所有的子对象都会被保留。
现在,关于你的xpath本身,你可能不想要“后代或自我”轴,因为它不仅匹配顶级zuq元素,而且还匹配其所有子元素并创建一个比你真正寻求回归更大的数组(除非我误解了你的要求)。如果您尝试这样的事情:
$sxml_zuq = $sxml->xpath('//zuq:*[not(ancestor::zuq:*)]');
然后你将获得一个只有顶级zuq命名空间元素的数组。 (虽然您的示例XML只有一个这样的顶级元素,但您的实际数据可能在该级别有几个兄弟)。然后,您可以捕获每个顶级元素的内容,如下所示:
foreach ($sxml_zuq as $zuq_node) {
echo ($zuq_node->asXML());
}
如果你想重复这个过程但是在默认命名空间中搜索顶级(或任何)元素,事情会变得有点棘手;你必须使用registerNamespace函数为默认命名空间赋予一个临时前缀,并对其进行xpath搜索。
答案 1 :(得分:1)
我认为你正在寻找//zuq:*/descendant-or-self::*
。这将导致所有具有zuq
名称空间前缀的根的子树。
观察到的行为似乎是SimpleXML的工件(XPath规范不处理XPath查询输出中的树,只处理单独的节点)。您可以使用
之类的东西来解决它 //zuq:*[not(ancestor::zuq:*)]/descendant-or-self::*
ancestor [...]检查是否存在条件为真的祖先 - 即是否存在具有zuq前缀的祖先。所以你应该只得到zuq:没有zuq的根:祖先。