xpath for immediate preceding sibling
<p><strong>XML</strong></p>

<pre><code>&lt;root&gt;
  &lt;p&gt;nodea text 1&lt;/p&gt;
  &lt;p&gt;nodea text 2&lt;/p&gt;
  &lt;nodea&gt;
  &lt;/nodea&gt;
  &lt;p&gt;nodeb text 1&lt;/p&gt;
  &lt;p&gt;nodeb text 2&lt;/p&gt;
  &lt;nodeb&gt;
  &lt;/nodeb&gt;
&lt;/root&gt;
</code></pre>

<p>I want to get the first preceding sibling p tag of nodea or nodeb if there is one. For example for the above xml the preceding siblings for respective node are  </p>

<p><strong>nodea</strong> preceding siblings</p>

<pre><code>&lt;p&gt;nodea text 1&lt;/p&gt;
&lt;p&gt;nodea text 2&lt;/p&gt;
</code></pre>

<p><strong>nodeb</strong> preceding siblings</p>

<pre><code>&lt;p&gt;nodeb text 1&lt;/p&gt;
&lt;p&gt;nodeb text 2&lt;/p&gt;
</code></pre>

<p>i have tried the below xpath but it gives me the preceding p tag of nodea instead of nodeb.</p>

<pre><code>nodeb = xml.find('nodeb')
nodeb.xpath('preceding-sibling::p[not(preceding-sibling::nodea)][1]')
</code></pre>

<p>If there is no preceding p tag before the node then it should return empty list. For example for the below xml there are no preceding sibling p tags for nodeb.</p>

<pre><code>&lt;root&gt;
  &lt;p&gt;nodea text 1&lt;/p&gt; 
  &lt;nodea&gt;
  &lt;/nodea&gt;
  &lt;nodeb&gt;
  &lt;/nodeb&gt;
&lt;/root&gt;
</code></pre>

<p>It would be nice if someone can also explain why my xpath is not working and what should i keep in mind when writing xpath?</p>

<p>You can select <code>preceding-sibling::*[1][self::p]</code> to select the preceding sibling element if it is a <code>p</code> element.</p>

<p>As for your attempt, I think if you select the <code>nodeb</code> element, you then want to select <code>preceding-sibling::p[preceding-sibling::nodea][1]</code> as you want to look at the sibling <code>p</code>s that are between the <code>nodeb</code> and the <code>nodea</code> element. Your condition <code>preceding-sibling::p[not(preceding-sibling::nodea)][1]</code> indeed selects <code>p</code> siblings that don't have a preceding <code>nodea</code> sibling and these are the first two <code>p</code> elements in document order.</p>

python xml xpath lxml