XPath 3.0, XPath 2.0, XPath 1.0 / XPath-Achsen / Positionsbestimmung bei following-sibling

Positionsbestimmung bei following-sibling

Positionsbestimmung bei following-sibling

Mitunter stehen wir vor der Spezialaufgabe, mit following-sibling::* die Abstände zwischen Elementen zu ermitteln, die sich beispielsweise durch das Vorhandensein eines bestimmten Attributs unterscheiden.

Positionsbestimmung bei following-sibling

Auch hier soll ein Beispiel dienen. Gegeben sei das folgende XML Input Dokument:


<root>
    <info>1</info>
    <info>2</info>
    <info>3</info>
    <info>4</info>
    <info>5</info>
    <info>6</info>
    <info irgendeinattribut="">7</info>
    <info>8</info>
    <info>9</info>
    <info>10</info>
    <info>11</info>
    <info irgendeinattribut="">12</info>
    <info>13</info>
    <info>14</info>
    <info>15</info>
    <info>16</info>
    <info>17</info>
    <info>18</info>
    <info irgendeinattribut="">19</info>
    <info>20</info>
</root>

Die Aufgabe ist, bei allen Elementen, die das Attribut "irgendeinattribut" aufweisen, den Abstand zum jeweils nächstfolgenden Element (following-sibling) zu ermitteln, das dieses Attribut ebenfalls aufweist.

Lösung über eine separate Variable

Zunächst geht es darum, die Position der gesuchten info-Elemente in einer separaten Variable festzuhalten. Das geschieht über die position()-Funktion, die eine Numerierung ermöglicht.


    <xsl:variable name="vwithpos">
        <xsl:for-each select="//root/child::*">
            <xsl:if test="@irgendeinattribut">
                <info pos="{position()}"/>                
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>

Der Inhalt von "vwithpos" ist dann:


   <info pos="7"/>
   <info pos="12"/>
   <info pos="19"/>

Im nächsten Schritt können wir die aktuelle Position mit jener in "vwithpos" abgleichen und Differenzen zum nächsten $vwithpos/info/@pos (following-sibling an der position()=1) berechnen.


  <xsl:template match="info" mode="folgendeElemente">
    <xsl:variable name="vpos" select="position()"/>
    <info>
      <xsl:for-each select="attribute()">
        <xsl:copy-of select="."/>
      </xsl:for-each>
      <xsl:if test="self::info[@irgendeinattribut]">
        <xsl:value-of 
           select="$vwithpos/info[@pos = $vpos]
                   /following-sibling::info[position()=1]
                   /@pos - $vpos"/>       
      </xsl:if>
    </info>
  </xsl:template>

Lösung in XSLT 2.0

Alternativ können wir in XSLT 2.0 jene Positionen durch die Differenz zum Minimum des jeweils folgenden "info"-Elements (wiederum mit following-sibling) ermitteln, das das Attribut "irgendeinattribut" aufweist.


  <xsl:template match="info" mode="folgendeElemente">
    <xsl:variable name="vpos" select="position()"/>
    <info nr="{$vpos}">
      <xsl:for-each select="attribute()">
        <xsl:copy-of select="."/>
      </xsl:for-each>
      <xsl:value-of select="
        if (self::info[@irgendeinattribut]) 
        then 
        ( 
          min
          ( 
            for $x in following-sibling::info return 
             if ($x/@irgendeinattribut) 
             then ( count($x/preceding-sibling::info) + 1) 
             else nothing
          ) - $vpos
        ) 
        else nothing"/>
    </info>
  </xsl:template>

wg / 10. November 2017



Fragen? Anmerkungen? Tips?

Bitte nehmen Sie Kontakt zu mir auf:

Vorname
Nachname
Mailadresse







Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info2018@wilfried-grupe.de

www.wilfried-grupe.de/followingsibling.html