I have the following code
<div class="editor-options">
<div class="editor-item">
<label>Name</label>
<input type="text" name="name">
</div>
</div>
<div class="editor-item">
<label>Data Source</label>
<div class="react-select-component css-2b097c-container"></div>
</div>
<div class="editor-item" >
<label>Attribute</label>
<div class="react-select-component css-2b097c-container"></div>
</div>
<div class="editor-item">
<label>Type</label>
<div class="type-select css-2b097c-container"></div>
</div>
</div>
I need to find and select the two 'react-select-component' nodes independently by xpath (Data Source and Attribute)
These are dynamically created react-dropdown lists and have unique class names and content based on database values.
When I try to use:
$x("//div[contains(@class, 'react-select-component')]/ancestor::div[@class='editor-item']//label[contains(text(), 'Data Source')]")
The //label is returned not the //div[class='react-select-component'] which is what I expect. My understanding of Xpath/ancestor is:
Return the node:
//div[contains(@class, 'react-select-component')]
With the Ancestor:
/ancestor::div[@class='editor-item']//label[contains(text(), 'Data Source')]
Do I have it backwards?
The last element in the expression is returned
1) //div[contains(@class, 'react-select-component')]
2) ancestor::div[@class='chart-editor-item']
3) label[contains(text(), 'Data Source')]
That's why label element is returned.
This xpath returns the expected element
//div[contains(@class,'editor-item') and child::label[contains(text(), 'Data Source')]]/div[contains(@class, 'react-select-component')]
That reads: "get a div with @class containing editor-item and a child label with value 'Data Source'"
//div[contains(@class,'editor-item') and child::label[contains(text(), 'Data Source')]]
given that div, get a child div with @class containing react-select-component
div[contains(@class, 'react-select-component')]
Using xml2xpath.sh to check relevant xpaths
xml2xpath.sh -s '//div[contains(@class,"editor-item") and child::label[contains(text(), "Data Source")]]' -t -l test.html
Namespaces:
xml http://www.w3.org/XML/1998/namespace
XML tree:
div
label
div
Found XPath:
//div[contains(@class,"editor-item") and child::label[contains(text(), "Data Source")]]
//div[contains(@class,"editor-item") and child::label[contains(text(), "Data Source")]]
//div[contains(@class,"editor-item") and child::label[contains(text(), "Data Source")]]/label
//div[contains(@class,"editor-item") and child::label[contains(text(), "Data Source")]]/div
Since the output contains the label within the div you specified, you can use the following-sibling axe to locate nodes relative to that node on this specific tree. What I mean:
//div[contains(@class, 'react-select-component')]/ancestor::div[@class='editor-item']//label[contains(text(), 'Data Source')]/following-sibling::div
In case you want to be more specific, or want to avoid getting the wrong div (considering the existence of more than one), add more restrictions to that sibling.
Working example.