eeye: CSS parsen und nicht benötigte Selektoren ausfiltern

Hallo Forum

Ich habe neulich schon mal zu dem Thema gepostet und bin auf die hilfreiche Idee gebracht worden, die CSS Selektoren in XPath ausdrücke zu übersetzen.

Auch wenn ich mich erst an einfachen Beispielen versucht habe (Formate für Element, Formate für Klassen) ohne allzu spezielle CSS Eigenschaften auszunutzen, bin ich nun doch schon auf ein Problem gestossen, zu dem mir keine schöne Lösung einfallen will.

Dabei geht es um die Möglichkeit im class-Attribut mehrere CSS Klassen anzugeben:

  
<div class="aaa bbb ccc">foobar</div>  

Einen CSS class-Selektor:

  
.aaa { color:#000000 }  

übersetze ich in folgenden XPath:

  
//*[@class='aaa']  

Das matched aber nur, wenn die Klasse als einzige notiert ist:

  
<div class="aaa">foobar</div>  

sobald 2 oder mehr Klassen notiert werden funktioniert das nicht mehr.

Die einzige Lösung, die mir bisher eingefallen ist, ist das XHTML vorher auf das vorhandensein solcher mehrfach Angaben zu prüfen und dann das matching in mehreren Durchläufen zu machen. Dabei würde bei jedem Durchlauf das class-Attribut so modifiziert, dass nur eine der Klassen enthalten ist.

Funktioniert sicher, gefällt mir aber irgendwie nicht. Ich hätte lieber eine XPath-Lösung...

Hat jemand eine Idee?

Danke & Grüsse,
eeye

  1. Hallo,

    Einen CSS class-Selektor: .aaa { color:#000000 } übersetze ich in folgenden XPath: //*[@class='aaa'] Das matched aber nur, wenn die Klasse als einzige notiert ist: ... sobald 2 oder mehr Klassen notiert werden funktioniert das nicht mehr.

    //*[[link:http://de.selfhtml.org/xml/darstellung/xpathfunktionen.htm#contains@title=contains](@class, "aaa")]

    Nebenbei: Du kannst nicht jeden CSS-Selektor als XPath Localisation Path ausdrücken, ich meine da konkret die Pseudoelemente und Pseudoklassen. Aber das weisst Du sicher schon, oder?

    Tim

    1. Hi Tim

      //*[[link:http://de.selfhtml.org/xml/darstellung/xpathfunktionen.htm#contains@title=contains](@class, "aaa")]

      super! vielen Dank dafür.
      (wie immer hätte man mit ein bisschen mehr nachdenken auch selber draufkommen können :/ )

      Nebenbei: Du kannst nicht jeden CSS-Selektor als XPath Localisation Path ausdrücken, ich meine da konkret die Pseudoelemente und Pseudoklassen. Aber das weisst Du sicher schon, oder?

      stimmt (zu beiden Aussagen ;).
      Mir geht es ja darum einen ganzen Haufen CSS mit einer konkreten XHTML Datei abzugleichen und alles was nicht benötigt ist wegzuwerfen.
      Bei den Pseudoelementen und Klassen matche ich dann einfach auf das Element (also zB auf a bei a:visited). Denke das reicht mir.

      Viele Grüsse $ ein schönes WE,
      eeye

      1. Hi,

        //*[[link:http://de.selfhtml.org/xml/darstellung/xpathfunktionen.htm#contains@title=contains](@class, "aaa")]
        super! vielen Dank dafür.

        Aber Achtung!
        contains(@class, "a") ist auch wahr für class="hallo", nicht nur für class="a" oder class="a b" usw.

        cu,
        Andreas

        --
        Warum nennt sich Andreas hier MudGuard?
        Schreinerei Waechter
        O o ostern ...
        Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
        1. Hi Andreas

          contains(@class, "a") ist auch wahr für class="hallo", nicht nur für class="a" oder class="a b" usw.

          Danke für den Hinweis, da hab ich auch schon drüber nachgedacht.
          Denke das lässt sich das lösen, indem ich das Leerzeichen, das bei einem alleinstehenden Klassennamen folgt (oder vorausgeht) mit in die Abfrage aufnehme:

            
          //*[contains(@class, " aaa ")]  
          oder  
          //*[starts-with(@class, "aaa ")]  
          oder  
          //*[ends-with(@class, " aaa")]  
          
          

          Grüsse,
          eeye

          1. Hi,

            Denke das lässt sich das lösen, indem ich das Leerzeichen, das bei einem alleinstehenden Klassennamen folgt (oder vorausgeht) mit in die Abfrage aufnehme:

            Es muß kein Leerzeichen sein. Es kann beliebiger Whitespace sein.

            class "a
             b"
            ist auch zulässig.

            In Javascript löse ich das in etwa so:
            class-Attribut holen,
            Sequenzen von Whitespace auf 1 Leerzeichen normalisieren
            vorne und hinten je ein Leerzeichen anhängen.

            An den zu suchenden Klassennamen ebenfalls vorne und hinten je ein Leerzeichen anhängen.

            Dann gucken, ob der erweiterte Klassenname im bearbeiteten class-Attribut enthalten ist.

            cu,
            Andreas

            --
            Warum nennt sich Andreas hier MudGuard?
            Schreinerei Waechter
            O o ostern ...
            Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
            1. Hi,

              class "a
              b"
              ist auch zulässig.

              Wer hat das = geklaut?

              cu,
              Andreas

              --
              Warum nennt sich Andreas hier MudGuard?
              Schreinerei Waechter
              O o ostern ...
              Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
            2. Hi Andreas

              Es muß kein Leerzeichen sein. Es kann beliebiger Whitespace sein.

              oha, nochmal danke für den Hinweis, das wäre mir entgangen...

              Sequenzen von Whitespace auf 1 Leerzeichen normalisieren
              vorne und hinten je ein Leerzeichen anhängen.

              ich erlaube mir das in perl dann genauso zu machen, werde aber die Reihenfolge umdrehen (also erst ein Leerzeichen vorne und hinten einfügen, dann normalisieren). So hat man in jedem Fall ein schön normalisiertes Ergebnis. Andernfalls könnten 2 Leerzeichen (vorne oder hinten) vorkommen (sofern führende Leerzeichen im class-Attribut überhaupt erlaubt sind?!), was freilich am Ergebnis der Prüfung nichts ändert.

              Viele Grüsse,
              eeye

              1. Hi

                Bin grade drauf gestossen, dass in XPath ja auch reguläre Ausdrücke benutzt werden können.
                Dann könnte man die Whitespaces auch über einen Regex erschlagen:
                //*[contains(@class, "\s+aaa\s+")]

                es wären aber wieder extra Prüfungen notwendig, falls die Klasse am Anfang oder Ende steht. Daher gefällt mir deine Lösung doch besser, zumal sie auch funktioniert, falls das class-Attribut nur eine Klasse und keine Liste enthält.

                Grüsse,
                eeye

                1. Hi

                  //*[contains(@class, "\s+aaa\s+")]

                  es müsste natürlich 'matches' statt 'contains' heissen...

                  cu,
                  eeye