命名空间元素的所有子项的XPath字符串

时间:2010-12-29 07:18:20

标签: php xml xpath simplexml

刚开始使用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);

2 个答案:

答案 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的根:祖先。