Textausgaben nummerieren

(Auszug aus "XSLT Kochbuch" von Sal Mangano)

Problem

Sie wollen eine fortlaufend nummerierte Ausgabe erzeugen.

Lösung

Da Ausgaben auf viele Weisen nummeriert werden können, präsentiert dieses Rezept eine Reihe zunehmend komplexer werdender Beispiele, mit denen die gebräuchlichsten (und auch einige ungebräuchliche) Anforderungen an die Nummerierung angesprochen werden.

Fortlaufende Nummerierung von Geschwistern

Diese Kategorie bildet die einfachste Form der Nummerierung. So können Sie etwa eine nummerierte Liste von Leuten erzeugen, indem Sie das Stylesheet aus den beiden folgenden Beispielen verwenden. In diesen Beispielen setze ich xsl:number und sein count-Attribut ein. Sie können das Attribut count auch weglassen, wenn Sie wollen, weil es das Standardverhalten vorsieht, alle Knoten im aktuellen Kontext zu zählen.

Beispiel: Stylesheet.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:template match="person">
    <xsl:number count="*" format="1. "/>
    <xsl:value-of select="@name"/>
  </xsl:template>
</xsl:stylesheet>

Beispiel: Ausgabe.

1. Al Zehtooney
2. Brad York
3. Charles Xavier
4. David Williams
5. Edward Ulster
6. Frank Townsend
7. Greg Sutter
8. Harry Rogers
9. John Quincy
10. Kent Peterson
...

Falls Sie rechtsbündig ausgerichtete Zahlen haben wollen, können Sie auf das in Rezept Einen in Spalten gesetzten Bericht erzeugen besprochene justify-Template zurückgreifen.

Mit einer anderen Zahl als Eins beginnen

xsl:number bietet standardmäßig keine Möglichkeit, mit einer anderen Zahl als Eins zu beginnen oder um einen anderen Wert als Eins zu erhöhen. Mit ein bisschen Mathematik können Sie das jedoch bewältigen. Die beiden folgenden Beispiele zeigen, wie es geht.

Beispiel: Stylesheet mit nichtfortlaufender Nummerierung.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="person">
    <xsl:variable name="num">
      <xsl:number count="*"/>
    </xsl:variable>
    <xsl:number value="($num - 1) * 5 + 10" format="1. "/>
    <xsl:value-of select="@name"/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Beispiel: Ausgabe.

10. Al Zehtooney
15. Brad York
20. Charles Xavier
25. David Williams
30. Edward Ulster
35. Frank Townsend
40. Greg Sutter
45. Harry Rogers
50. John Quincy
55. Kent Peterson
...

Dieses Szenario funktioniert sogar dann, wenn Sie wollen, dass in der endgültigen Ausgabe kein numerisches Format verwendet wird. So zeigen die beiden folgenden Beispiele die gleiche Technik, beginnen aber die Nummerierung bei L .

Beispiel: Stylesheet für die Nummerierung von L an.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="person">
    <xsl:variable name="num">
      <xsl:number count="*"/>
    </xsl:variable>
    <xsl:number value="$num + 11" format="A. "/>
    <xsl:value-of select="@name"/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Beispiel: Ausgabe - Hier werden die Leute vom Buchstaben L an durchnummeriert.

L. Al Zehtooney
M. Brad York
N. Charles Xavier
O. David Williams
P. Edward Ulster
Q. Frank Townsend
R. Greg Sutter
S. Harry Rogers
T. John Quincy
U. Kent Peterson
...

Elemente global nummerieren

Manchmal wollen Sie Elemente fortlaufend nummerieren, ohne Rücksicht auf deren Kontext zu nehmen. Am gebräuchlichsten ist vermutlich ein Dokument, das Fußnoten enthält. Die Fußnoten können auf jeder Ebene der Dokumentstruktur auftauchen, dennoch sollen sie fortlaufend nummeriert sein. Um jedoch das Thema Ihres Beispiels fortzusetzen, kommt hier ein Dokument, das Leute in verschiedene Gruppen und Untergruppen aufteilt:

<people>
  <group>
    <person name="Al Zehtooney" age="33" sex="m" smoker="nein"/>
    <person name="Brad York" age="38" sex="m" smoker="ja"/>
    <person name="Charles Xavier" age="32" sex="m" smoker="nein"/>
    <person name="David Williams" age="33" sex="m" smoker="nein"/>
    <person name="Edward Ulster" age="33" sex="m" smoker="ja"/>
    <person name="Frank Townsend" age="35" sex="m" smoker="nein"/>
  </group>
  <group>
    <person name="Greg Sutter" age="40" sex="m" smoker="nein"/>
    <person name="Harry Rogers" age="37" sex="m" smoker="nein"/>
    <group>
      <person name="John Quincy" age="43" sex="m" smoker="ja"/>
      <person name="Kent Peterson" age="31" sex="m" smoker="nein"/>
      <person name="Larry Newell" age="23" sex="m" smoker="nein"/>
      <group>
        <person name="Max Milton" age="22" sex="m" smoker="nein"/>
        <person name="Norman Lamagna" age="30" sex="m" smoker="nein"/>
        <person name="Ollie Kensinton" age="44" sex="m" smoker="nein"/>
      </group>
      <person name="John Frank" age="24" sex="m" smoker="nein"/>
    </group>
    <group>
      <person name="Mary Williams" age="33" sex="w" smoker="nein"/>
      <person name="Jane Frank" age="38" sex="w" smoker="ja"/>
      <person name="Jo Peterson" age="32" sex="w" smoker="nein"/>
      <person name="Angie Frost" age="33" sex="w" smoker="nein"/>
      <person name="Betty Bates" age="33" sex="w" smoker="nein"/>
      <person name="Connie Date" age="35" sex="w" smoker="nein"/>
      <person name="Donna Finster" age="20" sex="w" smoker="nein"/>
    </group>
    <group>
      <person name="Esther Gates" age="37" sex="w" smoker="nein"/>
      <person name="Fanny Hill" age="33" sex="w" smoker="ja"/>
      <person name="Geta Iota" age="27" sex="w" smoker="nein"/>
      <person name="Hillary Johnson" age="22" sex="w" smoker="nein"/>
      <person name="Ingrid Kent" age="21" sex="w" smoker="nein"/>
      <person name="Jill Larson" age="20" sex="w" smoker="nein"/>
      <person name="Kim Mulrooney" age="41" sex="w" smoker="nein"/>
      <person name="Lisa Nevins" age="21" sex="w" smoker="nein"/>
    </group>
  </group>
</people>

Die einzige notwendige Änderung besteht darin, dass das xsl:number-Attribut level="any" verwendet werden muss. Dieses Attribut weist den XSLT-Prozessor an, alle vorhergehenden Vorkommen des person-Elements zu beachten, wenn die Nummerierung ermittelt wird (siehe die beiden folgenden Beispiele).

Beispiel: Stylesheet für level="any".

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="person">
    <xsl:number count="person" level="any" format="1. "/>
    <xsl:value-of select="@name"/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Beispiel: Ausgabe mit level="any".

1. Al Zehtooney
2. Brad York
3. Charles Xavier
4. David Williams
5. Edward Ulster
6. Frank Townsend
7. Greg Sutter
8. Harry Rogers
9. John Quincy
10. Kent Peterson
11. Larry Newell

12. Max Milton
13. Norman Lamagna
14. Ollie Kensinton
15. John Frank
16. Mary Williams
17. Jane Frank
18. Jo Peterson
19. Angie Frost
20. Betty Bates
21. Connie Date
22. Donna Finster
23. Esther Gates
24. Fanny Hill
25. Geta Iota
26. Hillary Johnson
27. Ingrid Kent
28. Jill Larson
29. Kim Mulrooney
30. Lisa Nevins

Elemente global innerhalb eines Subkontexts nummerieren

Manchmal wollen Sie die globale Nummerierung auf einen Subkontext beschränken. Nehmen Sie beispielsweise an, Sie wollen die Leute innerhalb ihrer obersten Gruppe nummerieren und Untergruppen ignorieren:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="people/group">
    <xsl:text>Gruppe </xsl:text>
    <xsl:number count="group"/>
    <xsl:text>&#xa;</xsl:text>
    <xsl:apply-templates/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
  <xsl:template match="person">
    <xsl:number count="person" level="any" from="people/group" format="1. "/>
    <xsl:value-of select="@name"/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Beispiel: Ausgabe.

Gruppe 1
1. Al Zehtooney
2. Brad York
3. Charles Xavier
4. David Williams
5. Edward Ulster
6. Frank Townsend

Gruppe 2
1. Greg Sutter
2. Harry Rogers
3. John Quincy
4. Kent Peterson
5. Larry Newell
6. Max Milton
7. Norman Lamagna
8. Ollie Kensinton
9. John Frank
10. Mary Williams
11. Jane Frank
12. Jo Peterson
13. Angie Frost
14. Betty Bates
15. Connie Date
16. Donna Finster
17. Esther Gates
18. Fanny Hill
19. Geta Iota
20. Hillary Johnson
21. Ingrid Kent
22. Jill Larson
23. Kim Mulrooney
24. Lisa Nevins

Hierarchisch nummerieren

In formellen und juristischen Dokumenten werden Objekte oft sowohl anhand ihrer Abfolge als auch anhand ihrer Stellung in der Hierarchie nummeriert. Wie im folgenden Beispiel gezeigt, unterstützt xsl:number dies über das Attribut level="multiple".

Beispiel: Hierarchische Nummerierung basierend auf Gruppe und Person.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="people/group">
    <xsl:text>Gruppe </xsl:text>
    <xsl:number count="group"/>
    <xsl:text>&#xa;</xsl:text>
    <xsl:apply-templates/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
  <xsl:template match="person">
    <xsl:number count="group | person" level="multiple" format="1.1.1 "/>
    <xsl:value-of select="@name"/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Die Nummerierung, die durch das Stylesheet in diesem Beispiel erreicht wird, ist ein bisschen seltsam, unterstreicht aber deutlich die Wirkung des Attributs count, wenn dieses mit level="multiple" eingesetzt wird. Dieses Attribut ist einfach eine Spezifikation, mit der sich feststellen lässt, welche Vorgängerelemente beim Aufstellen einer hierarchischen Nummerierung einbezogen werden sollen. Das Stylesheet wies den Leuten auf der Grundlage der Gruppe oder der person-Elemente Nummern zu. Bard York wurde 1.2 zugewiesen, weil er in Gruppe 1 steht und die zweite Person in der Gruppe ist. Max Milton wurde entsprechend 2.3.4.1 zugewiesen, weil er in Gruppe 2 steht, wenn man nur die Gruppen der obersten Ebene betrachtet, in Gruppe 3, wenn man sowohl die Gruppen der obersten als auch die Gruppen der zweiten Ebene betrachtet, und in Gruppe 4, wenn man alle Gruppen, nämlich die der obersten, die der zweiten und die der dritten Ebene betrachtet. Innerhalb seiner eigenen Gruppe ist er die erste Person:

Gruppe 1
1.1 Al Zehtooney
1.2 Brad York
1.3 Charles Xavier
1.4 David Williams
1.5 Edward Ulster
1.6 Frank Townsend

Gruppe 2
2.1 Greg Sutter
2.2 Harry Rogers
2.3.1 John Quincy
2.3.2 Kent Peterson
2.3.3 Larry Newell
2.3.4.1 Max Milton
2.3.4.2 Norman Lamagna
2.3.4.3 Ollie Kensinton
2.3.5 John Frank
2.4.1 Mary Williams
2.4.2 Jane Frank
2.4.3 Jo Peterson
2.4.4 Angie Frost
2.4.5 Betty Bates
2.4.6 Connie Date
2.4.7 Donna Finster
2.5.1 Esther Gates
2.5.2 Fanny Hill
2.5.3 Geta Iota
2.5.4 Hillary Johnson
2.5.5 Ingrid Kent
2.5.6 Jill Larson
2.5.7 Kim Mulrooney
2.5.8 Lisa Nevins

In typischen Anwendungen erwarten Sie ein Nummerierungsschema, in dem die Nummer auf jeder Ebene relativ zur Nummer auf der nächsthöheren Ebene gesehen wird. Sie erreichen diese Beziehung, indem Sie mehrere und benachbarte xsl:number-Elemente verwenden, wie in den beiden folgenden Beispielen gezeigt wird.

Beispiel: Stylesheet zum Erzeugen mehrfach angeordneter Ebenen.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="group">
    <xsl:text>Gruppe </xsl:text>
    <xsl:number count="group" level="multiple"/>
    <xsl:text>&#xa;</xsl:text>
    <xsl:apply-templates/>
  </xsl:template>
  <xsl:template match="person">
    <xsl:number count="group" level="multiple" format="1.1.1."/>
    <xsl:number count="person" level="single" format="1 "/>
    <xsl:value-of select="@name"/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Beispiel: Ausgabe.

Gruppe 1
1.1 Al Zehtooney
1.2 Brad York
1.3 Charles Xavier
1.4 David Williams
1.5 Edward Ulster
1.6 Frank Townsend

Gruppe 2
2.1 Greg Sutter
2.2 Harry Rogers

Gruppe 2.1
2.1.1 John Quincy
2.1.2 Kent Peterson
2.1.3 Larry Newell

Gruppe 2.1.1
2.1.1.1 Max Milton
2.1.1.2 Norman Lamagna
2.1.1.3 Ollie Kensinton
2.1.4 John Frank

Gruppe 2.2
2.2.1 Mary Williams
2.2.2 Jane Frank
2.2.3 Jo Peterson
2.2.4 Angie Frost
2.2.5 Betty Bates
2.2.6 Connie Date
2.2.7 Donna Finster

Gruppe 2.3
2.3.1 Esther Gates
2.3.2 Fanny Hill
2.3.3 Geta Iota
2.3.4 Hillary Johnson
2.3.5 Ingrid Kent
2.3.6 Jill Larson
2.3.7 Kim Mulrooney
2.3.8 Lisa Nevins

Diskussion

Nahezu jedes Nummerierungsschema lässt sich realisieren, indem Sie ein oder mehrere xsl:number-Elemente mit den entsprechenden Attributeinstellungen verwenden. Allerdings kann die extensive Benutzung von xsl:number (vor allem mit level="multiple") Ihre Stylesheets verlangsamen. Bei sehr tief verschachtelten hierarchischen Nummern können Sie einen Leistungsschub erreichen, indem Sie die Nummerierung auf der Elternebene über einen Parameter nach unten an die Kinder übergeben. Beachten Sie, wie Sie auf diese Weise eine hierarchische Nummerierung erstellen, ohne überhaupt xsl:number zu verwenden:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="group">
    <xsl:param name="parent-level" select=" '' "/>
    <xsl:variable name="number" select="concat($parent-level,position( ))"/>
    <xsl:text>Group </xsl:text>
    <xsl:value-of select="$number"/>
    <xsl:text>&#xa;</xsl:text>
    <xsl:apply-templates>
      <xsl:with-param name="parent-level" select="concat($number,'.')"/>
    </xsl:apply-templates>
  </xsl:template>
  <xsl:template match="person">
    <xsl:param name="parent-level" select=" '' "/>
    <xsl:variable name="number">
      <xsl:value-of select="concat($parent-level,position( ),' ')"/>
    </xsl:variable>
    <xsl:value-of select="$number"/>
    <xsl:value-of select="@name"/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Diese Verwendung von position ist weniger bequem, wenn das Nummerierungsschema Buchstaben für römische Ziffern verlangt.

  

zum Seitenanfang

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2006 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT Kochbuch" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O'Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de