Tim Tepaße: CSS Syntax, CSS in XML und mit XPath

Beitrag lesen

Hallo Def,

Wenn HTML mittels SGML definiert wurde, und XHTML mittels XML, womit wurde dann die Syntax der CSS definiert? Oder sind die CSS eine eigenständige Erfindung?

Sind sie. Dem ursprünglichen Vorschlag von CSS lag noch eine ganz andere Syntax zu Grunde. Wenn Du übrigens mehr über frühe Stylesheet-Sprachen wissen möchtest, empfehle ich Dir dazu die Dissertation von Håkon Lie. Diese bietet u.a. einen guten Überblick über verschiedene Konzepte und Syntaxen von Vorgängervorschlägen, die dann letztendlich in CSS gemündet sind – kein Wunder, war er doch dabei und einer der Autoren von CSS.

Außerdem würde mich interessieren, ob es einen speziellen Sinn hat, dass die Syntax der CSS weder mit SGML, noch mit XML definiert wurde?

Ja. Es gibt haufenweise Sprachen da draussen, deren Syntax weder mit SGML noch mit XML definiert werden. Allein schon die ganzen Programmiersprachen.

SGML bzw. XML und deren regelmäßige Meta-Strukturen der Syntax haben durchaus auch schon Vorteile, man muss sich nicht mehr stark um das Parsen von Text kümmern, sondern kann mit relativ standardisierten Parsern darauf zugreifen. Allerdings ist die Syntax einer Metasprache oft einfach nur zuviel. Es spricht nichts dagegen, ein eigenes Konzept einer strukturierten Sprache zu entwickeln – schließlich wird das ja schon seit Jahrzehnten gemacht.

Zum Definieren solcher eigener Sprachen wird oft die Backus-Naur-Form verwendet, von der es auch Varianten wie EBNF und ABNF gibt. Das ist im wesentlichen eine strukturierte Syntax zur Definition Strukturierter Syntaxen. XML selber wird teilweise in der EBNF definiert, SGML auch, wenn ich das richtig sehe. Sprich: Ausser XML und SGML gibt es auch eine Möglichkeit, „Freiform“-Strukturen von Text zu definieren, ohne auf Elemente und Tags und Attribute zurückzugreifen. CSS selber nutzt eine gleiche Variante von Produktionen und Token, um die Syntax zu definieren.

Ich persönlich bin ein Fan von kleineren Grammatiken für spezielle Anwendungsfälle. Ein in XML ausgedrücktes CSS fände ich grässlich. Allein schon weil da so viel zu schreiben wäre. ;)

(Ich persönlich fände es übrigens toll, würde sich die Syntax von CSS an Python und nicht an C orientieren. Aber signifikanter Whitespace ist eine mit sehr überzeugten Argumenten aufgeladene Diskussion, insofern ist es müssig darauf zu hoffen. Und ich meine TimBL himself hat die geschweiften Klammern für CSS vorgeschlagen – er macht auch nicht alles richtig.)

So weit ich das beobachten konnte, gehen die Entwicklungen bei XSL(T) wohl in die Richtung, die Style-Anweisungen von der Syntax her in ein einheitliches XML-Schema zu bringen.

Prinzipiell ist das nicht schwer, wie Gunnar schon demonstriert hat. Der Teufel liegt aber immer im Detail. Mal demonstriert:

Ein CSS Stylesheet besteht aus zwei Typen von Anweisungen, nämlich at-Regeln und Regelmengen (Rulesets). Erstere dürfen teilweise wieder Regelmengen enthalten, das geschähe dann durch Verschachtelung, teilweise nicht, dann sind das einfach nur Elemente oder Attribute, die im XML-Dokument rumlungern. Vereinfacht hätte dann ein in XML ausgedrücktes CSS-Stylesheet so eine Syntax:

~~~xml <stylesheet xmlns="tag:tepasse.org,2006-07-25:css-in-xml">
    <rule/>
    <rule/>
    ...
  </stylesheet>

  
Eine Regelmenge besteht aus einem Selektor und einem Deklarationsblock, der null bis ganz ganz viele Deklarationen enthalten kann. Eine Deklaration weisst einer Eigenschaft einen Wert zu. Das könnte in XML dann so aussehen:  
  
  ~~~xml
<rule select="Selektor"  
    <property>value</property>  
    <another-property>value</another-property>  
  </rule>

Und hier beginnt es schon leicht schwierig zu werden. Die Methode, um in XML Elemente zu selektieren nennt sich XPath eine recht mächtige Sprache zum Selektieren von Elementen in einem XML-Dokument. Dieser CSS Selektor ...

div#eichhoerchen p > strong:nth-of-type(2n)

... der jeden zweiten stark betonten Test (strong) innerhalb eines Absatzes unterhalb des Divs mit der ID "eichhoernchen" erfasst, vorausgesetzt, der stark betonte Text ist nicht von anderem Markup umschlossen liesse sich in XPath so ausdrücken:

child::div[attribute::id="eichhoernchen"]/descendant::p/child::strong[position() mod 2 = 0]

Oder um gerecht zu sein in verkürzter Position so:

div[@id="eichhoernchen"]//p/strong[position() mod 2 = 0]

Letztendlich tun sich die beiden Syntaxen zur Adressierung von Elementen also nicht wirklich viel. Nur XPath ist aufgrund der XPath-Funktionen teilweise viel mächtiger. Nur mal zum Beispiel dieser XPath-Ausdruck:

a/@href

Der adressiert nicht einen Link. Er adressiert den Textinhalt des Attributes href dieses Linkes, also die URI darin. Und nun? Für den Zweck von CSS ist das unwichtig - den wie wird so ein Attribut auf dem Bildschirm dargestellt? Gar nicht. Die erlaubten (oder besser: sinnvollen) XPath-Ausdrücke als Selektoren in einem hypothetischen CSS-in-XML wären also nur eine _Teilmenge_ aller erlaubter XPath-Ausdrücke. Man müsste sich also erstmal einen Stück aus XPath rauskratzen.

Dazu kommen ein paar andere Erwägungen. Man nehme nur mal diesen XPath-Ausdruck:

child::body[not(descendant::marquee[ancestor::blink])]

Der selektiert das body-Element, aber nur, wenn sich innerhalb dieses Elementes keinerlei marquee-Elemente befinden, die sich innerhalb eines blink-Elementes befinden – im wesentlichen selektiert der Ausdruck also gutes Webdesign. Das Problem dabei nur: Um so einen XPath-Ausdruck anwenden oder nicht anwenden zu können, muss man erstmal den ganzen DOM-Baum eines Dokumentes kennen und dieses durchgehen. Erstmal ganz runter, dann wieder ganz rauf. Das dauert natürlich. Ok, nicht soviel, aber immerhin. Dummerweise mag die CSS Working Group etwas namens „inkrementelles Rendering“, dass die CSS Regeln schon angewendet werden, während das Dokument lädt. Und damit diese Regeln angewendet werden können, weiss man das ein Selektor „passt“ am besten schon nachdem man nur das Start-Tag eines Elementes gelesen und in einen DOM-Knoten und dann letztendlich in eine Box auf dem Bildschirm umgewandelt hat. Man mag dazu stehen wie man will – und es hat durchaus ziemliche Vorteile – aber diese Wertschätzung von inkrementellen Rendering (und dadurch inkrementeller Evaluierung von Selektoren) hat dazu geführt, dass die CSS Working Group nicht einfach jeden Vorschlag eines neuen Selektors annimmt, sondern diese auf die mögliche Effektivität in der Implementierung abklopft. Zum Beispiel die immer wiederkehrenden Vorschläge eines :contains() oder :contains-not(), die immer wieder schmerzlich vermisst werden werden deswegen abgelehnt.

Es gibt übrigens auch einiges, das CSS kann, XPath aber nicht. Spontan fallen einem die Pseudoelemente auf: ::first-line, ::first-letter. Oder Pseudoklassen wie :hover. Kann XPath alles nicht. Kein Wunder, betrifft so etwas ja auch das ausgegebene visuelle Modell von CSS, nicht den DOM-Baum eines XML-Dokumentes.

XPath kann also einiges, was CSS nicht kann, einiges davon hat im Kontext von CSS keinen Sinn. CSS kann einiges, was XPath nicht kann. Man kann also nicht so XPath benutzen, sondern müsste eine erweiterte Teilmenge von XPath benutzen. Also gleich eine eigene Sprache – die von CSS Selektoren fällt einen da ein.

Welches wäre ein weiterer Vorteil einer XMLisierung von CSS? Dass man die Validität eines Stylesheets gleich mit der Validität von XML überprüfen kann? Wenn ich mal eben von Gunnar dieses Beispiel klaue und adaptiere...

~~~xml <rule select="p">
    <font-family>Zapfino, serif</font-family>
    <font-size>1.1em</font-size>
  </rule>

  
... dann sind die Deklarationen Elemente, die nach der Eigenschaft benannt sind, der Textinhalt ist dann der Wert. Das wirft nun wieder zwei Problemchen auf:  
  
Zum einen kann man mit klassischer Validierung von XML nach DTD nicht überprüfen, ob der Wert einer Eigenschaft auch ein erlaubter Wert ist. Da ist dann prinzipiell Textinhalt erlaubt. Eine Überprüfung auf „Richtigkeit“ müsste also noch mal nach der Validierung mit eigenem Programmcode nachprüfen. Man hat also keinen Vorteil durch klassische XML-Validierung nach DTD. (Validierung nach XML Schema oder RELAX NG würde das übrigens bieten). Man könnte das zwar auch anders notieren:  
  
  `<declaration property="font-color" value="#0F63BC">`{:.language-xml}  
  
Aber für eine Validierung nach DTD müsste dann auch in der DTD alle erlaubten Werte aufzählen – nicht praktikabel. Man landet also bei einer Validierung immer bei XML Schema oder RELAX NG – oder gleich bei eigenem Programmcode, dann fragt man sich, wozu XML verwendet wird.  
  
Zum anderen hat CSS ein Prinzip namens „forward-compatible parsing“, d.h. nicht bekannte Eigenschaften sind zwar invalid, aber kein Grund zu verzweifeln und zu weinen. Man ignoriert fehlerhafte oder unbekannte Deklarationen einfach, fertig. Im XML-Land gibt es das Konzept dagegen nicht wirklich. Validierung nach XML Schema oder RELAX NG bietet dafür Möglichkeiten, ein nach DTD validierender Parser wäre aber ganz raus.  
  
Das heisst, um eine Validierung des CSS-in-XML zu haben, muss man recht komplexe Schemata in einer anderen XML-Syntax haben, die auch nicht alles abdecken und die man hinterher mit eigenem Programmcode nachbessern muss.  
  
Aber hey, man kann alles in Namensräume stecken und dafür eigene Schema basteln:  
  
  ~~~xml
<?xml version="1.0"?>  
  <syntax:stylesheet xmlnx:syntax="tag:tepasse.org,2006-07-25:css-in-xml/syntax"  
                     xmlns:border="tag:tepasse.org,2006-07-25:css-in-xml/border"  
                     xmlns:color="tag:tepasse.org,2006-07-25:css-in-xml/color"  
                     xmlns:font="tag:tepasse.org,2006-07-25:css-in-xml/font">  
      <syntax:ruleset select="p">  
          <color:color>rgb(255, 255, 255)</color:color>  
          <font:family>Verdana</font:family>  
          <font:size>1em</font:size>  
          <border:all>1px solid red</border:all>  
      </syntax:ruleset>  
  </syntax:stylesheet>

Aber was für Vorteile hat man denn nun durch so eine XML-isierung von CSS?

Eine strukturierte Syntax? Hatte man auch schon vorher.
Benutzung von XML-Techniken? Wozu, wenn man sie sich doch umbasteln muss?
Validierung nach einer XML Schemasprache? Schwierig mit den bestehenden Schemasprachen.

Spitze Klammern hat man. ;)

War die Syntax der CSS also Irrweg, der jetzt korrigiert wird, oder sehe ich das falsch?

Nicht jeder abweichende Weg ist ein Irrweg, der korrigiert werden muss.

Tim

--
blog