Given this XML/HTML:
<dl>
<dt>Label1</dt><dd>Value1</dd>
<dt>Label2</dt><dd>Value2</dd>
<dt>Label3</dt><dd>Value3a</dd><dd>Value3b</dd>
<dt>Label4</dt><dd>Value4</dd>
</dl>
I want to find all <dt> and then, for each, find the following <dd> up until the next <dt>.
Using Ruby’s Nokogiri I am able to accomplish this like so:
dl.xpath('dt').each do |dt|
ct = dt.xpath('count(following-sibling::dt)')
dds = dt.xpath("following-sibling::dd[count(following-sibling::dt)=#{ct}]")
puts "#{dt.text}: #{dds.map(&:text).join(', ')}"
end
#=> Label1: Value1
#=> Label2: Value2
#=> Label3: Value3a, Value3b
#=> Label4: Value4
However, as you can see I’m creating a variable in Ruby and then composing an XPath using it. How can I write a single XPath expression that does the equivalent?
I guessed at:
following-sibling::dd[count(following-sibling::dt)=count(self/following-sibling::dt)]
but apparently I don’t understand what self means there.
This question is similar to XPath : select all following siblings until another sibling except there is no unique identifier for the ‘stop’ node.
This question is almost the same as xpath to find all following sibling adjacent nodes up til another type except that I’m asking for an XPath-only solution.
One possible solution:
This relies on a value comparison of
dtelements and will fail when there are duplicates. The following (much more complicated) expression does not depend on uniquedtvalues:Note: Your use of
selffails because you’re not properly using it as an axis (self::). Also,selfalways contains just the context node, so it would refer to eachddinspected by the expression, not back to the originaldt