lxml XPath- filter all text including tails

Viewed 998

I'm trying to filter out text from a website using lxml and Python, however, the formatting can be very irregular. (It's a forum.)

So for example, I might have:

<a>
   <c>
      <d>
         MARKER some text
      </d>
   </c>
   MARKER other text 1
   <b>MARKER other text 2</b>
   M<b>ARKE</b>R <e>other</e> text 3
</a>

I would like my xpath to return me:

MARKER other text 1
<b>MARKER other text 2</b>
M<b>ARKE</b>R <e>other</e> text 3

So in other words, I want to be able to parse nested text, but also return the text with markup.

What I currently have is:

filter = "//text()[not(parent::d[parent::c]) and contains(., 'MARKER')]"
filtered = root.xpath(self.vote_xpath)
for i in filtered:
    print(i)

where root is an elementtree parsed from a string, which returns me:

MARKER other text 1
MARKER other text 2

This fails in returning me the last text with the MARKER, and fails in keeping the formatting that I want.

How should I proceed from here?

EDIT: OK, I've been fiddling a bit with the xpath.

//node()[not(parent::d[parent::c]) and contains(., 'MARKER')]

run on:

<a>
   <c>
      <d>
         some text
      </d>
   </c>
   other text 1
   <b>other text 2</b>
   M<b>ARKE</b>R <e>other</e> text 3
</a> 

successfully registers the MARKER broken up by the <b> tags, since the node() passes the node entire to the contains filter. However, it returns as a match the parent node entire, in this case it simply returns the entire <a> node with all its contents.

How should I proceed so that the xpath returns only the matched portion?

1 Answers
Related