0

So I need to get a particular text in a webpage that contains 200+ lines of text outside a tag or after span tag.

I was able to get the exact xpath,

By outputVersion = By.xpath("//*[@class='output']/text()[contains(.,'TEXT THAT I NEED')]");
By outputVersion = By.xpath("//*[@class='timestamp']/following-sibling::text()[contains(.,'TEXT THAT I NEED')]");

Although it has text() on the xpath that I have came up with and using this, I'm having org.openqa.selenium.InvalidSelectorException whenever I use getText(), getAttribute("value") and getAttribute("innerText").

The actual page elements looks likes this

<pre class="output">
    <span class="timestamp">time</span>
    "TEXT"

    <span class="timestamp">time</span>
    "TEXT"
    .
    .
    .
    .
    .
    <span class="timestamp">time</span>
    "TEXT THAT I NEED"  
    .
    .
    .
    .
    .
</pre>

With that, I need to come up with an xpath excluding text() on it.

Please note that the <span class="timestamp">time</span> are more than 200+ lines with different texts and are changing from time to time. Also the text that I need is not in a fixed line location so I'm dependent to the contains

ohlori
  • 312
  • 1
  • 8
  • 22
  • This depends on the hosting language XPath API. Is there any method for handling text nodes results? – Alejandro Apr 05 '19 at 16:51
  • @Alejandro, there is an alternative to locate an element using text node. please refer my answer – NarendraR Apr 09 '19 at 06:32
  • The issue is about WebDriver specification see https://github.com/w3c/webdriver/issues/340 – Alejandro Apr 10 '19 at 13:22
  • 1
    @Miel Yan, Does any answer resolve you issue ? If yes then please accept the answer by click on tick mark below the vote count on answer. So it can be helpful for others. If no then update your question with more details or feel free to ask in comments. Thanks :) – NarendraR Mar 05 '20 at 12:16

3 Answers3

1

Here is the method to get only parent text.

Java implementation:

public String get_text_from_parent_by_postion(WebDriver driver, WebElement element, int textPosition) {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    return (String) js.executeScript("var parent = arguments[0];var textPosition = arguments[1]; var txtPosition = 0; var child = parent.firstChild; var textValue=''; while(child) { if (child.nodeType === 3){ if (txtPosition===(textPosition-1)){ textValue = child.textContent; break;}}else{txtPosition+=1;}child = child.nextSibling; } return textValue;", element, textPosition);
}

This is how to call this method in your case -

WebElement element = driver.findElement(By.xpath("//p[@class='output']"));
get_text_from_parent_by_postion(driver, element,3)

python implementation:

        def get_text_from_parent_by_postion(element, textPosition=1):
    return driver.execute_script(
        """ var parent = arguments[0];
            var textPosition = arguments[1];
            var txtPosition = 0;
            var child = parent.firstChild;
            var textValue="";
            while(child) {
              if (child.nodeType === 3){                        
                if (txtPosition===(textPosition-1)){
                  textValue = child.textContent;                
                  break;
                }}else{txtPosition+=1;}
              child = child.nextSibling;
            }
        return textValue;""",
        element, textPosition).strip()
supputuri
  • 13,644
  • 2
  • 21
  • 39
  • 1
    I need this in java. :( – ohlori Apr 05 '19 at 15:12
  • Check the updated answer with the java method, let me know how it goes. – supputuri Apr 05 '19 at 15:21
  • ```Thrown Exception : invalid selector: The result of the xpath expression "//*[@class='output']/text()[contains(.,'TEXT THAT I NEED')]" is: [object Text]. It should be an element. (Session info: chrome=73.0.3683.86)``` – ohlori Apr 05 '19 at 16:10
  • check the updated answer. My bad, I have provided the another method which should get all the direct text of the pare node. – supputuri Apr 05 '19 at 16:18
  • Selenium `findElement` will return element but the xpath you provided in the above comment will return the test, so you are getting that message. Try the updated answer. – supputuri Apr 05 '19 at 16:20
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/191336/discussion-between-supputuri-and-miel-yan). – supputuri Apr 05 '19 at 18:13
  • It is still the same. Returns an invalid selector exception. – ohlori Apr 05 '19 at 23:50
  • As I've stated above, I need to come up with an xpath excluding text() on it. – ohlori Apr 05 '19 at 23:51
0
"return document.evaluate(\"//*[@class='timestamp']/following-sibling::text()[contains(.,'TEXT THAT I NEED')]\", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE,null);"

You can use your Xpath, try to pass it to the JavascriptExecutor, It will be like:

public String yourMethodName(WebDriver webDriver, String yourText) {
        String script = String.format("return document.evaluate(\"//*[@class='timestamp']/following-sibling::text()[contains(.,'%s')]\", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE,null);", yourText);
        JavascriptExecutor js = (JavascriptExecutor) webDriver;
        return (String) js.executeScript(script);
}
Spencer Melo
  • 410
  • 4
  • 14
0

You can evaluate the xpath using javascript execution refer below code :

JavascriptExecutor js = (JavascriptExecutor)driver;
Object textYouWant= js.executeScript("var value = document.evaluate(\"//*[@class='timestamp']/following-sibling::text()[contains(.,'TEXT THAT I NEED')]\",document, null, XPathResult.STRING_TYPE, null ); return value.stringValue;");
System.out.println(textYouWant.toString().trim());

For more details regarding evaluate() refer this

NarendraR
  • 7,577
  • 10
  • 44
  • 82