Reputation: 1516
I would like to extract the text within the following HTML. However, everything that occurs within an enclosed HTML tag and everything that comes after it should be ignored.
The HTML appears in different forms.
<span class="classA">Text 1 <span class="classB">Text 2</span> Text 3 <span class="classC">Text 4</span> Text 5</span>
Desired result: "Text 1 Text 2 Text 3"
Other variants:
<span class="classA">Text 1 <span class="classC">Text 2</span></span>
<span class="classA">Text 1 <span class="classC">Text 2</span> Text 3</span>
<span class="classA">Text 1</span>
Desired result: "Text 1"
<span class="classA">Text 1 <span class="classB">Text 2</span> Text 3</span>
Desired result: "Text 1 Text 2 Text3"
So everything after the occurrence of a span element with class "classC" should be ignored. It's also possible that "classC" doesn't appear at all.
I already tried //span[@class="classA"]//text()[parent::*[not(@class="classC")]]
, this ignores "classC" content, but returns the text after <span class="classC">
(Text 5 from the first example).
How can I achieve this?
Update:
With //span[@class="classC"]//parent::*/preceding::text()
I'm getting a little closer to the matter. However, it still doesn't work with <span class="classA">Text 1</span>
, which returns noting.
Upvotes: 1
Views: 50
Reputation: 4834
Try this XPath:
//text()[not(preceding::span[@class="classC"]|ancestor::span[@class="classC"])]
but as Michael Kay said it could be very inefficient, depending on your source html.
Upvotes: 1
Reputation: 163262
You haven't said which XPath version you are using. This is quite hard to achieve using XPath 1.0 which is all that PHP's DOMXPath supports.
Logically you can do
.//text() except .//span[@class="ClassC"]/following::text()
but the except
operator requires XPath 2.0. A workaround is that in XPath 1.0 you can rewrite (A except B)
as A[count(.|B)!=count(B)]
but it's potentially very inefficient.
Upvotes: 1