5. Programmering av webbsidor

Aarne Ranta
Datorintroduktion 2009, D och DV, Chalmers & GU

HTML

HTML = HyperText Markup Language - språket som används för att skriva webbsidor.

"Markup": taggar som strukturerar texten.

En webbläsare (t.ex. Firefox) är ett program som tolkar HTML och visar texten genom att göra de saker som taggarna anger.

(Jfr. GHCi: det är ett program som tolkar Haskell)

Exempel på HTML-dokument

En enkel text

Text med allt möjligt

Fahrenheit-Celsius-tabell

Text med länkar till Google

Text med länkar till en ordbok

Ett fotoalbum

Ett HTML-dokument

Den grundläggande strukturen i ett HTML-dokument finns i följande mall:

  <html>
    <head><title>Head-titeln: texten överst i ramen</title></head>
    <body>
    Body: texten i textfältet.
  
    <h1>Huvudtitel</h1>
  
    <p>
    Paragraf, bestående av text och annat, t.ex.
      <a href="http://www.haskell.org">länkar till webbsidor</a>,
      <b>text i fetstil</b>,
      <i>text i kursiv</i>,
      <tt>text i maskinskrift</tt>,
      <font color="red">text i röd font</font>,
      bilder, som är länkar till bildfiler och kan skalas till önskad storlek 
      (i nästa paragraf): 
    </p>
    <p>
      <img width="132"src="didno.jpg">
    </p>
  
    <h2>Lite mindre titel</h2>
  
    <p>Och så en tabell:</p>
  
    <table border="yes">
    <tr>
      <td>A1</td> <td>A2</td> <td>A3</td>
    </tr>
    <tr>
      <td>B1</td> <td>B2</td> <td>B3</td>
    </tr>
    </table>
  
    </body>
  </html>

Klicka här för att se dokumentet i din webbläsare.

Ett annat HTML-dokument

  <html><head><title>Pictures</title></head>
  <body><table border="yes"><tr><td><a href="pictures/IMG_4922.jpg"><img src="pictures/IMG_4922.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_4935.jpg"><img src="pictures/IMG_4935.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_4944.jpg"><img src="pictures/IMG_4944.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_4950.jpg"><img src="pictures/IMG_4950.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_4955.jpg"><img src="pictures/IMG_4955.jpg" width="128"></a></td>
  </tr>
  <tr><td><a href="pictures/IMG_4956.jpg"><img src="pictures/IMG_4956.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_4957.jpg"><img src="pictures/IMG_4957.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_4966.jpg"><img src="pictures/IMG_4966.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_4971.jpg"><img src="pictures/IMG_4971.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_4974.jpg"><img src="pictures/IMG_4974.jpg" width="128"></a></td>
  </tr>
  <tr><td><a href="pictures/IMG_4999.jpg"><img src="pictures/IMG_4999.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5005.jpg"><img src="pictures/IMG_5005.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5029.jpg"><img src="pictures/IMG_5029.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5036.jpg"><img src="pictures/IMG_5036.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5037.jpg"><img src="pictures/IMG_5037.jpg" width="128"></a></td>
  </tr>
  <tr><td><a href="pictures/IMG_5043.jpg"><img src="pictures/IMG_5043.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5049.jpg"><img src="pictures/IMG_5049.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5059.jpg"><img src="pictures/IMG_5059.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5072.jpg"><img src="pictures/IMG_5072.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5081.jpg"><img src="pictures/IMG_5081.jpg" width="128"></a></td>
  </tr>
  <tr><td><a href="pictures/IMG_5091.jpg"><img src="pictures/IMG_5091.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5099.jpg"><img src="pictures/IMG_5099.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5106.jpg"><img src="pictures/IMG_5106.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5111.jpg"><img src="pictures/IMG_5111.jpg" width="128"></a></td>
  <td><a href="pictures/IMG_5112.jpg"><img src="pictures/IMG_5112.jpg" width="128"></a></td>
  </tr>
  <tr></tr>
  </table>
  </body></html>

Klicka här för att se dokumentet i din webbläsare.

Vill någon skriva sånt här?

Nej! Vi ska skriva ett Haskell-program som skriver HTML-filen.

Detta är ett exempel på generativ programmering: man skriver program som genererar program.

HTML-element och taggar

En tagg är text mellan < och >. Vi börjar med en funktion som producerar en tagg

    tag :: String -> String
    tag t = "<" ++ t ++ ">"

och motsvarande sluttagg:

    endTag :: String -> String
    endTag t = tag ("/" ++ t)

De flesta HTML-elementen skapas genom att omsluta mindre element med en tagg och dess sluttagg:

    tagged :: String -> HTML -> HTML
    tagged t h = tag t ++ h ++ endTag t

Till exempel fetstil:

    bold :: HTML -> HTML
    bold h = tagged "b" h

Själva typen HTML? Vi nöjer oss med den enklaste möjliga,

    type HTML = String

Alla dessa definitioner finns i biblioteket som har skapats för den här föreläsningen och uppgifterna: MkHTML:

Ett litet HTML-bibliotek

Alla dessa finns i MkHTML:

  para :: HTML -> HTML
  para h = tagged "p" h
  
  header :: Int -> HTML -> HTML
  header i h = tagged ("h" ++ show i) h
  
  bold :: HTML -> HTML
  bold h = tagged "b" h
  
  italic :: HTML -> HTML
  italic h = tagged "i" h
  
  typewriter :: HTML -> HTML
  typewriter h = tagged "tt" h
  
  string :: String -> HTML
  string s = s
  
  list :: [HTML] -> HTML
  list hs = unlines hs

Attribut

En tagg kan innehålla attribut, som ger extra information.

Exempel 1: en länk har URL:en (= Uniform Resource Locator, "webbadressen") som attribut:

    <a href="http://www.haskell.org">Haskell Home</a>

Exempel 2: en bild har både bild-URL:en och valfria storleksattribut:

    <img src="pictures/IMG_5091.jpg" width="128">

Obs: URL-attributet kan vara en fil på samma dator, som i bildexemplet.

Obs: sluttaggen har inga attribut.

Generering av attribut

Vi kan generalisera den tagg-skapande funktionen:

    attrTag :: String -> [(String,String)] -> String
    attrTag t attrs = 
      tag (t ++ " " ++ unwords [a ++"=" ++ "\"" ++ v ++ "\"" | (a,v) <- attrs])

Nu kan vi skriva

    attrTagged :: String -> [(String,String)] -> HTML -> HTML
    attrTagged t attrs h = attrTag t attrs ++ h ++ endTag t

Och sedan:

    link :: String -> HTML -> HTML
    link url txt = attrTagged "a" [("href",url)] txt
  
    image :: String -> Int -> HTML
    image url size = attrTag "img" [("src",url),("width", show size)]

Alla dessa finns i MkHTML.

Fullständiga HTML-dokument

Dokumentet ska (oftast) ha formen

  <html>
    <head>
      <title> Titeln </title>
    </head>
    <body>
      Innehållet
    </body>
  </html>

Vi skapar detta med

  html :: String -> HTML -> HTML
  html hd bod = tagged "html" (headTitle (string hd) ++++ body bod)
  
  headTitle :: String -> HTML
  headTitle s = tagged "head" (tagged "title" s)
  
  body :: HTML -> HTML
  body h = tagged "body" h

Alla dessa finns i MkHTML.

Ett fullständigt exempel i Haskell

HTML-koden:

  <html>
    <head>
      <title>Hello</title>
    </head>
    <body>
      Hello World
    </body>
  </html>

Haskell-koden

    html "Hello" (string "Hello World")

Resultatet i webbläsaren

I Haskell blir det mindre att skriva.

Och det blir inga syntaxfel t.ex. saknande sluttaggar.

Ett annat exempel

HTML-koden:

  <html>
    <head><title>Head-titeln: texten överst i ramen</title></head>
    <body>
    Body: texten i textfältet.
  
    <h1>Huvudtitel</h1>
  
    <p>
    Paragraf, bestaende av text och annat, t.ex.
      <a href="http://www.haskell.org">lankar till webbsidor</a>,
      <b>text i fetstil</b>,
      <i>text i kursiv</i>,
      <tt>text i maskinskrift</tt>,
      <font color="red">text i röd font</font>,
      bilder, som ar lankar till bildfiler och kan skalas till onskad storlek 
      (i nästa paragraf): 
    </p>
    <p>
      <img width="132"src="didno.jpg">
    </p>
    <h2>Lite mindre titel</h2>
    </body>
  </html>

Haskell-koden:

    html 
      "Head-titeln: texten overst i ramen"
      (list [
        string "Body: texten i textfaltet.",
        header 1 "Huvudtiteln",
        para (list [
          string "Paragraf, bestaende av text och annat, t.ex.",
          link "http://www.haskell.org" "lankar till webbsidor",
          bold "text i fetstil",
          italic "text i kursiv",
          typewriter "text i maskinskrift",
          colored "red" "text i rod font",
          string "bilder, som ar lankar till bildfiler och kan skalas",
          string "till onskad storlek (i nasta paragraf):"
        ]),
       para (image "didno.jpg" 512),
       header 2 "Lite mindre titel"
      ])

Dokumentet i webbläsaren.

Vi vinner knappast något med Haskell här...

Tabeller

En enkel tabell ser ut så här:

A1 A2 A3
B1 B2 B3

HTML-koden ser ut så här:

  <table border="yes">
    <tr>
      <td>A1</td> <td>A2</td> <td>A3</td>
    </tr>
    <tr>
      <td>B1</td> <td>B2</td> <td>B3</td>
    </tr>
  </table>

Vi vill kunna skapa tabellen med Haskell-koden

    table [["A1","A2","A3"],["B1","B2","B3"]]

Generering av tabeller

En tabell kan ses som en lista av listor.

Den yttre listan är raderna (<tr>), de inre är cellerna (<td>).

Vi kan så klart använda listkomprehension:

    table :: [[HTML]] -> HTML
    table rows = 
      attrTagged "table" [("border","yes")] 
        (list [tagged "tr" (list [tagged "td" cell | cell <- row]) | row <- rows])

Funktionen finns även i MkHTML

Generering av större tabeller

Vi kan generera innehållet i tabellen med listkomprehension:

    html
      "Fahrenheit to Celcius"
      (table [[show f, show (5*(f - 32)/9)] | f <- [0,20 .. 300]])

Resultatet finns här.

Fotoalbumet

Vårt fotoalbum är en tabell där

Om pics är listan av bildernas URL:er, kan vi generera albumet med

    html
      "Pictures"
      (table (grid 5 [link pic (image pic 128) | pic <- pics]))

Funktionen grid (finns i MkHTML) styckar upp en lista till dellistor av önskad längd:

    grid :: Int -> [a] -> [[a]]
    grid i [] = []
    grid i xs = take i xs : grid i (drop i xs)

Obs: grid är en rekursiv funktion, dvs. den anropar sig själv. Detta begrepp hör till nästa Haskell-kurs!

Hur man skapar fillistan

Vi har använt Unix-kommandot ls:

    ls pictures/*.jpg > pics

som gav oss alla filer i katalogen pictures med namnsuffixen jpg.

Dessa skrevs till filen pics, som sedan lästes av en IO-funktion så här:

    mk_test5 :: IO ()
    mk_test5 = do
      s <- readFile "pics"
      let pics = lines s
      let doc = html
          "Pictures"
          (table (grid 5 [link pic (image pic 128) | pic <- pics]))
      writeFile "test5.html" doc

Vi går inte genom detaljerna på den här kursen - men den här koden kan tillämpas till vilken som helst katalog med JPG-filer.

Generering av Google-sökningar

Om man går till Google och slår in ett sökord, t.ex. "haskell", öppnas en webbsida som har URL

    http://www.google.se/search?&q=haskell

Från detta kan vi gissa en funktion

    googled :: String -> HTML
    googled s = link ("http://www.google.se/search?&q=" ++ s) s

För att länka varje ord i en text till en Google-sökning används

    googledText :: String -> HTML
    googledText s = unwords [googled w | w <- words s]

Som exempel på detta, skapar Haskell-koden

    html
      "Google bakom lankarna"
      (googledText "Varje ord som klickas skickas till Google")

det här dokumentet.

Dynamiska HTML-sidor

Vi har visat hur man skapar statiska sidor: de skapas en gång, läggs ut på nätet, och ändras inte automatiskt.

Dynamiska sidor: ett program skriver nya sidor t.ex. som svar till besökarnas frågor.

Google är ett typexempel.

Haskell är ett möjligt språk även för dynamisk webbprogrammering, se här.

Ett exempel med Haskell, GF och Google Web Toolkit: flerspråkiga kylskåpsmagneter.

Andra sätt att skapa HTML

De här föreläsningarna har skapats med txt2tags.

Källan till den här föreläsningen ser ut så här.

Fördelar:

Nackdelar:

Uppgifter

Redovisning. Visa de resulterande HTML-sidorna i en webbläsare.

1. Skapa en HTML-fil som innehåller ditt namn och foto (om du har ett digitalt; annars någon annan trevlig bild). och valfritt annat material. Gör detta manuellt i HTML eller med en Haskell-funktion genom att använda MkHTML.hs.

2. Undersök hur man skapar söklänkar till Wikipedia och generera sedan en HTML-sida som innehåller en tabell med namnen på de 27 EU-länderna, med 3 länder på en rad. Varje land ska vara länkat till Wikipedia-artikeln om landet. Börja med att söka upp listan av EU-länderna på nätet. (Vi rekommenderar engelsk Wikipedia sör att slippa problemen med äåö.)

3. Skapa ett eget fotoalbum genom att återanvända funktionen mk_test5.html i MkHTML.hs. Albumet ska innehålla minst 15 bilder. Tips: om du inte har egna digitala bilder, kan du hitta sådana med Googles bildsökning.

4. Modifiera ordstatistikfunktionen i Freq.hs (föreläsning 4) så att den skriver ut de 100 vanligaste orden med antalet förekomster till en tabell i en HTML-fil. I redovisningen, visa resultatet för Röda rummet.

Sammanfattning och referens

Vi hade inget nytt Haskell-material, utan bara en del HTML, som kan sammanfattas i malldokumentet med källkoden

  <html>
    <head><title>Head: texten överst i ramen</title></head>
    <body>
    Body: texten i textfältet.
  
    <h1>Huvudtitel</h1>
  
    <p>
    Paragraf, bestående av text och annat, t.ex.
      <a href="http://www.haskell.org">länkar till webbsidor</a>,
      <b>text i fetstil</b>,
      <i>text i kursiv</i>,
      <tt>text i maskinskrift</tt>,
      <font color="red">text i röd font</font>,
      bilder, som är länkar till bildfiler och kan skalas till önskad storlek 
      (i nästa paragraf): 
    </p>
    <p>
      <img width= "512" src="didno.jpg">
    </p>
  
    <h2>Lite mindre titel</h2>
  
    <p>
    Och så en tabell:
    </p>
  
    <table border="yes">
    <tr>
      <td>A1</td> <td>A2</td> <td>A3</td>
    </tr>
    <tr>
      <td>B1</td> <td>B2</td> <td>B3</td>
    </tr>
    </table>
  
    </body>
  </html>