sanjay
sanjay

Reputation: 1020

XPath - Select first element of by analyzing following-siblings

I have xml like follows,

<section>
        <p id="ss_main">aa</p>
        <p id="ss_main">bb</p>
        <p id="main">cc</p>
        <p id="main">dd</p>
        <p id="main">ee</p>
        <p id="ss_main">ff</p>
        <p id="main">gg</p>
        <p id="main">hh</p>
        <p id="main">ii</p>
        <p id="main">jj</p>
        <p id="ss_main">xx</p>
        <p id="ss_main">yy</p>
        <p id="ss_main">zz</p>
    </section>

you can see consecutive <p> elements which attributes is staring from ss . what I need is using xpath select the 1st <p> element of every group which attribute is starting from ss .

SO in above xml <p id="ss_main">aa</p> , <p id="ss_main">ff</p> , <p id="ss_main">xx</p> should be selected.

I can write p[starts-with(@id,'ss')] which select all <p> element that id attr starting from ss and p[starts-with(@id,'ss')][1] which select only 1st <p> element that id starting from ss .

Can anyone suggest me a method how can I select first <p> element of each group that attr starting from ss ??

Upvotes: 0

Views: 527

Answers (2)

Sean B. Durkin
Sean B. Durkin

Reputation: 12729

For this answer, I am assuming that you are using XPath 2.0 and that a different suffix (part of @id content after the ss prefix) starts a new group.

This XPath 2.0 expression ...

p[ starts-with( @id, 'ss')]
 [ not( @id eq preceding-sibling::p[1]/@id)] 

... applied to document ...

<section>
  <p id="ss_main">aa</p>
  <p id="ss_main">bb</p>
  <p id="main">cc</p>
  <p id="main">dd</p>
  <p id="main">ee</p>
  <p id="ss_main">ff</p>
  <p id="main">gg</p>
  <p id="main">hh</p>
  <p id="main">ii</p>
  <p id="main">jj</p>
  <p id="ss_main">xx</p>
  <p id="ss_main">yy</p>
  <p id="ss_main">zz</p>
</section>

... where the focus node is the section element, resolves to ...

<p id="ss_main">aa</p>
<p id="ss_main">ff</p>
<p id="ss_main">xx</p>

Furthermore, when we apply the same expression to ...

<section>
  <p id="ss_main">aa</p>
  <p id="ss_DifferentGroup">bb</p>
  <p id="main">cc</p>
  <p id="main">dd</p>
  <p id="main">ee</p>
  <p id="ss_main">ff</p>
  <p id="main">gg</p>
  <p id="main">hh</p>
  <p id="main">ii</p>
  <p id="main">jj</p>
  <p id="ss_main">xx</p>
  <p id="ss_main">yy</p>
  <p id="ss_main">zz</p>
</section>

... with the same focus node, we get ...

<p id="ss_main">aa</p>
<p id="ss_DifferentGroup">bb</p>
<p id="ss_main">ff</p>
<p id="ss_main">xx</p>

Upvotes: 1

har07
har07

Reputation: 89285

This is one possible XPath :

//p[starts-with(@id, 'ss')][not(preceding-sibling::p[1][starts-with(@id, 'ss')])]

brief explanation :

  • //p[starts-with(@id, 'ss')] : find all p elments having id attribute starts with "ss"...
  • [not(preceding-sibling::p[1][starts-with(@id, 'ss')])] : ... and not having direct preceding sibling element p with the id attribute starts with "ss"

Upvotes: 1

Related Questions