Mikhail M.
Mikhail M.

Reputation: 5948

How to select only certain tag and text using xpath?

For example, html block:

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

I need to select all tags "a" and all the rest must be the plain text just like we see in browser:

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

or something like that.

Tried:

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

in this case it finds all tags "a" but text is returned only from direct children.

At the same time:

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

gets all texts, but tags "a" only from direct children.

UPDATE

    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())

is there a better way?

Upvotes: 0

Views: 945

Answers (3)

user357812
user357812

Reputation:

These relative XPath expressions:

.//text()|.//a

Or

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

Meanning: all descendant text nodes or a elements from the context node.

Note: It's up to the host language or the XPath engine whether this node set result is ordered by document order or not. By definition, node sets are unorderd.

Upvotes: 1

MattH
MattH

Reputation: 38247

Is this the kind of thing you're looking for?

You can remove the descendant tags from the block using 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')

Yields:

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

Upvotes: 1

Michael Kay
Michael Kay

Reputation: 163262

It looks to me as if you are stepping beyond XPath territory. XPath is good at selecting things from the input but not at constructing output. It was designed, of course, for use with XSLT where XSLT instructions handle the output side. I'm not sure what the Python equivalent would be.

Upvotes: 1

Related Questions