使用XPath拉出包含子节点的完整节点

时间:2009-10-14 14:04:21

标签: php xml xpath simplexml

我正在使用XPath从HTML页面中选择一个部分。但是,当我使用XPath提取节点时,正确仅选择围绕 HTML标记, HTML标记本身。

示例HTML

<body>
    <div>
      At first glance you may ask, &#8220;what <i>exactly</i>
      do you mean?&#8221; It means that we want to help <b>you</b> figure...
    </div>
</body>

我有以下XPath

/body/div

我得到以下

At first glance you may ask, &#8220;what do you mean?&#8221; It means that we want to help figure...

我想要

At first glance you may ask, &#8220;what <i>exactly</i> do you mean?&#8221; It means that we want to help <b>you</b> figure...

如果您在示例HTML中注意到内容中有<i/><b />个HTML标记。当我提取内容时,这些标签中的单词会“丢失”。

如果有所不同,我在PHP中使用SimpleXML。

3 个答案:

答案 0 :(得分:3)

您的XPath很好,但您可以删除最终的/.,因为这是多余的:

/atom/content

所有HTML都在<![CDATA ]]>部分内,因此在XML DOM中,您实际上只有文本。 <i><b>标记不会被解析为标记,而只会显示为文本。使用CDATA部分与XML的编写方式完全相同:

<atom>
    <content>
      At first glance you may ask, &amp;#8220;what &lt;i&gt;exactly&lt;/i&gt;
      do you mean?&amp;#8221; It means that we want to help &lt;b&gt;you&lt;/b&gt; figure...
    </content>
</atom>

因此,无论你在<content>元素之后做什么,都会丢弃这些标签。您是稍后将文本解析为HTML,还是通过过滤器或类似的方式运行?

答案 1 :(得分:1)

SimpleXML不喜欢文本节点,因此您必须使用自定义解决方案。

您可以在每个asXML()元素上使用div,然后移除div代码,也可以将div元素转换为DOMNode s然后循环$div->childNodes并序列化每个孩子。请注意,如果可用,您的HTML实体很可能会替换为实际字符。

或者,您可以查看SimpleDOM project并使用其innerHTML()方法。

$html = 
'<body>
    <div>
      At first glance you may ask, &#8220;what <i>exactly</i>
      do you mean?&#8221; It means that we want to help <b>you</b> figure...
    </div>
</body>';

$body = simpledom_load_string($html);

foreach ($body->xpath('/body/div') as $div)
{
    var_dump($div->innerHTML());
}

答案 2 :(得分:0)

我不知道SimpleXML是否不同,但对我而言,您似乎需要确保选择所有节点类型而不仅仅是文本。在标准XPath中,您可以执行/ body / div / node()