find xpath to pick following sibling not after ano

2019-09-02 01:25发布

问题:

I would like to get the following sibling C when I'm matching A or A1 template in the following, for the second A or A1 only:

<root>
  <A/>  <!-- first A -->
  <B/>
  <A/>  <!-- second A -->
  <C/>
  <A1/>
  <B/>
  <A1/>
  <B/>
  <C/>
</root>
  • If I'm matching the first A, I have not to retrieve anything as there is another A before my C tag.

  • If I'm matching the second A, I have to retrieve the C tag.

I tried the following without success:

 <xsl:template match="A|A1">
     <xsl:if test="following-sibling::C[preceding-sibling::A|A1[1] = .]">

It seems to be true in every case but why?

回答1:

In XSLT 2.0 you could use a test like

following-sibling::C[
    (preceding-sibling::A|preceding-sibling::A1)[last()] is current()]

to find all the Cs whose nearest preceding A or A1 is the one you first thought of. For XSLT 1.0 you'd have to compare generate-id values instead of using is

following-sibling::C[
     generate-id((preceding-sibling::A|preceding-sibling::A1)[last()])
   = generate-id(current())]

This would select

<root>
  <A/>  <!-- nothing -->
  <B/>
  <A/>  <!-- C1 -->
  <C/>  <!-- this is C1 -->
  <A1/> <!-- nothing -->
  <B/>
  <A1/> <!-- C2 -->
  <B/>
  <C/>  <!-- this is C2 -->
</root>

Your original test

following-sibling::C[preceding-sibling::A|A1[1] = .]

is equivalent to

following-sibling::C[
  ( preceding-sibling::A | (child::A1[1]) ) = .]

and would select all following C siblings for whom either (a) any of their preceding A siblings or (b) their first A1 child has a string value the same as that of the C itself. All the C elements in your document satisfy this predicate as every element has the empty string value.