xsltxpathancestor

selecting text() using ancestor-or-self with multiple expressions XSLT XPATH


Given the XML:

<surmat>
  <unpack>
     <proc>
        <para>SERVICE UPON RECEIPT</para>
     </proc>
     <proc>
         <title></title>
         <para>Lift and remove</para>
     </proc>
   </unpack>
<surmat>

<surmat> has three children unpack | chkeqp | processeqp so the xml could also be

<surmat>
  <processeqp>
     <proc>
        <para>SERVICE UPON RECEIPT</para>
     </proc>
     <proc>
         <title></title>
         <para>Lift and remove</para>
     </proc>
   </processeqp>
<surmat>

or

<surmat>
      <chkeqp>
         <title>SERVICE UPON RECEIPT</title>
         <proc>
             <title></title>
             <para>Lift and remove</para>
         </proc>
       </chkeqp>
    <surmat>

Using XPATH or XSLT 2.0 I simply want to check for the existence of SERVICE UPON RECEIPTin the first child of <unpack>, <chkeqp> or <processeqp> from the <title> template and the <unpack/chkeqp/processeqp> templates because <title> is optional. (I have to insert SERVICE... and/or the title tag if either are missing.) The children of chkeqp are different from unpack and processeqp.

This will return true as expected:

contains(upper-case(ancestor-or-self::*[unpack or chkeqp or processeqp]),'SERVICE UPON RECEIPT')

but I only need to check the first child and I couldn't figure out the syntax using text().

i.e. this didn't work:

contains(upper-case(ancestor-or-self::*[unpack or chkeqp or processeqp]/text()[1]),'SERVICE UPON RECEIPT')

or variations of this:

contains(upper-case(ancestor-or-self::*[unpack or chkeqp or processeqp]/proc/para/text()[1]),'SERVICE UPON RECEIPT')

If there is a more efficient way of doing this, I would appreciate you sharing it! Thanks.

This answer solved my problem:

contains(upper-case(ancestor-or-self::*[(self::unpack or self::chkeqp or self::processeqp) and count(preceding-sibling::*[self::unpack or self::chkeqp or self::processeqp])=0]/descendant-or-self::para[1]),'SERVICE UPON RECEIPT')

Solution

  • To check if the ancestor element is the first child element of surmat you can count the preceding-siblings:

    contains(upper-case(ancestor-or-self::*[(self::unpack or self::chkeqp or self::processeqp) and count(preceding-sibling::*[self::unpack or self::chkeqp or self::processeqp])=0]/descendant-or-self::para[1]),'SERVICE UPON RECEIPT')
    

    This expression only returns true for text matching the first para element which is a descendant of the ancestor unpack,chkeqp or processeqp element of the title element.