C#.NET * C++ * JAVASCRIPT * PYTHON * XML
* XML-SCHEMA * XPATH * XSL * XSL-FO * SVG * XQUERY * XPROC



XPath / XPath-Achsen / preceding::*

preceding::*

preceding::*

➪ Mit preceding::* erhalten Sie Vorgänger-Nodes des aktuellen Knotens. Analog dem following::* erhalten Sie bei preceding::* sämtliche Nodes und deren Childnodes, die dem adressierten Node /Orte/Ort[2]/Mensch[2] vorausgehen.

Auf dieser Seite:

pic/XPath_preceding.jpg


 <xsl:template match="/">
  <ergebnis>
   <xsl:for-each 
        select="/Orte/Ort[2]/Mensch[2]/preceding::*">
    <e nr="{position()}">
     <xsl:call-template name="generateXPath"/>
    </e>
   </xsl:for-each>
  </ergebnis>
 </xsl:template>

Je nach Umfang des Gesamtdokuments und nach Adressierung des aktuellen Nodes kann der Output sehr umfangreich sein. Erfasst wird jeder vorhergehende Node mit all seinen Childnodes, unabhängig von dem jeweiligen Namen. Möchten Sie dagegen nur die vorhergehenden Nodes eines bestimmten Namens ansprechen (also z.B. Mensch), sämtliche anderen Nodes jedoch ignorieren, so lautet der Ausdruck:


<xsl:for-each 
     select="/Orte/Ort[2]/Mensch[2]/preceding::Mensch">
...
</xsl:for-each>

Dann erhalten Sie auch nur die erwähnten Nodes Mensch ohne deren Parent- oder Childnodes. Das Ergebnis erinnert an preceding-sibling::Mensch, ist aber doch anders.

pic/XPath_preceding_Mensch.png

Evtl. etwas mißverständlicher Zugriff

Siehe auch

Freilich erscheint der Zugriff etwas mißverständlich. Für folgenden XML Import:


<A>
  <B1/>
  <B2/>
  <B3/>
  <B4/>
  <B5/>
  <B6/>
  <B7/>
  <B8/>
  <B9/>
</A>

... und diesem XSLT-Quellcode:


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/A/B5">
    <ergebnis>
      <xsl:for-each select="./preceding-::*">
        <Element>
          <xsl:value-of select="name()"/>
        </Element>
      </xsl:for-each>
    </ergebnis>
    </xsl:template>
</xsl:stylesheet>

... lautet das Ergebnis:


<?xml version="1.0" encoding="UTF-8"?>
<ergebnis>
   <Element>B1</Element>
   <Element>B2</Element>
   <Element>B3</Element>
   <Element>B4</Element>
</ergebnis> 

Ergebnis bei erstem Wert

Bei demselben XML-Input und folgendem XSLT-Code


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/A/B5">
    <ergebnis>
      <xsl:for-each select="./preceding-::*[1]">
        <Element>
          <xsl:value-of select="name()"/>
        </Element>
      </xsl:for-each>
    </ergebnis>
    </xsl:template>
</xsl:stylesheet>

... lautet das Ergebnis dagegen (also nur der direkt vorhergehende Wert):


<?xml version="1.0" encoding="UTF-8"?>
<ergebnis>
   <Element>B4</Element>
</ergebnis> 

preceding und Namespace

Weist das XML-Dokument Namespaces auf, so ist es ausreichend, den Namespace-Präfix mit einzubinden: preceding::ns3:Mensch.


<xsl:stylesheet 
    xmlns:d="www.wilfried-grupe.de/Beispiele/2018" 
    xmlns:ns1="www.wilfried-grupe.de/Orte/2018"
    xmlns:ns2="www.wilfried-grupe.de/Ort" 
    xmlns:ns3="www.wilfried-grupe.de/Mensch"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/">
      <ergebnis>
        <xsl:for-each 
            select="/ns1:Orte/ns2:Ort[2]
                             /ns3:Mensch[2]
                             /preceding::ns3:Mensch">
          <M>
              <xsl:value-of select="d:vorname"/>
          </M>
        </xsl:for-each>
      </ergebnis>
    </xsl:template>
</xsl:stylesheet>

Jedem XML-Element seine ID

In dem folgenden XML-Dokument soll jeder <Ort> und jeder <Mensch>, der das Element name aufweist, ein eindeutiges Attribut @ID zugewiesen werden.


<?xml version="1.0" encoding="UTF-8"?>
<Orte>  
  <Ort>
    <id>1</id>
    <name>Neustadt</name>
    <Mensch>      
      <id>eins</id>
      <name>Holzflos</name>
      <vorname>HUGO</vorname>
    </Mensch>
    <Mensch>
      <id>4</id>      
      <vorname>Nicole</vorname>
    </Mensch>
    <Mensch>
      <id>9</id>
      <name>Sprachlos</name>
      <vorname>Stefan</vorname>      
    </Mensch>
    <Mensch>
      <id>2</id>
      <name>Sagblos</name>
      <vorname>Stefan</vorname>
    </Mensch>
    <Mensch>
      <id>3</id>
      <name>Sorglos</name>
      <vorname>SIGGI</vorname>
    </Mensch>
    <Mensch>
      <id>7</id>
      <name>Herzlos</name>
      <vorname>Heini</vorname>
    </Mensch>
  </Ort>
  <Ort>
    <id>2</id>
    <name>Darmstadt</name>    
    <Mensch>
      <id>8</id>
      <name>Rhodos</name>
      <vorname>Rudi</vorname>
    </Mensch>
    <Mensch>
      <id>15</id>
      <name>Kolos</name>
      <vorname>Karl</vorname>
    </Mensch>
    <Mensch>
      <id>16</id>
      <name>SINNLOS</name>
      <vorname>Simone</vorname>
    </Mensch>
    <Mensch>
      <id>17</id>
      <name>Brotlos</name>
      <vorname>Berta</vorname>
    </Mensch>
    <Mensch>
      <id>18</id>
      <name>Wortlos</name>
      <vorname>Werner</vorname>
    </Mensch>
    <Mensch>
      <id>19</id>
      <name>Lustlos</name>
      <vorname>Ludwig</vorname>
    </Mensch>
  </Ort>
  <Ort>
    <id>3</id>
    <name>Kapstadt</name>
    <Mensch>
      <id>5</id>
      <name>Wasistlos</name>
      <vorname>Willi</vorname>
    </Mensch>
    <Mensch>
      <id>10</id>
      <name>Ruhelos</name>
      <vorname>Rita</vorname>
    </Mensch>
    <Mensch>
      <id>11</id>
      <name>Schlaflos</name>
      <vorname>Susi</vorname>
    </Mensch>
    <Mensch>
      <id>12</id>
      <name>Rielos</name>
      <vorname>Lotte</vorname>
    </Mensch>
    <Mensch>
      <id>6</id>
      <name>Bodenlos</name>
      <vorname>Betty</vorname>
    </Mensch>
    <Mensch>
      <id>13</id>
      <name>Muehelos</name>
      <vorname>Martin</vorname>
    </Mensch>
    <Mensch>
      <id>14</id>      
      <vorname>Liane</vorname>
    </Mensch>
  </Ort>
</Orte>

Diese Aufgabe können Sie via preceding mit folgendem XSL-Stylesheet lösen:


<xsl:template match="*">
  <xsl:element name="{local-name()}">
    <xsl:if test="name">
      <xsl:attribute name="ID">    
        <xsl:choose>
          <xsl:when test="name() = 'Ort'">
            <xsl:value-of 
                 select="count(preceding::Ort[name]) + 1 "/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of 
                 select="concat( count(preceding::Ort[name]) + 1, 
                 '.', 
                 count(preceding-sibling::Mensch[name]) + 1 ) "/>    
          </xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>
    </xsl:if>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:element>
</xsl:template>

Das Ergebnis lautet:


<?xml version="1.0" encoding="UTF-8"?>
<Orte>
  <Ort ID="1">
    <id>1</id>
    <name>Neustadt</name>
    <Mensch ID="1.1">      
      <id>eins</id>
      <name>Holzflos</name>
      <vorname>HUGO</vorname>
    </Mensch>
    <Mensch>
      <id>4</id>      
      <vorname>Nicole</vorname>
    </Mensch>
    <Mensch ID="1.2">
      <id>9</id>
      <name>Sprachlos</name>
      <vorname>Stefan</vorname>      
    </Mensch>
    <Mensch ID="1.3">
      <id>2</id>
      <name>Sagblos</name>
      <vorname>Stefan</vorname>
    </Mensch>
    <Mensch ID="1.4">
      <id>3</id>
      <name>Sorglos</name>
      <vorname>SIGGI</vorname>
    </Mensch>
    <Mensch ID="1.5">
      <id>7</id>
      <name>Herzlos</name>
      <vorname>Heini</vorname>
    </Mensch>
  </Ort>
  <Ort ID="2">
    <id>2</id>
    <name>Darmstadt</name>    
    <Mensch ID="2.1">
      <id>8</id>
      <name>Rhodos</name>
      <vorname>Rudi</vorname>
    </Mensch>
    <Mensch ID="2.2">
      <id>15</id>
      <name>Kolos</name>
      <vorname>Karl</vorname>
    </Mensch>
    <Mensch ID="2.3">
      <id>16</id>
      <name>SINNLOS</name>
      <vorname>Simone</vorname>
    </Mensch>
    <Mensch ID="2.4">
      <id>17</id>
      <name>Brotlos</name>
      <vorname>Berta</vorname>
    </Mensch>
    <Mensch ID="2.5">
      <id>18</id>
      <name>Wortlos</name>
      <vorname>Werner</vorname>
    </Mensch>
    <Mensch ID="2.6">
      <id>19</id>
      <name>Lustlos</name>
      <vorname>Ludwig</vorname>
    </Mensch>
  </Ort>
  <Ort ID="3">
    <id>3</id>
    <name>Kapstadt</name>
    <Mensch ID="3.1">
      <id>5</id>
      <name>Wasistlos</name>
      <vorname>Willi</vorname>
    </Mensch>
    <Mensch ID="3.2">
      <id>10</id>
      <name>Ruhelos</name>
      <vorname>Rita</vorname>
    </Mensch>
    <Mensch ID="3.3">
      <id>11</id>
      <name>Schlaflos</name>
      <vorname>Susi</vorname>
    </Mensch>
    <Mensch ID="3.4">
      <id>12</id>
      <name>Rielos</name>
      <vorname>Lotte</vorname>
    </Mensch>
    <Mensch ID="3.5">
      <id>6</id>
      <name>Bodenlos</name>
      <vorname>Betty</vorname>
    </Mensch>
    <Mensch ID="3.6">
      <id>13</id>
      <name>Muehelos</name>
      <vorname>Martin</vorname>
    </Mensch>
    <Mensch>
      <id>14</id>      
      <vorname>Liane</vorname>
    </Mensch>
  </Ort>
</Orte>

Tipp: Um eine andere Reihenfolge des Ergebnisses zu erhalten, versuchen Sie es mit


<xsl:choose>
  <xsl:when test="name() = 'Ort'">
    <xsl:value-of select="count(following::Ort[name]) + 1  "/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of 
         select="concat( count(following::Ort[name]) + 1, 
                 '.', 
                 count(following-sibling::Mensch[name]) + 1 )  "/>        
  </xsl:otherwise>
</xsl:choose>

... oder mit :


<xsl:number format="1" count="Ort | Mensch" level="any"/>

Siehe auch

wg / 14. März 2021



Fragen? Anmerkungen? Tipps?

Bitte nehmen Sie Kontakt zu mir auf.






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: info10@wilfried-grupe.de

www.wilfried-grupe.de/XPath_Achsen5.html