Mengenoperationen auf Knotenmengen ausführen

(Auszug aus "XSLT Kochbuch" von Sal Mangano)

Problem

Sie müssen die Vereinigung, den Durchschnitt, die Mengendifferenz oder die symmetrische Mengendifferenz zweier Knotenmengen ermitteln. Möglicherweise müssen Sie auch noch Gleichheit und Teilmengenbeziehungen zweier Knotenmengen testen.

Lösung

XSLT 1.0

Die Vereinigung ist trivial, da XPath sie direkt unterstützt:

<xsl:copy-of select="$knotenmenge1 | $knotenmenge2"/>

Die Ermittlung des Durchschnitts zweier Knotenmengen erfordert einen komplizierteren Ausdruck:

<xsl:copy-of select="$knotenmenge1[count(. | $knotenmenge2) = count($knotenmenge2)]"/>

Dies bedeutet: alle Elemente, die in knotenmenge1 und auch in knotenmenge2 sind, und zwar kraft der Tatsache, dass eine Vereinigung von knotenmenge2 und einigen bestimmten Elementen in knotenmenge1 die gleiche Menge an Elementen ergibt.

Es folgt die Mengendifferenz (diejenigen Elemente, die in der ersten Menge, nicht jedoch in der zweiten sind):

<xsl:copy-of select="$knotenmenge1[count(. | $knotenmenge2) != count($knotenmenge2)]"/>

Dies bedeutet: alle Elemente in knotenmenge1, die nicht auch in knotenmenge2 sind, und zwar kraft der Tatsache, dass eine Vereinigung aus knotenmenge2 und einigen bestimmten Elementen aus knotenmenge1 eine Menge mit mehr Elementen ergibt.

Es folgt ein Beispiel für die symmetrische Mengendifferenz (die Elemente sind in einer Menge, nicht jedoch in der anderen vorhanden):

<xsl:copy-of select="$knotenmenge1[count(. | $knotenmenge2) != count($knotenmenge2)] | $knotenmenge2[count(. | $knotenmenge1) != count($knotenmenge1)] "/>

Die symmetrische Mengendifferenz ist einfach die Vereinigung der auf beide Weisen ermittelten Differenzen.

Test, ob knotenmenge1 gleich knotenmenge2 ist:

<xsl:if test="count($km1|$km2) = count($km1) and count($km1) = count($km2)">

Zwei Mengen sind gleich, wenn ihre Vereinigung eine Menge mit der gleichen Anzahl an Elementen erzeugt, wie jeweils in beiden Mengen enthalten sind.

Test, ob knotenmenge2 eine Teilmenge von knotenmenge1 ist:

<xsl:if test="count($knotenmenge1|$knotenmenge2) = count($knotenmenge1)">

Test, ob knotenmenge2 eine echte Teilmenge von knotenmenge1 ist:

<xsl:if test="count($km1|$km2) = count($km1) and count($km1) &gt; count(km2)">

XSLT 2.0

Mengenoperationen auf Sequenzen werden in XPath 2.0 direkt unterstützt (für Näheres siehe das Rezept Mengenoperationen verwenden).

Diskussion

Sie werden sich vielleicht fragen, was Mengenoperationen mit XML-Abfragen zu tun haben. Mengenoperationen bieten Möglichkeiten, um Gemeinsamkeiten und Unterschiede zwischen Mengen von Elementen herauszufinden, die aus einem Dokument extrahiert wurden. Viele grundlegende Fragen, die man sich in Bezug auf Daten stellen kann, haben mit gemeinsamen und abgrenzenden Eigenschaften zu tun.

Stellen Sie sich beispielsweise vor, dass Sie person-Elemente aus people.xml extrahieren:

<xsl:variable name="Männer" select="//person[@sex='m']"/>
<xsl:variable name="Frauen" select="//person[@sex='w']"/>
<xsl:variable name="Raucher" select="//person[@smoker='ja']"/>
<xsl:variable name="Nichtraucher" select="//person[@smoker='nein']"/>

Falls Sie nun mit Lebensversicherungen zu tun hätten, würden Sie jede der folgenden Gruppen von Leuten unterschiedlich bewerten:

<!-- Männliche Raucher -->
<xsl:variable name="sehr-großes-Risiko" select="$Männer[count(. | $Raucher) = count($Raucher)]"/>
<!-- Weibliche Raucher -->
<xsl:variable name="hohes-Risiko" select="$Frauen[count(. | $Raucher) = count($Raucher)]"/>
<!-- Männliche Nichtraucher -->
<xsl:variable name="mittleres-Risiko" select="$Männer[count(. | $Nichtraucher) = count($Nichtraucher)]"/>
<!-- Weibliche Nichtraucher -->
<xsl:variable name="geringes-Risiko" select="$Frauen[count(. | $Nichtraucher) = count($Nichtraucher)]"/>

Sie werden wahrscheinlich bemerkt haben, dass Sie die gleichen Antworten mit Hilfe von Logik anstelle von Mengentheorie auch viel direkter hätten erhalten können:

<!-- Männliche Raucher -->
<xsl:variable name="sehr-großes-Risiko" select="//person[@sex='m' and @smoker='ja']"/>
<!-- Weibliche Raucher -->
<xsl:variable name="hohes-Risiko" select="//person[@sex='w' and @smoker='ja']"/>
<!-- Männliche Nichtraucher -->
<xsl:variable name="mittleres-Risiko" select="//person[@sex='m' and @smoker='nein']"/>
<!-- Weibliche Nichtraucher -->
<xsl:variable name="geringes-Risiko" select="//person[@sex='w' and @smoker='nein']"/>

Hätten Sie zuerst die Gruppen der Männer bzw. Frauen extrahiert, dann wäre Folgendes noch effizienter:

<!-- Männliche Raucher -->
<xsl:variable name="sehr-großes-Risiko" select="$Männer[@smoker='ja']"/>
<!-- Weibliche Raucher -->
<xsl:variable name="hohes-Risiko" select="$Frauen[@smoker='ja']"/>
<!-- Männliche Nichtraucher -->
<xsl:variable name="mittleres-Risiko" select="$Männer[@smoker='nein']"/>
<!-- Weibliche Nichtraucher -->
<xsl:variable name="geringes-Risiko" select="$Frauen[@smoker='nein']"/>

Diese Beobachtungen tun der Nützlichkeit des Mengenansatzes keinen Abbruch. Beachten Sie, dass die Mengenoperationen auch dann funktionieren, wenn man nicht weiß, was die Mengen selbst enthalten. Mengenoperationen funktionieren auf einer höheren Abstraktionsebene. Stellen Sie sich vor, dass Sie ein komplexes XML-Dokument haben und an den folgenden vier Mengen interessiert sind:

<!-- Alle Elemente, die die Elemente c1 oder c2 als Kinder haben-->
<xsl:variable name="menge1" select="//*[c1 or c2]"/>
<!-- Alle Elemente, die die Elemente c3 und c4 als Kinder haben-->
<xsl:variable name="menge2" select="//*[c3 and c4]"/>
<!-- Alle Elemente, deren Eltern-Element das Attribut a1 besitzt-->
<xsl:variable name="menge3" select="//*[../@a1]"/>
<!-- Alle Elemente, deren Eltern-Element das Attribut a2 besitzt-->
<xsl:variable name="menge4" select="//*[../@a2]"/>

Im Originalbeispiel war es ganz offensichtlich, dass die Mengen der Männer und Frauen (sowie der Raucher und Nichtraucher) disjunkt sind. Hier wissen Sie das nicht. Die Mengen können vollständig disjunkt sein, sich vollständig überschneiden oder nur einige Elemente gemeinsam haben. Es gibt nur zwei Möglichkeiten herauszufinden, was zwischen, sagen wir, menge1 und menge3 gleich ist. Die erste Möglichkeit besteht darin, ihren Durchschnitt zu bilden. Bei der zweiten durchlaufen Sie das gesamte Dokument noch einmal mit Hilfe des logischen and ihrer Prädikate. In diesem Fall erweist sich die Durchschnittsbildung ganz klar als der gangbare Weg.

EXSLT definiert ein Mengenmodul, das Funktionen enthält, die die hier besprochenen Mengenoperationen ausführen. Das EXSLT verwendet eine interessante Technik, um das Ergebnis seiner Mengenoperationen zurückzuliefern. Anstatt das Ergebnis direkt zurückzuliefern, wendet es Templates auf das Ergebnis an, und zwar in einem Modus, der speziell auf die Art der Mengenoperation abgestimmt ist. Nachdem beispielsweise EXSLT- set:intersection den Durchschnitt berechnet, führt es auf dem Ergebnis <xsl:apply-templates mode="set:intersection"/> aus. Es gibt in EXSLT ein Standard-Template mit diesem Modus. Dieses liefert eine Kopie des Ergebnisses als Knotenbaumfragment. Dieser indirekte Ansatz zum Zurückliefern des Ergebnisses erlaubt es den Benutzern, das EXSLT-Mengenmodul zu importieren, um die Vorgabe zu überschreiben. Diese Technik ist nützlich, aber auch beschränkt. Sie ist nützlich, weil sie potenziell die Notwendigkeit eliminiert, die node-set-Erweiterungsfunktion einzusetzen, um das Ergebnis wieder in eine Knotenmenge umzuwandeln. Sie ist beschränkt, weil es pro passendem Muster im Benutzer-Stylesheet für jede Operation höchstens ein solches überschreibendes Template geben kann. Sie wollen jedoch vielleicht ganz unterschiedliche Postprozessing-Aufgaben mit dem Ergebnis der Durchschnitte ausführen, die von unterschiedlichen Stellen im gleichen Stylesheet aus ermittelt wurden.

Siehe auch

Sie können unter EXSLT-Sets eine Erläuterung der EXSLT-Mengenoperationen finden.

  

<< 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