Hyvin lyhyt johdatus SGML:ään

Esipuhe

HTML-kieli perustuu SGML:ään. Tämän takia on hyvä tietää jotain SGML:stä, jos tuottaa HTML-dokumentteja.

Erityisesti on huomattava, että HTML-kielen syntaksi on määritelty SGML:n merkintätavoilla. Tätä varten perehdyin hiukan SGML:ään ja samalla kirjoitin tämän jutun - jäsentääkseni ajatuksiani ja auttaakseni ehkä muita tutustumaan SGML:ään nopeammin.

Eräs käytännön tilanne, jossa HTML-sivujen tekijä tarvitsee perustietoja SGML:stä, on validointi tilanteessa, jossa tietoisesti halutaan käyttää kielen spesifikaatioon kuulumattomia piirteitä. Aiheesta on esimerkki dokumentissani JavaScript and HTML: possibilities and caveats.

Esitys on kirjoitettu olettaen, että lukijalla on jossain määrin käsitystä formaaleista järjestelmistä kuten säännöllisistä lausekkeista (regular expressions).

Pääpaino on SGML:n selittämisellä siinä määrin, kuin HTML:n syntaksin tarkan kuvauksen ymmärtäminen vaatii. - Tässä käytetään esimerkkinä HTML-kielen versiota HTML 3.2:ta. Sen virallinen kuvaus, W3C:n määrittelemä HTML 3.2 Reference Specification sisältää sekä HTML 3.2:n yhtenäisen SGML-kielisen kuvauksen että otteita siitä kielen eri piirteiden sanallisessa selostamisessa. (HTML:n eri versioiden välillä ei ole aiheemme kannalta suurtakaan merkitystä.)

SGML ja HTML

SGML, Standard Generalized Markup Language, on yleinen dokumenttien rakenteen kuvaamisen kieli. Se sisältää välineet kuvata dokumenttityyppejä (document type). Dokumenttityyppiä vastaa kieli, jolla dokumentti kirjoitetaan. Eräs tällainen tyyppi HTML, joka on tarkoitettu hypertekstidokumentteja varten. (Oikeastaan se on joukko lähisukuisia tyyppejä, sillä HTML:stähän on useita versioita.)

SGML voidaan siis käsittää metakieleksi, jolla kuvataan dokumenttityyppejä vastaavia kieliä (esim. HTML-kieli).

HTML ei kaikilta osin ole mitenkään tyypillinen tai ideaalinen esimerkki SGML:n käytöstä. Osasyynä tähän on se, että HTML on pikemminkin vähitellen muodostunut kuin järjestelmällisesti suunniteltu.

SGML:n peruskäsitteitä ja -rakenteita

Dokumenttityypin määrittely (DTD)

SGML:ssä dokumenttityypin määrittely (document type definition, DTD) kuvaa dokumentin muodollisen syntaksin kuten sen, millaisia rakenteita mikin rakenne saa sisältää. Rakenteiden merkitys (tulkinta) esitetään erikseen luonnollisella kielellä; tällaisia selityksiä voidaan liittää myös dokumenttityypin määrittelyyn kommentteihin. Yksinkertaisimmassa tapauksessa kommentti alkaa merkkiyhdistelmällä <!-- ja loppuu merkkeihin -->.

Elementtien yleinen rakenne

Dokumentin sisältämiä rakenteita kutsutaan elementeiksi. (Käytän tässä yhteydessä sanaa elementti englannin sanan element vastineena, koska "suomalaisempi" vastine alkio olisi harhaanjohtava: elementti voi olla hyvinkin laaja ja kompleksinen; esimerkiksi jokainen HTML-tiedosto kokonaisuudessaan on periaatteessa yksi elementti.)

Elementtien yleinen rakenne on seuraava:

Elementin määrite (attribute) koostuu jostakin avainsanasta, yhtäläisyysmerkistä ja määritteen arvosta. Erikoistapauksena voivat yhtäläisyysmerkki ja määritteen arvo puuttua, mikä tarkoittaa, että määritteen arvo on sama kuin avainsana. (Esim. määrite COMPACT tarkoittaa samaa kuin COMPACT=COMPACT.)

Esimerkki elementistä HTML-kielessä ( H1-elementti)

<H1 ALIGN=CENTER>Johdanto</H1>

Elementtien syntaksin määrittely SGML:ssä

Edellä sanottu pätee dokumenttityypistä riippumatta eli kyse on kaikille SGML:n avulla määriteltäville kielille yhteisistä piirteistä. Dokumenttityypin määrittelyssä on olennaista, että se kertoo elementtien yksityiskohtaisen syntaksin: mitä elementtien nimiä on, mitä määritteitä kuhunkin elementtiin voidaan liittää, mitä arvoja kullakin määritteellä voi olla ja millaisia elementtejä kunkin elementin sisällössä voi olla. Lisäksi se kertoo mm. sen, mistä elementeistä lopetustägi voidaan tai täytyy jättää pois.

Elementin perussyntaksi määritellään esim. seuraavaan tapaan:

<!ELEMENT H1 - - %text>

Tämä määrittelee, että H1 on yksi mahdollinen elementinnimi ja että H1-elementin sisällön tulee vastata määrittelyä %text (johon palataan jäljempänä mutta joka sisältää mm. pelkän tekstin ja erilaisia korostuselementtejä mutta ei esim. otsikkoelementtejä). Miinusmerkit - - tarkoittavat, että aloitus- ja lopetustägi ovat molemmat pakollisia; jos miinusmerkin tilalla on O-kirjain (joka johtuu sanasta optional) niin vastaava tägi saadaan (ja eräissä tilanteissa täytyykin) jättää pois. Esimerkiksi HTML-kielen P-elementin määrittely on seuraava:

<!ELEMENT P - O (%text)*>

Ilmaisu, joka kuvaa elementin sallitun sisällön (edellä olevassa esimerkissä %text), on luonteeltaan ns. säännöllinen lauseke (regular expression); aloitussymbolina on periaatteessa HTML-niminen elementti. SGML:ssä käytetään tässä yhteydessä seuraavia symboleita:

, peräkkäisyys (katenaatio)
& peräkkäisyys siten, että järjestys on vapaa
| vaihtoehtoisuus (tai-operaattori)
? (edeltävän rakenteen) valinnaisuus
* (edeltävän rakenteen) valinnaisuus ja toistettavuus
+ (edeltävän rakenteen) toistettavuus.
() ryhmittely.

Esimerkiksi määrittely

<!ELEMENT TABLE - - (CAPTION?, TR+)>

sanoo, että TABLE-elementti koostuu yhdestä tai useammasta TR-elementistä, joita voi edeltää CAPTION-elementti. Jos plussan tilalla olisi tähti, niin myös sellainen rakenne olisi sallittu, jossa ei ole yhtään TR-elementtiä. Jos kysymysmerkki puuttuisi, niin CAPTION-elementti olisi pakollinen. Jos pilkun tilalla olisi &-merkki, niin CAPTION-elementti voisi sijaita myös TR-elementtien jälkeen (mutta ei silloinkaan niiden välissä).

Elementin sallitun sisällön kuvaava ilmaisu voi myös olla sana EMPTY, jolloin kyseessä on tyhjä elementti. Tämä tarkoittaa sitä, että elementillä ei voi olla sisältöä eikä sillä tarvitse eikä saa olla lopputägiä. Elementti siis koostuu pelkästään alkutägistä. Tällainen elementti ei suinkaan yleensä ole semanttisesti tyhjä. Esimerkiksi HTML-kielessä HR-elementti (pelkkä <HR>) on syntaktisesti tyhjä edellä kuvatussa mielessä, mutta sillä on toki vaikutus.

Elementin määrittelyssä voi olla (merkkien < ja > välissä) myös kommentti, joka alkaa merkkiparilla -- ja loppuu samanlaiseen merkkipariin.

Määritteiden (attribuuttien) kuvaukset

Elementin perussyntaksin määrittely ei sisällä tietoja mahdollisista määritteistä, vaan sellaiset tiedot annetaan erikseen seuraavaan tapaan:

<!ATTLIST H1
     ALIGN (LEFT | CENTER | RIGHT) #IMPLIED
     >

Tämä tarkoittaa, että H1-elementin määritelistassa (attribute list) on vain yksi mahdollinen määrite, nimeltään ALIGN, ja sen mahdolliset arvot ovat LEFT, CENTER ja RIGHT. (Näissä isojen ja pienten kirjainten ero ei ole merkitsevä. Tosin tämä periaatteessa riippuu kielen ns. SGML-deklaraatiosta).

Symboli | tarkoittaa SGML:ssä yleisesti vaihtoehtoisuutta, tai-operaattoria. Määrittelyssä oleva sana #IMPLIED tarkoittaa, että määrite ei ole pakollinen. Vastaavasti sana #REQUIRED tarkoittaa, että määrite on pakollinen. Jos lopussa ei ole näitä kumpaakaan vaan jokin muu merkintä, se tarkoittaa, että määrite ei ole pakollinen ja että sen oletusarvo (default) on se, jonka merkintä ilmoittaa. (HTML:n kuvauksessa tätä ei useinkaan käytetä, koska oletusarvo voi riippua asiayhteydestä tai implementaatiosta.) Esimerkiksi HTML:n TH- ja TD-elementtien määrittelyssä esiintyvä attribuuttimäärittely

 rowspan NUMBER   1      -- number of rows spanned by cell --

tarkoittaa, että rowspan-attribuutti voi puuttua, mikä vastaa tilannetta rowspan=1.

Tavallisimmin !ATTLIST-rakenteessa esitetty määritteen kuvaus käyttää jotakin seuraavista avainsanoista:

avainsana merkitys
CDATA merkkijono
NAME nimi: alkaa kirjaimella (A-Z, a-z) ja saa sisältää kirjaimia ja numeroita
ID nimi, joka on yksiselitteinen dokumentin sisällä
IDREF viittaus (muualla määriteltyyn) nimeen
NUMBER luku: (etumerkitön) numeroiden jono
NMTOKEN kuten nimi, mutta saa alkaa numerolla

Huomautuksia:

Merkit ja merkistö

SGML:llä kuvatun kielen ilmaisut ovat yhdeltä kannalta katsottuna merkkien jonoja, ja rakenteellisesti alimman tason rakenteen kielessä ovat sellaisia elementtejä, joiden sisältönä on pelkkää tekstiä. Tällainen sisältö ilmaistaan symbolilla CDATA tai symbolilla #PCDATA. Jälkimmäisessä tapauksessa kyseessä on ns. parsed character data, mikä tarkoittaa, että sen tulkinnassa eräillä merkkiyhdistelmillä, ns. entiteeteillä, on erikoismerkitys siihen tapaan, että &auml; saattaa tarkoittaa ä-kirjainta (ja jos &-merkki halutaan esittää, on käytettävä sille merkintää &amp;). Huomautus: elementin sisällön kuvauksessa CDATA merkitsee, että mainittuja entiteettejä ei tulkita (t.s. &-merkki tarkoittaa aina vain itseään), kun taas määritteen kuvauksessa sillä on olennaisesti sama merkitys kuin #PCDATAlla (t.s. entiteetit tulkitaan).

Merkistönä on yleensä ISO Latin 1 tai jokin sitä laajempi merkistö, esim. Unicode, mutta periaatteessa SGML-kielellä voidaan määritellä, mitä merkistöä käytetään.

Entiteetit

SGML:ssä voidaan käyttää eräitä yksinkertaisia makron tapaisia rakenteita, joista käytetään nimitystä entiteetti, engl. entity.

Esimerkiksi HTML:n käyttäjälle tuttu merkintä &auml; on tavallaan makron auml kutsu. SGML:llä määritellyissä kielissä "makron" kutsu siis alkaa &-merkillä ja loppuu puolipisteeseen, joskin puolipiste voidaan joissakin tilanteissa jättää pois. Kyseisen "makron" eli entiteetin määrittely on seuraavanlainen:

<!ENTITY auml   CDATA "&#228;" -- small a, dieresis or umlaut mark -->

Tässä siis määrittely esitetään yksinkertaisesti merkkijonona, joka sisältää ä-kirjaimen (ISO-Latin-1:n mukaisen) koodiarvonsa avulla esitettynä.

Rakenne &#228; on sekin tavallaan makro. Sentapaisten merkintöjen virallinen nimitys on numerical character reference Periaatteessa sen, miten tällaiset merkinnät tulkitaan, määrää ns. document character set, joka HTML:n osalta on Unicode. HTML:ssä siis merkintä &#n; tarkoittaa aina sitä merkkiä, jonka koodi Unicodessa on n (jos sellainen on olemassa). Nimitys document character set on huomattavan harhaanjohtava, koska se tarkoittaa nimenomaan ja vain tätä määrätyntyyppisten entiteettien tulkintaa! Sillä ei ole mitään tekemistä sen kanssa, millaisia merkkejä ja minkä merkkikoodin mukaan dokumentissa esiintyy.

Esimerkin pohjalta lienee helppo ymmärtää ja muistaa, että makrojen nimissä isojen ja pienten kirjainten ero on merkitsevä, toisin kuin esim. elementtien nimissä. (Makron auml lisäksi on määritelty makro Auml, jolla saadaan iso Ä-kirjain.) Periaatteessa nämä seikat tosin ovat sellaisia piirteitä, jotka ovat määriteltävissä SGML-kielellä, eivät itse SGML:n piirteitä.

Makrojen kutsuja voidaan siis käyttää sellaisessa kielessä (esim. HTML:ssä), joka on määritelty SGML:llä, jos makro on määritelty kyseisen dokumenttityypin yhteydessä. Toisentasoisia makroja, parameter entities, ovat ne, joita käytetään metakielessä eli SGML:ssä (siis esim. HTML:n kuvauksessa, ei itse HTML:ssä). Niiden määrittelyissä ja kutsuissa käytetään %-merkkiä erottamaan ne edellä kuvatuista makroista. Esimerkiksi HTML:n SGML-kielisessä kuvauksessa esiintyvät seuraavat makronmäärittelyt:

<!ENTITY % font "TT | I | B  | U | STRIKE | BIG | SMALL | SUB | SUP">
<!ENTITY % phrase "EM | STRONG | DFN | CODE | SAMP | KBD | VAR | CITE">

Näistä esimerkiksi edellinen tarkoittaa yksinkertaisesti sitä, että %font on lyhennysmerkintä ilmaisulle TT | I | B | U | STRIKE | BIG | SMALL | SUB | SUP. Täten esimerkiksi määrittely

<!ELEMENT (%font|%phrase) - - (%text)*>

on lyhennysmerkintä, joka tarkoittaa seuraavaa:

<!ELEMENT (TT | I | B  | U | STRIKE | BIG | SMALL | SUB | SUP |
  EM | STRONG | DFN | CODE | SAMP | KBD | VAR | CITE) - - (%text)*>

ja siis yhdellä kertaa määrittelee varsin monien HTML-elementtien perussyntaksin. Tässä tietysti myös %text on lyhennysmerkintä; sen määritelmä on seuraava:

<!ENTITY % text "#PCDATA | %font | %phrase | %special | %form">

Muutoinkin lyhennysmerkintöjen käyttö on olennaista, jotta mm. HTML-kielen SGML-kielinen kuvaus on saatu kohtuullisen lyhyeksi ja tiiviiksi.

Poikkeussääntöjen esittäminen

Koska pelkät säännölliset lausekkeet eivät aina ole riittävän ilmaisuvoimainen keino, on SGML:ssä myös mahdollisuus esittää ns. poikkeuksia (exceptions). Tätä nimitystä käytetään kahdesta varsin erityyppisestä asiasta:

ekskluusio (exclusion)
sen ilmaiseminen, että elementti ei saa sisältää määrättyjä elementtejä, vaikka normaali (säännöllisten lausekkeiden avulla esitetty) määrittely sen sallisi
inkluusio (inclusion)
sen ilmaiseminen, että määrätty elementti saa esiintyä missä tahansa kohdassa jonkin rakenteen sisällä, vaikka tämä mahdollisuus ei sisälly normaaliin määrittelyyn.

Ekskluusio ilmaistaan siten, että määrittelevän ilmaisun loppuun kirjoitetaan miinusmerkki ja sitten ilmaisu, joka esittää kielletyt elementit. Inkluusio on syntaksiltaan vastaava siten, että miinusmerkin tilalla on plusmerkki.

Esimerkkejä HTML:n määrittelystä:

<!ENTITY % pre.exclusion "IMG|BIG|SMALL|SUB|SUP|FONT">
<!ELEMENT PRE - - (%text)* -(%pre.exclusion)>

Tämä tarkoittaa, että PRE-elementin sisältönä saa olla mikä tahansa tekstielementtien jono, kunhan mikään niistä tai mikään niiden sisältämä elementti ei ole IMG-, BIG-, SMALL-, SUB-, SUP- tai FONT-elementti. Huomattakoon, että "positiivisempi" määrittely, jossa ilman ekskluusiota vain lueteltaisiin muut tekstielementit kuin nuo kielletyt, ei olisi riittävä. Sellainen määrittely nimittäin kieltäisi esim. IMG-elementin esiintymisen vain ylimmällä rakennetasolla PRE-elementin sisällössä.

<!ENTITY % head.misc "SCRIPT|STYLE|META|LINK" -- repeatable head elements -->
<!ENTITY % head.content "TITLE & ISINDEX? & BASE?">
<!ELEMENT HEAD O O  (%head.content) +(%head.misc)>

Tässähän head.misc on yksinkertainen makro (jossa piste on osa makron nimeä ilman erikoismerkitystä), samoin head.content. Itse määrittely kertoo HEAD-elementistä seuraavat asiat:

Tietoja SGML:stä WWW:ssä

Tietoja suomeksi

Tietoja englanniksi

SGML:n varsinaiset määrittelyt

Itse SGML-standardia, ISO 8879:1986, ei ole Webissä, koska tekijänoikeuden omistaja ISO ei sitä halua.

SGML-kielen täydellisimpänä kuvauksena voidaan pitää sitä, joka sisältyy seuraavaan (varsin raskaslukuiseen ja laajaan, 663 s.) kirjaan, joka sisältää myös koko standardin:

Goldfarb, Charles F.: The SGML handbook
Oxford, 1990. Clarendon Press.
ISBN 0-19-853737-9. UDK: 681.3.06

Standardia tai kirjaa luettaessa voi olla apua Chris Madenin koosteesta Productions from ISO 8879:1986 - SGML, jossa on tiivistettynä SGML:n itsensä syntaksi.


Jukka Korpela 2003-12-25. Korjattu viimeksi 2005-02-06.