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')
开发者_StackOverflow
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?
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', ')']
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.
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.
精彩评论