Edmund Schöpf: Suche, ober ein bestimmter Wert mindestens einmal vorkommt

Hallo,
ich habe eine XML-Struktur wie folgt:
...
<artikel>
  <name>Name 1</name>
  <preis>10</preis>
  <waehrung>EUR</waehrung>
</artikel>
<artikel>
  <name>Name 2</name>
  <preis>20</preis>
  <waehrung>CHF</waehrung>
</artikel>
<artikel>
  <name>Name 3</name>
  <preis>30</preis>
  <waehrung>EUR</waehrung>
</artikel>
...

Wie kann ich in XSL erkennen, ob das Element waehrung mindestens einmal nicht "EUR" ist? Anders gesagt, ich möchte wissen, ob alle Preise in EUR sind, oder ob auch anderen Währungen vorhanden sind.

Danke
Edi

  1. Hallo,

    Wie kann ich in XSL erkennen, ob das Element waehrung mindestens einmal nicht "EUR" ist? Anders gesagt, ich möchte wissen, ob alle Preise in EUR sind, oder ob auch anderen Währungen vorhanden sind.

    Eine Möglichkeit:
    <xsl:if test="count(//waehrung[current() != 'EUR']) &gt 0">Es gibt mind. eine andere Währung!</xsl:if>

    Grüße
    Thomas

    1. ...

      Eine Möglichkeit:
      <xsl:if test="count(//waehrung[current() != 'EUR']) &gt 0">

      &gt;

      Grüße
      Thomas

      1. ...

        Eine Möglichkeit:
        <xsl:if test="count(//waehrung[current() != 'EUR']) &gt 0">
                                                               &gt;

        Grüße
        Thomas

        Danke für den Hinweis, leider funktioniert der nicht so wie ich mir das dachte. Ich habe folgende Varianten versucht:

        <xsl:value-of select="count(/DATA/DISPO/DIVISA[current() = 'EUR'])"/>
        <xsl:value-of select="count(/DATA/DISPO[current()/DIVISA = 'EUR'])"/>
        Beide Anweisungen geben mir immer 0 zurück.

        Folgende Anweisung:
        <xsl:value-of select="count(/DATA/DISPO/DIVISA)"/>
        gibt mir hingegen den richtigen Wert (3) zurück.
        wobei meine XML-Struktur so aussieht:
        <DATA>
          <DISPO>
            ...
            <DIVISA>EUR</DIVISA>
          </DISPO>
          <DISPO>
            ...
            <DIVISA>CHF</DIVISA>
          </DISPO>
          <DISPO>
            ...
            <DIVISA>EUR</DIVISA>
          </DISPO>
        </DATA>

        Übrigens ist es in meiner Java-Anwendung egal, ob ich ein "//" oder ein "/" vor dem letzten Element verwende

        Danke jedenfalls
        Edi

        1. Hallo,

          Danke für den Hinweis, leider funktioniert der nicht so wie ich mir das dachte. Ich habe folgende Varianten versucht:

          <xsl:value-of select="count(/DATA/DISPO/DIVISA[current() = 'EUR'])"/>
          <xsl:value-of select="count(/DATA/DISPO[current()/DIVISA = 'EUR'])"/>
          Beide Anweisungen geben mir immer 0 zurück.

          count(/DATA/DISPO[DIVISA = 'EUR'])

          Übrigens ist es in meiner Java-Anwendung egal, ob ich ein "//" oder ein "/" vor dem letzten Element verwende

          Das ist an sich "egal" wenn es eh nur ein letzes Kindelement gibt:

          "/DATA/DISPO//DIVISA" und "/DATA/DISPO/DIVISA" ergibt dann immer 1.
          Gänbe es aber mehrere DIVISA-Elemente würde der Ausdruck ein anderes Ergebnis liefern.

          Grüße
          Thomas

          1. ...

            count(/DATA/DISPO[DIVISA = 'EUR'])

            oder so:

            count(DATA/DISPO/DIVISA[ . = 'EUR'])

            Grüße
            Thomas

            1. ...

              count(/DATA/DISPO[DIVISA = 'EUR'])

              oder so:

              count(DATA/DISPO/DIVISA[ . = 'EUR'])

              Grüße
              Thomas

              Super,
              danke, das mit dem Punkt war die Lösung. Es ist nicht das erste Mal, dass ich Dank Ihrer/Deiner Hilfe meine Probleme gelöst habe.
              Ich hätte da gleich noch eine Variante:
              Wie stelle ich fest, ob die Elemente DIVISA alle den gleichen Wert haben? D.h. ich möchte wissen, ob unterschiedliche Währungen vorhanden sind, oder alles dieselben (unabhängig von EUR)?

              Danke
              Edi

              1. Hallo,

                danke, das mit dem Punkt war die Lösung. Es ist nicht das erste Mal, dass ich Dank <del>Ihrer/</del>Deiner Hilfe meine Probleme gelöst habe.

                Ich hätte da gleich noch eine Variante:
                Wie stelle ich fest, ob die Elemente DIVISA alle den gleichen Wert haben? D.h. ich möchte wissen, ob unterschiedliche Währungen vorhanden sind, oder alles dieselben (unabhängig von EUR)?

                <xsl:key name="waehrung" match="DIVISA" use="."/>
                 <xsl:template match="/">
                  <xsl:if test="count(/DATA/DISPO/DIVISA[ . != 'EUR']) &gt; 0">
                   Es gibt mind. eine andere Währung!
                  </xsl:if>

                so viele versch. Währungen gibt es:
                <xsl:value-of select="count(//DIVISA[generate-id(.) = generate-id(key('waehrung', .)[1])])"/>

                das sind die versch. Währungen:
                  <xsl:for-each select="//DIVISA[generate-id(.) = generate-id(key('waehrung', .)[1])]">
                   <xsl:value-of select="."/>
                  </xsl:for-each>
                 </xsl:template>

                Grüße
                Thomas

                1. Hallo,

                  danke, das mit dem Punkt war die Lösung. Es ist nicht das erste Mal, dass ich Dank <del>Ihrer/</del>Deiner Hilfe meine Probleme gelöst habe.

                  Ich hätte da gleich noch eine Variante:
                  Wie stelle ich fest, ob die Elemente DIVISA alle den gleichen Wert haben? D.h. ich möchte wissen, ob unterschiedliche Währungen vorhanden sind, oder alles dieselben (unabhängig von EUR)?

                  <xsl:key name="waehrung" match="DIVISA" use="."/>
                  <xsl:template match="/">
                    <xsl:if test="count(/DATA/DISPO/DIVISA[ . != 'EUR']) &gt; 0">
                     Es gibt mind. eine andere Währung!
                    </xsl:if>

                  so viele versch. Währungen gibt es:
                  <xsl:value-of select="count(//DIVISA[generate-id(.) = generate-id(key('waehrung', .)[1])])"/>

                  das sind die versch. Währungen:
                    <xsl:for-each select="//DIVISA[generate-id(.) = generate-id(key('waehrung', .)[1])]">
                     <xsl:value-of select="."/>
                    </xsl:for-each>
                  </xsl:template>

                  Grüße
                  Thomas

                  Praktisch würde die Anzahl der vorhandenen Währungen (DIVISA)  mein Problem lösen. Nur, dass ich beim Verwenden der Anweisung
                  <xsl:value-of select="count(//DIVISA[generate-id(.) = generate-id(key('DIVISA', .)[1])])"/>
                  folgenden Fehler erhalte:
                  Keine xsl:key-Vereinbarung für DIVISA vorhanden
                  Wo muss ich die key-Vereinbarung treffen?

                  Ich muss parktisch die Summe aller Aufträge anschreiben, aber nur dann, wenn alle Aufträge dieselbe Währung haben.
                  Ich habe ein for-each über alle Aufträge (DISPO) und erst außerhalb des loops zeige ich die Gesamtsumme an (eben nur, wenn alle Aufträge dieselbe Währung (DIVISA) haben.
                  DIVISA bedeutet auf deutsch Währung, im 1. Posting habe ich nur Beispielhaft die "Übersetzung" hergenommen. Im eigentlichen XML steht nicht waehrung, sondern "DIVISA" (ist italienisch).
                  Es ist zwar schön, wenn ich eine funktionierende Lösung bekommen, aber mich würde auch interessieren, diese selbst zustande zu bekommen. Wo finde ich eine Doku spieziell zu diesen verschiedenen count() Varianten mit generated-id, key....

                  Danke
                  Edi

                  1. Hallo,

                    Praktisch würde die Anzahl der vorhandenen Währungen (DIVISA)  mein Problem lösen. Nur, dass ich beim Verwenden der Anweisung
                    <xsl:value-of select="count(//DIVISA[generate-id(.) = generate-id(key('DIVISA', .)[1])])"/>
                    folgenden Fehler erhalte:
                    Keine xsl:key-Vereinbarung für DIVISA vorhanden
                    Wo muss ich die key-Vereinbarung treffen?

                    Ganz oben als direktes Kind vom xsl:styesheet

                    Ich muss parktisch die Summe aller Aufträge anschreiben, aber nur dann, wenn alle Aufträge dieselbe Währung haben.
                    Ich habe ein for-each über alle Aufträge (DISPO) und erst außerhalb des loops zeige ich die Gesamtsumme an (eben nur, wenn alle Aufträge dieselbe Währung (DIVISA) haben.

                    So ganz genau verstehe ich das jetzt nicht, aber mit der Gruppierung über key & generate-id() könntest du auch alle Aufträge nach Währung gruppiert ausgeben/bearbeiten.

                    Es ist zwar schön, wenn ich eine funktionierende Lösung bekommen, aber mich würde auch interessieren, diese selbst zustande zu bekommen. Wo finde ich eine Doku spieziell zu diesen verschiedenen count() Varianten mit generated-id, key....

                    So richtig: niergends.
                    Aber sehr gute Beispiele/Lösungen findest du unter http://www.dpawson.co.uk/xsl/sect2/sect21.html

                    Oder wenn es hilft, kann ich dir auch gerne erklären, was der key/count macht.

                    Grüße
                    Thomas

                    1. Oder wenn es hilft, kann ich dir auch gerne erklären, was der key/count macht.

                      Danke, für das Angebot, vielleicht hilft mir das weiter.
                      Nochmals kurz meine Problemstelung:
                      Ich habe viele Auftrage <DISPO> mit Beträgen in der Währung (<DIVISA>) EURO. In diesem Falle zeige ich die Summe der Aufträge in Euro an. Es kann aber auch vorkommen, dass einige Aufträge in USD oder JPY sind. Falls also in den vielen Knoten <DISPO> nicht alle Aufträge dieselbe Währung haben, kann ich natürlich keine Summe anzeigen (ich würde z.B. EUR mit JPY mischen). Also reicht mir aus dies feststellen zu können.
                      Natürlich wäre eine Gruppierung der Aufträge pro Währung <DIVISA> nicht schlecht...
                      Hier nochmals ein Beispiel XML:

                      <DATI>
                        <DISPO>
                          <Artikel>aaaa</Artikel>
                          <Preis>1110</Preis>
                          <DIVISA>EUR</DIVISA>
                        </DISPO>
                        <DISPO>
                          <Artikel>bbbb</Artikel>
                          <Preis>220</Preis>
                          <DIVISA>CHF</DIVISA>
                        </DISPO>
                        <DISPO>
                          <Artikel>ccc</Artikel>
                          <Preis>2330</Preis>
                          <DIVISA>EUR</DIVISA>
                        </DISPO>
                      </DATI>

                      Auch hier hab ich einen interessanten Beitrag gelesen, bekomme mein xsl aber trotzdem nicht auf die Reihe...
                      http://www2.informatik.hu-berlin.de/~obecker/XSLT/Tutorials/muenchian/
                      Da wäre alles drinnen was du mir beigebracht hast.

                      Grüße
                      Thomas

                      1. Hallo,

                        Danke, für das Angebot, vielleicht hilft mir das weiter.
                        Nochmals kurz meine Problemstelung:
                        Ich habe viele Auftrage <DISPO> mit Beträgen in der Währung (<DIVISA>) EURO. In diesem Falle zeige ich die Summe der Aufträge in Euro an. Es kann aber auch vorkommen, dass einige Aufträge in USD oder JPY sind. Falls also in den vielen Knoten <DISPO> nicht alle Aufträge dieselbe Währung haben, kann ich natürlich keine Summe anzeigen (ich würde z.B. EUR mit JPY mischen). Also reicht mir aus dies feststellen zu können.
                        Natürlich wäre eine Gruppierung der Aufträge pro Währung <DIVISA> nicht schlecht...

                        ------------------ xsl ----------------------
                        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
                         <xsl:key name="dispo" match="DISPO" use="DIVISA"/>
                         <xsl:template match="/DATI">
                          <xsl:for-each select="DISPO[generate-id(.) = generate-id(key('dispo', DIVISA)[1])]">
                           DISPO in : <xsl:value-of select="DIVISA"/>
                           <xsl:for-each select="key('dispo', DIVISA)">
                            Artikel: <xsl:value-of select="Artikel"/>
                            Peis: <xsl:value-of select="Preis"/>
                           </xsl:for-each>
                           ==================
                           Summe in <xsl:value-of select="DIVISA"/>: <xsl:value-of select="sum(key('dispo', DIVISA)/Preis)"/>
                          </xsl:for-each>
                         </xsl:template>
                        </xsl:stylesheet>

                        ------------------ ausgabe ------------------

                        DISPO in : EUR
                            Artikel: aaaa
                            Peis: 1110
                            Artikel: ccc
                            Peis: 2330
                           ==================
                           Summe in EUR: 3440

                        DISPO in : CHF
                            Artikel: bbbb
                            Peis: 220
                           ==================
                           Summe in CHF: 220

                        ------------------------- erklärung -----------------

                        mit: <xsl:key name="dispo" match="DISPO" use="DIVISA"/>
                        legst du einen Schlüssel für "DISPO" an, dessen Wert "DIVISA" bildet.
                        Du kannst es als ein Array (oder als ein Hashtable) betrachten.

                        <xsl:for-each select="DISPO[generate-id(.) = generate-id(key('dispo', DIVISA)[1])]">

                        1. Das: "DISPO[generate-id(.)"
                          generiert ein ID für das jeweilige DISPO-Element.

                        2. Das: "generate-id(key('dispo', DIVISA))"
                          generiert jeweils ein ID für die DISPO-Elemente im key, die den selben Wert im "DIVISA" haben wie das aktuelle DISPO-Element.

                        3)Das: "generate-id(key('dispo', DIVISA)[1])" generiert die ID nur für das erste Element im key, das den selben Wert im "DIVISA" hat wie das aktuelle DISPO-Element.

                        Ein ID wird für ein Element im Dokument immer nur einmal generiert: das heisst ein und dasselbe Element bekommt immer dieselbe ID zugewiesen, egal an welcher Stelle oder wie oft man diese ID generiert. Deshalb eignet sich die ID gut für Vergleiche.

                        Für die Gruppierung gilt: suche den ersten Mitlgied der Gruppe, dann finde die anderen Mitglieder der Gruppe.

                        Das: "generate-id(.) = generate-id(key('dispo', DIVISA)[1])"
                        vergleich die ID aus 1 mit dem ID aus 3.
                        Bei Übereinstimmung hat man den ersten Mitglied, so kann man dann DIVISA für die Gruppe ausgeben:
                        "DISPO in : <xsl:value-of select="DIVISA"/>"

                        Danach sucht man die Mitglieder der Gruppe:
                        "<xsl:for-each select="key('dispo', DIVISA)">"
                        DIVISA kommt hier von dem DISPO-Elemente, das gerade im ersten for-each abgearbeitet wird. Und weil durch den ID-Vergleich genau ein Element ausgewählt wurde, gilt das zweite for-each also für alle DISPO-Elemente im key, die den aktuellen DIVISA-Wert haben.
                        Dann kann man die Sachen für die einzelnen Gruppenmitglieder ausgeben:
                        "Artikel: <xsl:value-of select="Artikel"/>"
                        "Peis: <xsl:value-of select="Preis"/>"

                        Als letztes gab ich noch die Summe der Mitglieder der Gruppe aus:
                        "<xsl:value-of select="sum(key('dispo', DIVISA)/Preis)"/>"

                        Das: "key('dispo', DIVISA)" gilt hier ja für alle Gruppemitglieder und "key('dispo', DIVISA)/Preis" greift auf den Preis des Gruppenmitgliedes zu und sum() zählt dann das zusammen.

                        Grüße
                        Thomas

                        1. Grüße
                          Thomas

                          Vielen Dank für die ausführliche Erklärung.
                          Endlich funktioniert mein XSL so wie ich es mir vorstelle!
                          Grüße
                          Edi

                2. Hallo,

                  danke, das mit dem Punkt war die Lösung. Es ist nicht das erste Mal, dass ich Dank <del>Ihrer/</del>Deiner Hilfe meine Probleme gelöst habe.

                  Ich hätte da gleich noch eine Variante:
                  Wie stelle ich fest, ob die Elemente DIVISA alle den gleichen Wert haben? D.h. ich möchte wissen, ob unterschiedliche Währungen vorhanden sind, oder alles dieselben (unabhängig von EUR)?

                  <xsl:key name="waehrung" match="DIVISA" use="."/>
                  <xsl:template match="/">
                    <xsl:if test="count(/DATA/DISPO/DIVISA[ . != 'EUR']) &gt; 0">
                     Es gibt mind. eine andere Währung!
                    </xsl:if>

                  so viele versch. Währungen gibt es:
                  <xsl:value-of select="count(//DIVISA[generate-id(.) = generate-id(key('waehrung', .)[1])])"/>

                  das sind die versch. Währungen:
                    <xsl:for-each select="//DIVISA[generate-id(.) = generate-id(key('waehrung', .)[1])]">
                     <xsl:value-of select="."/>
                    </xsl:for-each>
                  </xsl:template>

                  Grüße
                  Thomas

                  Nach etwas Suche habe ich nun am Beginn meines XSL folgende keys Anweisung hinzugefügt:
                    <xsl:key name="DIV" match="DISPO" use="DIVISA" />
                  Am Ende hab ich dann diese Anweisung, die mir immer 0 zurückgibt
                    <xsl:value-of select="count(/DATI/DISPO/DIVISA[generate-id(.) = generate-id(key('DIV', .)[1])])"/>

                  Irgendetwas mach ich noch falsch.
                  Edi

                  1. Hallo,

                    Nach etwas Suche habe ich nun am Beginn meines XSL folgende keys Anweisung hinzugefügt:
                      <xsl:key name="DIV" match="DISPO" use="DIVISA" />
                    Am Ende hab ich dann diese Anweisung, die mir immer 0 zurückgibt
                      <xsl:value-of select="count(/DATI/DISPO/DIVISA[generate-id(.) = generate-id(key('DIV', .)[1])])"/>

                    Irgendetwas mach ich noch falsch.

                    Ja und zwar:

                    Bei "<xsl:key name="DIV" match="DISPO" use="DIVISA" />" ist das Element "DIVISA" der der Wert für den Schlüssel für: "DISPO".

                    Bei der Abfrage:
                     "count(/DATI/DISPO/DIVISA[generate-id(.) = generate-id(key('DIV', .)[1])])"
                    trifft der key nie zu, weil du hier einen Wert für den Schlüssel für: "DIVISA" suchst.

                    Der key von oben könnte nur so zutreffen:
                    count(/DATI/DISPO[generate-id(.) = generate-id(key('DIV', DIVISA)[1])])
                    was aber dann nicht unbedingt dasselbe Ergebnis liefert.

                    Grüße
                    Thomas