Let's have this xpath:
<div>
<!-- ... -->
<div> <!--I want this element-->
<!-- ... -->
<sometag>
<a></a>
</sometag>
<!-- ... -->
</div>
<!-- ... -->
</div>
I have this xpath //div[.//a], which selects both divs.
How to write the xpath which selects the nearest div of his child(a). Without link it by that sometag.
You can try to locate the a elements first and then select nearest ancestor div from there:
//a/ancestor::div[1]
xpathfiddle demo
Related
Say I have the following XML:
<body>
<div id="global-header">
header
</div>
<div class="a">
<h3>some title</h3>
<p>text 1</p>
<p>text 2</p>
<p>text 3</p>
</div>
</body>
I want to
find any <p> node whose value is "text 2", and then
find all the nodes that precede this particular <p> but are also descendants of the <div class='a'> node.
The desired output should look like:
<h3>some title</h3>
<p>text 1</p>
The caveat is that the preceding nodes may contain arbitrary node type, not only <h3> and <p>, as in the above case.
My first try:
.//p[text()="text 2"]/preceding::*
Unfortunately, this will also select <div id="global-header">, which is not desired.
You need to use preceding-sibling to select nodes that are children of the same parent instead of preceding:
.//p[text()="text 2"]/preceding-sibling::*
Is there a way to get the parent of a child element in SCSS?
html
<div>
<span>test1</span>
</div
<div>
<p>dsdfds</p>
</div>
In the above example how can I style only the parent of an span element?
I am new to nokogiri and so far most familiar with CSS selectors, I am trying to parse information from a table, below is a sample of the table and the code I'm using, I'm stuck on the appropriate if statement, as it seems to return the whole contents of the table.
Table:
<div class="holder">
<div class ="row">
<div class="c1">
<!-- Content I Don't need -->
</div>
<div class="c2">
<span class="data">
<!-- Content I Don't Need -->
<span class="data">
</div>
</div>
...
<div class="row">
<div class="c1">
SPECIFIC TEXT
</div>
<div class="c2">
<span class="data">
What I want
</span>
</div>
</div>
</div>
My Script: (if SPECIFIC TEXT is found in the table it returns every "div.c2 span.data" variable - so I've either screwed up my knowledge of do loops or if statements)
data = []
page.agent.get(url)
page.search('div.row').each do |row_data|
if (row_data.search('div.c1:contains("/SPECIFIC TEXT/")').text.strip
temp = row_data.search('div.c2 span.data').text.strip
data << temp
end
end
There's no need to stop and insert ruby logic when you can extract what you need in a single CSS selector.
data = page.search('div.row > div.c1:contains("SPECIFIC TEXT") + div.c2 span.data')
This will include only those that match the selector (e.g. follow the SPECIFIC TEXT).
Here's where your logic may have gone wrong:
This code
if (row_data.search('div.c1:contains("SPECIFIC TEXT")'...
temp = row_data.search('div.c2 span.data')...
first searches the row for the specific text, then if it matches, returns ALL rows matching the second query, which has the same starting point. The key is the + in the CSS selector above which will return elements immediately following (e.g. the next sibling element). I'm making an assumption, of course, that the next element is always what you want.
I'd do
require 'nokogiri'
html = <<_
<div class="holder">
<div class ="row">
<div class="c1">
<!-- Content I Don't need -->
</div>
<div class="c2">
<span class="data">
<!-- Content I Don't Need -->
<span class="data">
</div>
</div>
<div class="row">
<div class="c1">
SPECIFIC TEXT
</div>
<div class="c2">
<span class="data">
What I want
</span>
</div>
</div>
</div>
_
doc = Nokogiri::HTML(html)
css_string = 'div.row > div.c1[text()*="SPECIFIC TEXT"] + div.c2 span.data'
doc.at(css_string).text.strip
# => "What I want"
How those selectors would work here -
[name*="value"] - Selects elements that have the specified attribute with a value containing the a given substring.
Child Selector (“parent > child”) - Selects all direct child elements specified by "child" of elements specified by "parent".
Next Adjacent Selector (“prev + next”) - Selects all next elements matching "next" that are immediately preceded by a sibling "prev".
Class Selector (“.class”) - Selects all elements with the given class.
Descendant Selector (“ancestor descendant”) - Selects all elements that are descendants of a given ancestor.
Here's example from Steve Sanderson's blog demonstrating a containerless IF statement in knockout:
<h3>Products</h3>
<ul>
<li><strong>Here is a static header item</strong></li>
<!-- ko foreach: products -->
<li>
<em data-bind="text: name"></em>
<!-- ko if: manufacturer -->
— made by <span data-bind="text: manufacturer.company"></span>
<!-- /ko -->
</li>
<!-- /ko -->
</ul>
How would I make the IF statement more complex. I am trying the following and it doesn't work (always returns false):
<!-- ko if: PlanStateName == 'Draft' -->
<div>This plan is a draft!</div>
<!-- /ko -->
How would one accomplish this?
So it turns out I made a rookie mistake. Here's the working code:
<!-- ko if: PlanStateName() == 'Draft' -->
<div>This plan is a draft!</div>
<!-- /ko -->
Since the variables are wrappered by knockout, the parentheses on PlanStateName are required to access the underlying data.
You need to surround the logical statement with {}.
See http://jsfiddle.net/photo_tom/nvYdf/55/
I'd like to select the following HTML in a document, based on the content of TARGET. I.e. if TARGET matches, select everything. However, I'm not sure where to go after: id('page')/x:div/span/a='TARGET' – How to use parent, child, and sibling expressions to get the containing div, the a preceding that div, and the two br tags following the div
<a></a>
<div>
<br />
<span>
<a>TARGET</a>
<a></a>
<span>
<span>
<a></a>
</span>
<a></a>
<span></span>
</span>
<span>
<a></a>
</span>
</span>
</div>
<br />
<br />
Use a single XPath like:
"//*[
(self::a and following-sibling::*[1][self::div and span/a='TRAGET']) or
(self::div and span/a='TARGET') or
(self::br and preceding-sibling::*[1][self::div and span/a='TARGET']) or
(self::br and preceding-sibling::*[2][self::div and span/a='TARGET'])
]"
Do note that your document is not well formed due to unclosed br tags. Moreover, I didn't include any namespace, which you can add if necessary.
Probably, you should first find all divs (not sure about conditions should be met):
//div[span[a[text()="TARGET"]]][preceding-sibling::*[1][name()="a"]][following-sibling::*[1][name()="br"]]
after that - all related elements for each div:
./preceding-sibling::a[1]
./following-sibling::br[1]
./following-sibling::br[2]