Philipp: xsl/xpath für komplexe suchanfragen mit und-verknüpfung?

Hallo,

ich hab grad ein xsl-Problem vor mir, das anscheinend etwas schwieriger ist. Meinen bisherigen Ansatz muss ich wohl verwerfen oder zumindestens ändern. Ich habe auch den leichten Verdacht, das das was ich will evtl. garnicht geht...

Ich versuche, eine xml-basierte bildergalerie zu basteln, die 100% browserseitig läuft (zb lokal von cd geladen) und mehrere alben und 'tags' unterstützt.

Falls es sowas schon gibt: bitte bescheid sagen. Mich würde auch interessieren, ob jmd Bedenken wg. der Performance hat.

Was ich bisher habe:

-xml datei mit bilder-daten im format

<pic name="005.jpg" album="outdoor">
  <tag>birds</tag>
  <tag>nature</tag>
 </pic>

-html-javascript-gerüst mit form. es kann ein album ausgewählt werden und die vorhandenen tags können per checkbox angeklickt werden

Im Moment erzeugt das javascript ein string aus allen angeklickten tags.
Zb Haken bei birds und bei nature -> string="birds:nature:".
Dieser String wird dann als Parameter an das xsl übergeben, das Album auch.

-xsl-Datei, die Bilder des gewählten Albums ausgibt. Zusätzlich soll nach tags gefiltert werden.

Mein Problem:

Eigentlich habe ich mir vorgestellt, dass mindestens wählbar ist, ob die angeklickten tags AND oder OR verknüpft benutzt werden. (Evtl. noch ein NOT irgendwie reingebastelt)
Momentan kriege ich nichtmal ein AND alleine hin :-( ...
Mein momentanter code macht eine OR Suche, und gibt noch Bilder mehrfach aus, wenn mehrere Tags bei einem Bild gefunden wurden, die im Suchstring stecken.
Die Mehrfach-Ausgabe könnte ich wohl mit etwas grübeln unterdrücken, da habe ich schon was hier im Forum gesehen. Meine Reihenfolge akzeptabler Lösungen sieht aber eher so aus:

  1. AND/OR umschaltbar, NOT zusätzlich
  2. AND/OR umschaltbar
  3. AND-Suche

Also versuche ich mich an 3) :
Mir ist inzwischen klar, dass das mit dem string in der form "tag1:tag2:..." nix wird. Da müsste man den xsl:param per seperator ":" in Teilstrings zerlegen, per Schleife alle Teilstrings einzeln bearbeiten und zusehen, ob alle bei dem gerade  eingelesenen Bild definiert sind. Das geht wohl nicht in xsl.

Hat jemand eine Idee? Evtl irgendwie mit Javascript einen xml-Baum mit den angeklickten Tags generieren? Geht das was ich will überhaupt?

Mein xsl bisher:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:param name="album" />
  <xsl:param name="tags" />

<xsl:template match="/">
      xsl:choose
 <xsl:when test="$album='all'">
  <xsl:for-each select="//pic">
   <xsl:apply-templates select="."/>
      </xsl:for-each>
 </xsl:when>
 xsl:otherwise
         <xsl:for-each select="//pic[@album = $album]">
   <xsl:apply-templates select="."/>
    </xsl:for-each>
 </xsl:otherwise>
      </xsl:choose>
  </xsl:template>

<xsl:template match="pic">
  <xsl:for-each select="tag">
   <xsl:if test="contains($tags, .)">

[ HTML-Code zur Bilddarstellung ]

</xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

  1. Hallo,

    ich hab grad ein xsl-Problem vor mir, das anscheinend etwas schwieriger ist. Meinen bisherigen Ansatz muss ich wohl verwerfen oder zumindestens ändern. Ich habe auch den leichten Verdacht, das das was ich will evtl. garnicht geht...

    Was ich bisher habe:
    -xml datei mit bilder-daten im format

    -html-javascript-gerüst mit form. es kann ein album ausgewählt werden und die vorhandenen tags können per checkbox angeklickt werden
    Im Moment erzeugt das javascript ein string aus allen angeklickten tags.
    Zb Haken bei birds und bei nature -> string="birds:nature:".
    Dieser String wird dann als Parameter an das xsl übergeben, das Album auch.

    Also verwendest du XMLHTTPRequest und dir ist klar, dass du nur ein Paramter per JavaScript an das XSL übergeben kannst. So weit gut.

    -xsl-Datei, die Bilder des gewählten Albums ausgibt. Zusätzlich soll nach tags gefiltert werden.

    Mein Problem:

    1. AND-Suche

    Also versuche ich mich an 3) :
    Mir ist inzwischen klar, dass das mit dem string in der form "tag1:tag2:..." nix wird. Da müsste man den xsl:param per seperator ":" in Teilstrings zerlegen, per Schleife alle Teilstrings einzeln bearbeiten und zusehen, ob alle bei dem gerade  eingelesenen Bild definiert sind. Das geht wohl nicht in xsl.

    Das würde schon gehen.

    Eigentlich habe ich mir vorgestellt, dass mindestens wählbar ist, ob die angeklickten tags AND oder OR verknüpft benutzt werden. (Evtl. noch ein NOT irgendwie reingebastelt)

    1. AND/OR umschaltbar, NOT zusätzlich
    2. AND/OR umschaltbar

    Das würde nur davon abhängen wie du den String, der die Paramterwerte enthält, zusammenstellen kannst z.B. nur als Idee
    +tag1:+tag2:+tag3 = tag1 AND tag3 AND tag3
    +tag1:?tag2:+tag3 = tag1 OR tag2 AND tag3
    +tag1:-tag2:?tag3 = tag1 OR tag3 NOT tag2

    Das dann auseinanderzunehmen wäre schon etwas komplizierter, aber wirklich  nicht unmöglich.

    Hat jemand eine Idee? Evtl irgendwie mit Javascript einen xml-Baum mit den angeklickten Tags generieren? Geht das was ich will überhaupt?

    Ob wirklich möglich ist, kann ich dir jetzt so aus dem Stehgreif nicht sagen, jedoch halte ich es nicht für unmöglich, wenngleich für komplizierter und aufwändiger.

    Wenn du meinst, hier dein XSL und ein Bsp. XML posten zu können, wäre das hilfreich um damit für Test arbeiten zu können.

    Grüße
    Thomas

    1. Danke erstmal für Deine Antwort, das macht schonmal Mut.

      Ich werde Dir gleich ein zip-Archiv per mail zuschicken mit meinem aktuellen Stand.
      Der html-Kram mit der Parameter-Übergabe ist aus nem Forum-Beispiel übernommen und läuft bisher nur im Mozilla.
      Ich hab leider keinen Server, um das Beispiel online zu stellen.

      Hier nochmal mein Code. Jedes Bild existiert 3x. Wenn im xml was von 001.jpg steht, dann gibt es 001.jpg mit hoher auflösung, med001.jpg mit 640 Pixel Breite
      und thumb001.jpg mit 64 Pixel Breite.
      (Das öffnen der Bilder in hoher Aufl. ist noch nicht eingebaut)

      Wie gesagt, erstmal hätte ich gerne eine und-Abfrage für die tags.
      Die existierenden Tags sind übrigens noch 'hart' ins HTML kodiert, das muss später noch geändert werden.

      ---------html------------------------

      <html>
      <head>
         <script language="JavaScript" type="text/javascript">

      /* FÜR MOZILLA */
        var xslStylesheet;
        var xsltProcessor = new XSLTProcessor();
        var myDOM;
        var xmlDoc;

      function init()
         {
          // load the xslt file
          var myXMLHTTPRequest = new XMLHttpRequest();
          myXMLHTTPRequest.open("GET", "pics.xsl", false);
          myXMLHTTPRequest.send(null);

      xslStylesheet = myXMLHTTPRequest.responseXML;
          xsltProcessor.importStylesheet(xslStylesheet);

      // load the xml file
          myXMLHTTPRequest = new XMLHttpRequest();
          myXMLHTTPRequest.open("GET", "pics.xml", false);
          myXMLHTTPRequest.send(null);

      xmlDoc = myXMLHTTPRequest.responseXML;

      //document.getElementById("results").innerHTML = "Select a book above to read the review!";
         }

      function refreshresults()
         {

      var mytags="";
          if(document.ui.birds.checked)
       mytags+=":birds";
          if(document.ui.cats.checked)
       mytags+=":cats";
          if(document.ui.nature.checked)
       mytags+=":nature";
          var myParam = xsltProcessor.getParameter(null, "album");
          xsltProcessor.setParameter(null, "album", document.ui.album.value);

      var myParam2 = xsltProcessor.getParameter(null, "tags");
          xsltProcessor.setParameter(null, "tags", mytags);

      var fragment = xsltProcessor.transformToFragment(xmlDoc, document);
          myDOM = fragment;
          document.getElementById("results").innerHTML = "";
          document.getElementById("results").appendChild(fragment);
         }

      function showmed(title)
         {
          var html = "<IMG src=""+title+";" align="center" border="0">";

      document.getElementById("med").innerHTML = html;

      }
         </script>
         <title>XML / XSLT  mit JavaScript bearbeiten:IE + Mozilla</title>
      </head>

      <body onload="init();">
         <div style="position:fixed; top:0px; left:0px; width:100px; height:100%; background-color:#E0E0E0;">
      Album: <FORM name="ui">
                        <SELECT name="album" onchange="javascript:refreshresults();">
            <option value="all">All</option>
                          <option value="indoor">Indoor</option>
            <option value="outdoor">Outdoor</option>
                        </SELECT>
          <INPUT type="checkbox" id="birds" onchange="javascript:refreshresults();">Birds
          <INPUT type="checkbox" id="cats" onchange="javascript:refreshresults();">Cats
          <INPUT type="checkbox" id="nature" onchange="javascript:refreshresults();" >Nature
                      </FORM>

      </div>
         <div id="results" style="position:absolute; top:0px; left:100px; width:100px; height:100%; background-color:#c0c0c0;"></div>
         <div id="med" style="position:fixed; top:0px; left:200px; right:0px; height:100%;background-color:#909090; "></div>
      </body>
      </html>

      -xml------------------------------------------------------
      <?xml version='1.0'?>
      <picdb>
       <pic name="001.jpg" album="indoor">
        <tag>birds</tag>
       </pic>
       <pic name="002.jpg" album="indoor">
        <tag>birds</tag>
       </pic>
       <pic name="003.jpg" album="indoor">
        <tag>birds</tag>
       </pic>
       <pic name="004.jpg" album="indoor">
        <tag>cats</tag>
       </pic>
       <pic name="005.jpg" album="outdoor">
        <tag>birds</tag>
        <tag>nature</tag>
       </pic>
       <pic name="006.jpg" album="outdoor">
        <tag>nature</tag>
       </pic>
       <pic name="007.jpg" album="outdoor">
       </pic>
       <pic name="008.jpg" album="outdoor">
       </pic>
      </picdb>

      ----xsl------------------------------------------------

      <?xml version="1.0"?>
      <xsl:stylesheet version="1.0"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:param name="album" />
        <xsl:param name="tags" />

      <xsl:template match="/">
            xsl:choose
       <xsl:when test="$album='all'">
        <xsl:for-each select="//pic">
         <xsl:apply-templates select="."/>
            </xsl:for-each>
       </xsl:when>
       xsl:otherwise
               <xsl:for-each select="//pic[@album = $album]">
         <xsl:apply-templates select="."/>
          </xsl:for-each>
       </xsl:otherwise>
            </xsl:choose>
        </xsl:template>

      <xsl:template match="pic">

      <xsl:for-each select="tag">
         <xsl:if test="contains($tags, .)">
      <a>
         <xsl:attribute name="href">javascript:showmed('med<xsl:value-of select="../@name"/>')</xsl:attribute>
         <IMG align="left" border="0">
         <xsl:attribute name="src">thumb<xsl:value-of select="../@name"/></xsl:attribute>
         </IMG>
        </a>

      </xsl:if>
          </xsl:for-each>

      </xsl:template>

      </xsl:stylesheet>

      1. Hallo,

        Danke erstmal für Deine Antwort, das macht schonmal Mut.

        Der html-Kram mit der Parameter-Übergabe ist aus nem Forum-Beispiel übernommen und läuft bisher nur im Mozilla.

        //document.getElementById("results").innerHTML = "Select a book above to read the review!";

        Das ist sogar von mir ;-)
        (aber wenn schon, ich habe das auch mal für den IE gepostet ;-) )

        Ich hab leider keinen Server, um das Beispiel online zu stellen.

        Gut, schau'n wir zuerst was du geschickt hat und dann machen wir hier weiter.

        Grüße
        Thomas

        1. So, jetzt bin ich dazugekommen.

          Erst das HTML etwas aufräumen und den Code für IE einbauen plus die Tags richtig übergeben:
          ------------------- html ------------------------------------
          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
          <html>
           <head>
            <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
            <title>Bildergalerie</title>
            <script language="JavaScript" type="text/javascript">
             var XMLDatei = "pics.xml"; // Pafad zur XML-Datei
             var XSLDatei = "pics.xsl"; // Pafad zur XSL-Datei
             var objectXML;
             var objectXSL;
             var objectXSLCache;
             var objectXSLTProcessor;
             var HTMLAusgabe;
             var mytags = "";
             var bBirds = false;
             var bCats = false;
             var bNature = false;

          function transformation() {
              // Abfrage für den Internet Explorer
              if (window.ActiveXObject) {
               // XML laden
               objectXML = new ActiveXObject("MSXML2.DOMDocument");
               objectXML.async = false;
               objectXML.load(XMLDatei);

          // XSL laden
               objectXSL = new ActiveXObject("MSXML2.FreeThreadedDOMDocument.4.0");
               objectXSL.async = false;
               objectXSL.load(XSLDatei);
               //cachen das XSLT für bessere performance
               objectXSLCache = new ActiveXObject("Msxml2.XSLTemplate.4.0");
                  objectXSLCache.stylesheet = objectXSL;
              }
              // Abfrage für Mozilla / Netscape
              else if (window.ChromeWindow) {
               // Im Mozilla erst XSL laden
               objectXSLTProcessor = new XSLTProcessor();
               objectXSL = new XMLHttpRequest();
               objectXSL.open("GET", XSLDatei, false);
               objectXSL.send(null);
               objectXSL = objectXSL.responseXML;
               objectXSLTProcessor.importStylesheet(objectXSL);

          // XML laden
               objectXML = new XMLHttpRequest();
               objectXML.open("GET", XMLDatei, false);
               objectXML.send(null);
               objectXML = objectXML.responseXML;
              }
              else {
               alert("Ihr Browser unterstützt leider keine XML-XSL-Transformation mittels JavaScript");
              }
              refreshresults(); //führt die 1. tranformation aus mit dem wert aus dem ui.formular
             }

          function refreshresults() {
              if(document.ui.birds.checked && (bBirds == false)) {
               bBirds = true;
               mytags+=":birds";
              }
              if(!document.ui.birds.checked && bBirds) {
               mytags = mytags.replace(/:birds/, "");
               bBirds = false;
              }
              if(document.ui.cats.checked && (bCats == false)) {
               bCats = true;
               mytags+=":cats";
              }
              if(!document.ui.cats.checked && bCats) {
               mytags = mytags.replace(/:cats/, "");
               bCats = false;
              }
              if(document.ui.nature.checked && (bNature == false)) {
               bNature = true;
               mytags+=":nature";
              }
              if(!document.ui.nature.checked && bNature) {
               mytags = mytags.replace(/:nature/, "");
               bNature = false;
              }

          if (window.ActiveXObject) {
               objectXSLTProcessor = objectXSLCache.createProcessor();
                      objectXSLTProcessor.input = objectXML;
                      objectXSLTProcessor.addParameter("album", document.ui.album.value, "");
                      objectXSLTProcessor.addParameter("tags", mytags, "");
               objectXSLTProcessor.transform();
               document.getElementById("results").innerHTML = objectXSLTProcessor.output;
              }
              else if (window.ChromeWindow) {
               var myParam = objectXSLTProcessor.getParameter(null, "album");
               objectXSLTProcessor.setParameter(null, "album", document.ui.album.value);
               var myParam2 = objectXSLTProcessor.getParameter(null, "tags");
               objectXSLTProcessor.setParameter(null, "tags", mytags);
               HTMLAusgabe = objectXSLTProcessor.transformToFragment(objectXML, document);
               document.getElementById("results").innerHTML = "";
               document.getElementById("results").appendChild(HTMLAusgabe);
              }
             }

          function showmed(title) {
              var html = "<img src="" + title + "" border="0">";
              document.getElementById("med").innerHTML = html;
             }
            </script>
            <style type="text/css">
             html, body {
              height:100%;
              margin:0px;
              padding:0px;
             }
             body { background-color:#909090; }
             #albumform {
               width:95px;
              padding:0px 0px 0px 5px;
              height:100%;
              margin:0px;
              background-color:#E0E0E0;
              float:left;
              }
              #results {
               width:100px;
              height:100%;
              margin:0px;
              background-color:#c0c0c0;
              float:left;
              text-align:center;
              }
              #med {
               height:100%;
               width:auto;
               margin:0px;
               background-color:#909090;
               float:left;
              }
            </style>
           </head>
           <body onload="transformation();">
            <div id="albumform">
             Album:
             <form name="ui" action="">
              <select name="album" onchange="refreshresults();">
               <option value="all">All</option>
               <option value="indoor">Indoor</option>
               <option value="outdoor">Outdoor</option>
              </select>
              <input type="checkbox" id="birds" onclick="refreshresults();">Birds<br>
              <input type="checkbox" id="cats" onclick="refreshresults();">Cats<br>
              <input type="checkbox" id="nature" onclick="refreshresults();" >Nature
             </form>
            </div>
            <div id="results"></div>
            <div id="med"></div>
            <br clear="all">
           </body>
          </html>

          ------------------ xsl -------------------------------
          Dein Ansat war schon nicht schlecht, musste nur etwas erweitert werden:

          <?xml version="1.0" encoding="iso-8859-1"?>
          <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
           <xsl:param name="album" />
           <xsl:param name="tags" />

          <xsl:template match="/">
            <xsl:apply-templates />
           </xsl:template>

          <xsl:template match="picdb">
            xsl:choose
             <xsl:when test="$album = 'all'">
              <xsl:apply-templates select="pic" />
             </xsl:when>
             xsl:otherwise
              <xsl:apply-templates select="pic[@album = $album]" />
             </xsl:otherwise>
            </xsl:choose>
           </xsl:template>

          <xsl:template match="pic">
            xsl:choose
             <xsl:when test="$tags = ''">
              <a>
               <xsl:attribute name="href">javascript:showmed('med<xsl:value-of select="@name"/>')</xsl:attribute>
               <img border="0">
                <xsl:attribute name="src">thumb<xsl:value-of select="@name"/></xsl:attribute>
               </img>
              </a>
             </xsl:when>
             xsl:otherwise
              <xsl:for-each select="tag[contains($tags, .)][1]">
               <a>
                <xsl:attribute name="href">javascript:showmed('med<xsl:value-of select="../@name"/>')</xsl:attribute>
                <img border="0">
                 <xsl:attribute name="src">thumb<xsl:value-of select="../@name"/></xsl:attribute>
                </img>
               </a>
              </xsl:for-each>
             </xsl:otherwise>
            </xsl:choose>
           </xsl:template>

          </xsl:stylesheet>

          Grüße
          Thomas

          1. So, jetzt bin ich dazugekommen.

            Erstmal Danke für Deine Mühe. Das ist allerdings immer noch eine oder-verknüpfte Suche.

            Macht aber nichts, erstens brauch ich die auch, zweitens hast Du mit
            <xsl:for-each select="tag[contains($tags, .)][1]">
            eine anscheinend sehr elegante Lösung gezeigt, die ich noch nicht kannte. (Und noch nicht verstehe, werd mich aber reinlesen, wenn ich Zeit hab.)
            Und Drittens hab ich inzwischen auch schon ne Idee, wie man eine und-Suche machen könnte. Stichwörter sind substring-before/after, Rekursion und zählen.

            Das ist sogar von mir ;-)
            (aber wenn schon, ich habe das auch mal für den IE gepostet ;-) )

            Das stimmt. Wie Du wahrscheinlich gemerkt hast, war mein Code bisher eher ein Proof-of-Concept. Aufgeräumt wird später, wenn die Funktion einigermassen steht.
            Hab jetzt fast ein schlechtes Gewissen, weil ich Deinen Code klaue (und chaotisch verwurstele) und ihn dann noch von Dir aufräumen lasse...

            Wenn die Suche einigermassen läuft, dann kommt erstmal ne ganz andere Baustelle: Wie bastel ich am einfachsten einen Export für Digikam (meine Bildverwaltung)??

            1. Hallo,

              Erstmal Danke für Deine Mühe. Das ist allerdings immer noch eine oder-verknüpfte Suche.

              Ja, wobei ich mir überlegt habe, dass das aus der Sicht von XSL keine Bedeutung hat. Es kommt letzlich darauf an was du an "tags" übergibst. So eine OR-NOT Suche würde da nur Sinn haben, wenn du zusätzlich noch z.B. eine Beschreibung bei den Bildern hättest und darin auch was gesucht werden könnte. Z.B. text=wasser not:cats oder so.

              Macht aber nichts, erstens brauch ich die auch, zweitens hast Du mit
              <xsl:for-each select="tag[contains($tags, .)][1]">
              eine anscheinend sehr elegante Lösung gezeigt, die ich noch nicht kannte. (Und noch nicht verstehe, werd mich aber reinlesen, wenn ich Zeit hab.)

              Der Ausdruck besagt: von jedem <tag> dessen Inhalt in $tags vorkommt, das erste auswählen und bewirkt eben, dass auch wenn für ein <pic> mehrere <tag>s in Frage kommen, nur das erste das zutrifft ausgewählt wird.

              Und Drittens hab ich inzwischen auch schon ne Idee, wie man eine und-Suche machen könnte. Stichwörter sind substring-before/after, Rekursion und zählen.

              Wie gesagt, aus der Sicht von XSL ergibt das nicht viel Sinn, daher würde ich diese Such-Verknüpfungen in den JavaScript verlagern um am Ende eben nur die gewünschten "tags" an das XSL zu übergeben.

              Das ist sogar von mir ;-)
              (aber wenn schon, ich habe das auch mal für den IE gepostet ;-) )

              Hab jetzt fast ein schlechtes Gewissen, weil ich Deinen Code klaue (und chaotisch verwurstele)

              Wieso? Dafür steht es ja im Archiv.

              Wie bastel ich am einfachsten einen Export für Digikam (meine Bildverwaltung)??

              Das kann ich dir leider nicht sagen.

              Grüße
              Thomas

              1. Erstmal Danke für Deine Mühe. Das ist allerdings immer noch eine oder-verknüpfte Suche.

                Ja, wobei ich mir überlegt habe, dass das aus der Sicht von XSL keine Bedeutung hat. Es kommt letzlich darauf an was du an "tags" übergibst. So eine OR-NOT Suche würde da nur Sinn haben, wenn du zusätzlich noch z.B. eine Beschreibung bei den Bildern hättest und darin auch was gesucht werden könnte. Z.B. text=wasser not:cats oder so.

                NOT lasse ich erstmal aussen vor. Aber ansonsten sind wir glaub ich nicht ganz einer Meinung, was AND-Verknüpfung bedeutet. Jedenfalls sehe ich nicht, wie Du beide Fälle mit einer xsl-Suche erschlagen willst.

                Ich habe zB 3 Bilder:

                <pic name="1">
                <tag>nature</tag>
                </pic>

                <pic name="2">
                <tag>nature</tag>
                <tag>birds</tag>
                </pic>

                <pic name="3">
                <tag>birds</tag>
                </pic>

                suche: nature AND birds -> soll nur Bild 2 liefern
                suche: nature OR birds -> soll alle 3 Bilder liefern (geht ja jetzt)

                was sollte das Javascript denn da übergeben für ne AND-Suche mit dem vorhandenen xsl?
                Das einzige was mir da einfällt ist die De-Morgan-Regel also
                x AND y = NOT ( (NOT x) OR (NOT y) )
                Aber das man diese NOTs in die xpath-Abfrage einbauen kann sehe ich nicht so ganz. (In etwa: Man müsste die Tags der Suche ermitteln, die nicht im Bild vorkommen. Wenn es solche nicht gibt, dann hat man einen Treffer)

                1. Ich hab jetzt nochmal rausgenommen, was ich nicht verstanden habe, und eine and-Suche ins xsl gebastelt. Mit den ':' als Trennzeichen sollte das jetzt auch in soweit funktionieren, dass keine Substrings in den Tags gesucht werden.

                  An Vorschlägen bin ich natürlich weiter interessiert, aber ansonsten bin ich erstmal zufrieden, was das xml angeht. Danke nochmal fürs Mithelfen.

                  Meine aktuelle Version:

                  -----------------gallery.html------------------------------- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html>  <head>   <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">   <title>Bildergalerie</title>   <script language="JavaScript" type="text/javascript">    var XMLDatei = "pics.xml"; // Pafad zur XML-Datei    var XSLDatei = "pics.xsl"; // Pafad zur XSL-Datei    var objectXML;    var objectXSL;    var objectXSLCache;    var objectXSLTProcessor;    var HTMLAusgabe;    var mytags = "";

                  function transformation() {     // Abfrage für den Internet Explorer     if (window.ActiveXObject) {      // XML laden      objectXML = new ActiveXObject("MSXML2.DOMDocument");      objectXML.async = false;      objectXML.load(XMLDatei);

                  // XSL laden      objectXSL = new ActiveXObject("MSXML2.FreeThreadedDOMDocument.4.0");      objectXSL.async = false;      objectXSL.load(XSLDatei);      //cachen das XSLT für bessere performance      objectXSLCache = new ActiveXObject("Msxml2.XSLTemplate.4.0");         objectXSLCache.stylesheet = objectXSL;     }     // Abfrage für Mozilla / Netscape     else if (window.ChromeWindow) {      // Im Mozilla erst XSL laden      objectXSLTProcessor = new XSLTProcessor();      objectXSL = new XMLHttpRequest();      objectXSL.open("GET", XSLDatei, false);      objectXSL.send(null);      objectXSL = objectXSL.responseXML;      objectXSLTProcessor.importStylesheet(objectXSL);

                  // XML laden      objectXML = new XMLHttpRequest();      objectXML.open("GET", XMLDatei, false);      objectXML.send(null);      objectXML = objectXML.responseXML;     }     else {      alert("Ihr Browser unterstützt leider keine XML-XSL-Transformation mittels JavaScript");     }     refreshresults(); //führt die 1. tranformation aus mit dem wert aus dem ui.formular    }

                  function refreshresults() {     mytags=":";     if(document.ui.birds.checked) {      mytags+="birds:";     }     if(document.ui.cats.checked && (bCats == false)) {      mytags+="cats:";     }     if(document.ui.nature.checked) {      mytags+="nature:";     }

                  if (window.ActiveXObject) {      objectXSLTProcessor = objectXSLCache.createProcessor();             objectXSLTProcessor.input = objectXML;             objectXSLTProcessor.addParameter("album", document.ui.album.value, "");             objectXSLTProcessor.addParameter("tags", mytags, "");      objectXSLTProcessor.addParameter("searchmode", document.ui.searchmode.value, "");      objectXSLTProcessor.transform();      document.getElementById("results").innerHTML = objectXSLTProcessor.output;     }     else if (window.ChromeWindow) {      var myParam = objectXSLTProcessor.getParameter(null, "album");      objectXSLTProcessor.setParameter(null, "album", document.ui.album.value);      var myParam2 = objectXSLTProcessor.getParameter(null, "tags");      objectXSLTProcessor.setParameter(null, "tags", mytags);      var myParam3 = objectXSLTProcessor.getParameter(null, "searchmode");      objectXSLTProcessor.setParameter(null, "searchmode", document.ui.searchmode.value);      HTMLAusgabe = objectXSLTProcessor.transformToFragment(objectXML, document);      document.getElementById("results").innerHTML = "";      document.getElementById("results").appendChild(HTMLAusgabe);     }    }

                  function showmed(title) {     var html = "<img src="" + title + "" border="0">";     document.getElementById("med").innerHTML = html;    }   </script>   <style type="text/css">    html, body {     height:100%;     margin:0px;     padding:0px;    }    body { background-color:#909090; }    #albumform {      width:95px;     padding:0px 0px 0px 5px;     height:100%;     margin:0px;     background-color:#E0E0E0;     float:left;     }     #results {      width:100px;     height:100%;     margin:0px;     background-color:#c0c0c0;     float:left;     text-align:center;     }     #med {      height:100%;      width:auto;      margin:0px;      background-color:#909090;      float:left;     }   </style>  </head>  <body onload="transformation();">   <div id="albumform">    Album:    <form name="ui" action="">     <select name="album" onchange="refreshresults();">      <option value="all">All</option>      <option value="indoor">Indoor</option>      <option value="outdoor">Outdoor</option>     </select>

                  Search Mode:     <select name="searchmode" onchange="refreshresults();">      <option value="and">And</option>      <option value="or">Or</option>     </select><br>

                  <input type="checkbox" id="birds" onclick="refreshresults();">Birds<br>     <input type="checkbox" id="cats" onclick="refreshresults();">Cats<br>     <input type="checkbox" id="nature" onclick="refreshresults();" >Nature    </form>   </div>   <div id="results"></div>   <div id="med"></div>   <br clear="all">  </body> </html>

                  ------------------ pics.xsl -------------------------------------------------------- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html>  <head>   <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">   <title>Bildergalerie</title>   <script language="JavaScript" type="text/javascript">    var XMLDatei = "pics.xml"; // Pafad zur XML-Datei    var XSLDatei = "pics.xsl"; // Pafad zur XSL-Datei    var objectXML;    var objectXSL;    var objectXSLCache;    var objectXSLTProcessor;    var HTMLAusgabe;    var mytags = "";    var bBirds = false;    var bCats = false;    var bNature = false;

                  function transformation() {     // Abfrage für den Internet Explorer     if (window.ActiveXObject) {      // XML laden      objectXML = new ActiveXObject("MSXML2.DOMDocument");      objectXML.async = false;      objectXML.load(XMLDatei);

                  // XSL laden      objectXSL = new ActiveXObject("MSXML2.FreeThreadedDOMDocument.4.0");      objectXSL.async = false;      objectXSL.load(XSLDatei);      //cachen das XSLT für bessere performance      objectXSLCache = new ActiveXObject("Msxml2.XSLTemplate.4.0");         objectXSLCache.stylesheet = objectXSL;     }     // Abfrage für Mozilla / Netscape     else if (window.ChromeWindow) {      // Im Mozilla erst XSL laden      objectXSLTProcessor = new XSLTProcessor();      objectXSL = new XMLHttpRequest();      objectXSL.open("GET", XSLDatei, false);      objectXSL.send(null);      objectXSL = objectXSL.responseXML;      objectXSLTProcessor.importStylesheet(objectXSL);

                  // XML laden      objectXML = new XMLHttpRequest();      objectXML.open("GET", XMLDatei, false);      objectXML.send(null);      objectXML = objectXML.responseXML;     }     else {      alert("Ihr Browser unterstützt leider keine XML-XSL-Transformation mittels JavaScript");     }     refreshresults(); //führt die 1. tranformation aus mit dem wert aus dem ui.formular    }

                  function refreshresults() {     mytags=":";     if(document.ui.birds.checked) {      mytags+="birds:";     }     if(document.ui.cats.checked && (bCats == false)) {      mytags+="cats:";     }     if(document.ui.nature.checked) {      mytags+="nature:";     }

                  if (window.ActiveXObject) {      objectXSLTProcessor = objectXSLCache.createProcessor();             objectXSLTProcessor.input = objectXML;             objectXSLTProcessor.addParameter("album", document.ui.album.value, "");             objectXSLTProcessor.addParameter("tags", mytags, "");      objectXSLTProcessor.addParameter("searchmode", document.ui.searchmode.value, "");      objectXSLTProcessor.transform();      document.getElementById("results").innerHTML = objectXSLTProcessor.output;     }     else if (window.ChromeWindow) {      var myParam = objectXSLTProcessor.getParameter(null, "album");      objectXSLTProcessor.setParameter(null, "album", document.ui.album.value);      var myParam2 = objectXSLTProcessor.getParameter(null, "tags");      objectXSLTProcessor.setParameter(null, "tags", mytags);      var myParam3 = objectXSLTProcessor.getParameter(null, "searchmode");      objectXSLTProcessor.setParameter(null, "searchmode", document.ui.searchmode.value);      HTMLAusgabe = objectXSLTProcessor.transformToFragment(objectXML, document);      document.getElementById("results").innerHTML = "";      document.getElementById("results").appendChild(HTMLAusgabe);     }    }

                  function showmed(title) {     var html = "<img src="" + title + "" border="0">";     document.getElementById("med").innerHTML = html;    }   </script>   <style type="text/css">    html, body {     height:100%;     margin:0px;     padding:0px;    }    body { background-color:#909090; }    #albumform {      width:95px;     padding:0px 0px 0px 5px;     height:100%;     margin:0px;     background-color:#E0E0E0;     float:left;     }     #results {      width:100px;     height:100%;     margin:0px;     background-color:#c0c0c0;     float:left;     text-align:center;     }     #med {      height:100%;      width:auto;      margin:0px;      background-color:#909090;      float:left;     }   </style>  </head>  <body onload="transformation();">   <div id="albumform">    Album:    <form name="ui" action="">     <select name="album" onchange="refreshresults();">      <option value="all">All</option>      <option value="indoor">Indoor</option>      <option value="outdoor">Outdoor</option>     </select>

                  Search Mode:     <select name="searchmode" onchange="refreshresults();">      <option value="and">And</option>      <option value="or">Or</option>     </select><br>

                  <input type="checkbox" id="birds" onclick="refreshresults();">Birds<br>     <input type="checkbox" id="cats" onclick="refreshresults();">Cats<br>     <input type="checkbox" id="nature" onclick="refreshresults();" >Nature    </form>   </div>   <div id="results"></div>   <div id="med"></div>   <br clear="all">  </body> </html>

                  -------- pics.xml ---------------------------------------------------------------

                  <?xml version='1.0'?> <picdb>  <pic name="001.jpg" album="indoor">   <tag>birds</tag>  </pic>  <pic name="002.jpg" album="indoor">   <tag>birds</tag>  </pic>  <pic name="003.jpg" album="indoor">   <tag>birds</tag>  </pic>  <pic name="004.jpg" album="indoor">   <tag>cats</tag>  </pic>  <pic name="005.jpg" album="outdoor">   <tag>birds</tag>   <tag>nature</tag>  </pic>  <pic name="006.jpg" album="outdoor">   <tag>nature</tag>  </pic>  <pic name="007.jpg" album="outdoor">  </pic>  <pic name="008.jpg" album="outdoor">  </pic> </picdb>

                  1. oops: Korrektur:

                    ---------------------------pics.xsl-------------------------------

                    <?xml version="1.0" encoding="iso-8859-1"?>
                    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
                     <xsl:param name="album" />
                     <xsl:param name="tags" />
                     <xsl:param name="searchmode" />

                    <xsl:template match="/">
                      <xsl:apply-templates />
                     </xsl:template>

                    <xsl:template match="picdb">
                      xsl:choose
                       <xsl:when test="$album = 'all'">
                        <xsl:apply-templates select="pic" />
                       </xsl:when>
                       xsl:otherwise
                        <xsl:apply-templates select="pic[@album = $album]" />
                       </xsl:otherwise>
                      </xsl:choose>
                     </xsl:template>

                    <xsl:template match="pic">
                      xsl:choose
                       <xsl:when test="contains(':',$tags)">
                        <a>
                         <xsl:attribute name="href">javascript:showmed('med<xsl:value-of select="@name"/>')</xsl:attribute>
                         <img border="0">
                          <xsl:attribute name="src">thumb<xsl:value-of select="@name"/></xsl:attribute>
                         </img>
                        </a>
                       </xsl:when>
                       xsl:otherwise
                        xsl:choose
                         <xsl:when test="$searchmode = 'or'">
                          <xsl:for-each select="tag[contains($tags, concat(':',.,':'))][1]">
                           <a>
                           <xsl:attribute name="href">javascript:showmed('med<xsl:value-of select="../@name"/>')</xsl:attribute>
                            <img border="0">
                             <xsl:attribute name="src">thumb<xsl:value-of select="../@name"/></xsl:attribute>
                            </img>
                           </a>
                          </xsl:for-each>
                         </xsl:when>
                         xsl:otherwise

                    <xsl:call-template name="checkAnd">
                                <xsl:with-param name="tagsToCheck" select="substring-after($tags,':')" />
                            </xsl:call-template>

                    </xsl:otherwise>
                        </xsl:choose>
                       </xsl:otherwise>
                      </xsl:choose>
                     </xsl:template>

                    <xsl:template name="checkAnd">
                       <xsl:param name="tagsToCheck" />
                       xsl:choose
                        <xsl:when test="substring-after($tagsToCheck,':')">
                         <xsl:if test="tag[. = substring-before($tagsToCheck,':')]">
                          <xsl:call-template name="checkAnd">
                           <xsl:with-param name="tagsToCheck" select="substring-after($tagsToCheck,':')" />
                          </xsl:call-template>
                         </xsl:if>
                        </xsl:when>
                        xsl:otherwise
                         <xsl:if test="tag[. = substring-before($tagsToCheck,':')]">
                          <a>
                           <xsl:attribute name="href">
                            javascript:showmed('med<xsl:value-of select="@name"/>')
                           </xsl:attribute>
                           <img border="0">
                            <xsl:attribute name="src">thumb<xsl:value-of select="@name"/></xsl:attribute>
                           </img>
                          </a>
                         </xsl:if>
                        </xsl:otherwise>
                       </xsl:choose>
                     </xsl:template>

                    </xsl:stylesheet>

                    1. Hallo,

                      <xsl:template match="pic">
                        xsl:choose
                         <xsl:when test="contains(':',$tags)">

                      Das wird wohl nie zutreffen, denn im » : « wird nie der Wert von $tags enthalten sein, es sei denn $tags besteht nur aus einem » : «

                      Ich denke auch, das wir uns vielleicht missverstanden haben, was die Funktionen der Suche angeht, denn so genau kann mir ich deine OR nicht vorstellen  (oder willst du nicht mehr mehrere <tag>s in <pic> verwenden?).
                      Aber wenn es jetzt so funktioniert, wie du es dir vorgestellt hast, ist alles in Ordnung.

                      Grüße
                      Thomas

                      1. <xsl:template match="pic">
                          xsl:choose
                           <xsl:when test="contains(':',$tags)">

                        Das wird wohl nie zutreffen, denn im » : « wird nie der Wert von $tags enthalten sein, es sei denn $tags besteht nur aus einem » : «

                        Genau das. Was kürzeres ist mir nicht eingefallen für:
                        Wenn ($tags = '') oder ($tags = ":")

                        Ansonsten will ich natürlich mehrere tags in einem pic verwenden können.

                        und-Suche: Ich will nur Bilder, die alle der gewählten Tags enthalten.
                        oder-Suche: Ich will alle Bilder, die irgendeins der gewählten Tags enthalten.

          2. function refreshresults() {
                if(document.ui.birds.checked && (bBirds == false)) {
                 bBirds = true;
                 mytags+=":birds";
                }
                if(!document.ui.birds.checked && bBirds) {
                 mytags = mytags.replace(/:birds/, "");
                 bBirds = false;
                }

            Das versteh ich nicht, was Du Dir hier gedacht hast. Steht wohl im Zusammenhang mit unserem Missverständnis über die Suche, das ich unten schon erwähnt hab.

            Bist Du Dir sicher, dass die Variablen einen Sinn haben?

            1. function refreshresults() {
                  if(document.ui.birds.checked && (bBirds == false)) {
                   bBirds = true;
                   mytags+=":birds";
                  }
                  if(!document.ui.birds.checked && bBirds) {
                   mytags = mytags.replace(/:birds/, "");
                   bBirds = false;
                  }

              Das versteh ich nicht, was Du Dir hier gedacht hast. Steht wohl im Zusammenhang mit unserem Missverständnis über die Suche, das ich unten schon erwähnt hab.

              Bist Du Dir sicher, dass die Variablen einen Sinn haben?

              Wenn du es so machst, wie du es vorher hattest:
               if(document.ui.birds.checked) {
                  mytags+=":birds";
                }
              etc.

              bekommst du bei jedes Aktivieren eines Checkboxes auch die Werte der anderen bereits aktivierten Checkboxen mit:
              z.B. Klick  auf "Vogel" --> :birds
              dann Klick auf Katzen --> :birds:birds:cats
              usw.
              Auderdem geht das ganze natürlich weiter, wenn du ein Ceckbox deaktivierts und wieder aktivierst und so hast du irgendwann einen ewig langen String mit lauten Wiederholungen.

              Damit nur das übergeben wird, was gewünscht wurde gibts die Abfrage ob der Checkbox bereits vorher aktivert wurde oder nicht (dafault ist false):
              if(document.ui.birds.checked && (bBirds == false)) {

              dann wir die Aktivierung auf ture gesetzt:  bBirds = true;
              und der String geschrieben: mytags+=":birds";

              Wenn man jetzt nochmal die Checkbox anklikt (oder ein anderes) wird eben überprüft ob diese Checkbox schon vorher aktiviert wurde (d.h. man deaktivert sie jetzt):
              if(!document.ui.birds.checked && bBirds) {

              dann wird der String aus mytags entfernt: mytags = mytags.replace(/:birds/, "");
              und der Status wieder auf false (deaktiverit) gesetzt: bBirds = false;

              Dadurch sind im mytags immer nur die Werte der aktivierten Checkboxen erhalten und das auch nur einmal.

              Grüße
              Thomas

              }