如何使用xpath仅选择某些标签和文本?

时间:2011-04-12 02:34:31

标签: python xpath

例如,html block:

<p><b>text1</b> (<span><a href="#1">asdf</a>text2</span>)</p>

我需要选择所有标签“a”,所有其余标签必须是纯文本,就像我们在浏览器中看到的一样:

result = ["text1", " (", <tag_a>, "text2", ")"]

或类似的东西。

尝试:

hxs.select('.//a|text()')

在这种情况下,它会找到所有标签“a”,但文本仅从直接子节点返回。

同时:

hxs.select('.//text()|a')

获取所有文本,但仅使用直接子项标记“a”。

更新

    elements = []
    for i in hxs.select('.//node()'):
        try:
            tag_name = i.select('name()').extract()[0]
        except TypeError:
            tag_name = '_text'

        if tag_name == 'a':
            elements.append(i)
        elif tag_name == '_text':
            elements.append(i.extract())

有更好的方法吗?

3 个答案:

答案 0 :(得分:1)

在我看来,好像你正在超越XPath领域。 XPath擅长从输入中选择事物而不是构造输出。当然,它被设计用于XSLT,其中XSLT指令处理输出端。我不确定Python的等价物是什么。

答案 1 :(得分:1)

这是你要找的东西吗?

您可以使用etree.strip_tags

从块中删除后代标记
from lxml import etree
d = etree.HTML('<html><body><p><b>text1</b> (<span><a href="#1">asdf</a>text2</span>)</p></body></html>')
block = d.xpath('/html/body/p')[0]
# etree.strip_tags apparently takes a list of tags to strip, but it wasn't working for me
for tag in set(x.tag for x in block.iterdescendants() if x.tag != 'a'):
  etree.strip_tags(block,tag)

block.xpath('./text()|a')

收率:

['text1', ' (', <Element a at fa4a48>, 'text2', ')']

答案 2 :(得分:1)

这些相对 XPath表达式:

.//text()|.//a

或者

.//node()[self::text()|self::a]

表示来自上下文节点的所有后代文本节点或a元素。

注意:由主机语言或XPath引擎决定是否按文档顺序排序此节点集结果。根据定义,节点集是无序的。