Shakespeares sonetter
XML og CSS
Vi ta fatt i den originale XML-fila og kopler til et stilsett, sonnetes-xml.css, som ser slik ut:
sonnetes{ color: black; font-family: "Geneva", "Verdana", "Arial", sans-serif; font-size: 13px; text-align: left; margin-left:10px; margin-top:10px; } sonnete{ margin-top:20px; display:block; } id{ font-size:16; margin-left:140px; margin-top:30px; display:block; } line{ color:#783E1E; margin-left:20px; display:block; }
Tilkoplingen skjer i prologen til XML-fila, som nå blir slik:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE sonnetes SYSTEM "sonnetes.dtd"> <?xml-stylesheet code="text/css" href="sonnetes-xml.css"?> <sonnetes> ...
Vi ser at det er mye som kan gjøres for å forbedre dette, men vi konsentrerer oss i stedet om en transformasjon til HTML.
XSLT og HTML
Vi lager første en enkel transformasjon fra XML til HTML med helt tilsvarende struktur. Denne transformasjonen gir ingen annen gevinst enn at vi kan legge inn overskrifter osv.
Deretter lager vi en transformasjon som produserer en innholdsfortegnelse basert på sonette nummeret og den første linja i sonetten. Denne legger vi først i HTML-fila.
Flat HTML - fil
Transformasjonen lager XHTML strict og er slik:
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" encoding="ISO-8859-1" indent="yes"/> <xsl:template match="/"> <html> <head> <link rel="stylesheet" href="sonnetes.css" /> <title>Sonnets</title> </head> <body> <h1>Sonettene</h1> <xsl:apply-templates select="sonnetes/sonnet"/> </body> </html> </xsl:template> <xsl:template match="sonnetes/sonnet"> <div class="id"><xsl:value-of select="id"/></div> <xsl:for-each select="line"> <div class="line"><xsl:value-of select="."/></div> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Transformasjonen koples til i prologen til XML-fila som nå ser slik ut:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE sonnetes SYSTEM "sonnetes.dtd"> <?xml-stylesheet code="text/xsl" href="tohtml1.xslt"?> <sonnetes> ...
indeksert HTML - fil
Transformasjonen er bygget opp med to løkker. Den første går gjennom alle sonettene og produserer en liste av linker til de respektive sonettene. Den andre løkka er lik den vi brukte ovenfor, med den forskjellen at vi legger inn et anker i starten av hver sonette. Produksjon av referanse og anker er lagt til to funksjoner:
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" encoding="ISO-8859-1" indent="yes"/> <xsl:template match="/"> <html> <head> <link rel="stylesheet" href="sonnetes.css" /> <title>Sonnets</title> </head> <body> <h1>Sonettene</h1> <!-- a table of content based on first line in sonnet --> <table> <xsl:for-each select="sonnetes/sonnet"> <tr> <td class="ixnumber"> <xsl:value-of select="id"/> </td> <td class="ixname"> <xsl:call-template name="makeLocalRef"> <xsl:with-param name="adr"> <xsl:copy-of select="child::id[position()=1] "/> </xsl:with-param> <xsl:with-param name="nam"> <xsl:copy-of select="child::line[position()=1] "/> </xsl:with-param> </xsl:call-template> </td> </tr> </xsl:for-each> </table> <!-- the sonnets --> <xsl:for-each select="sonnetes/sonnet"> <xsl:apply-templates select="."/> </xsl:for-each> </body> </html> </xsl:template> <xsl:template match="sonnet"> <div class="id"> <xsl:call-template name="makeAnchor"> <xsl:with-param name="adr"> <xsl:copy-of select="id "/> </xsl:with-param> </xsl:call-template> </div> <xsl:for-each select="line"> <div class="line"><xsl:value-of select="."/></div> </xsl:for-each> </xsl:template> <xsl:template name="makeLocalRef"> <xsl:param name="adr">any adress</xsl:param> <xsl:param name="nam">any name</xsl:param> <a href="#{$adr}"><xsl:copy-of select="$nam"/></a> </xsl:template> <xsl:template name="makeAnchor"> <xsl:param name="adr">any adress</xsl:param> <a name="{$adr}"><xsl:copy-of select="$adr"/></a> </xsl:template> </xsl:stylesheet>
Transformasjonen koples til i prologen til XML-fila som nå ser slik ut:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE sonnetes SYSTEM "sonnetes.dtd"> <?xml-stylesheet code="text/xsl" href="tohtml2.xslt"?> <sonnetes> ...
Nettsted
Vi forsøker å lage et pythonprogram som tar XML-fila og bygger opp et nettsted der hver sonette er en egen side. Det vil si at vi vil lage følgende struktur:
![Splitte Shakespeares sonetter på flere websider split](shakespeare.gif)
Det betyr at vi skal lage en transformasjon som lager tre filtyper og 156 filer. Vi kaller transformasjonen shake og vil altså lage en Python-modul: shake.py.
Det er mange måter å gjøre dette på. Vi kan lage et Pythonprogram som er komplett i den forstand at det lager komplette filer inkludert stilsett. Jeg har i stedet valgt å lage tre templatefiler og et felles stilsett. Pythonprogrammet lager innhold som puttes inn i templatefilene. Fordelen med dette er at det er lettere å endre stil og layout på filene uten å endre Pythonkoden. Erfaringsmessig er det lettere å endre HTML- og CSS-kode enn det er å reprogrammere Python. Dette gjelder både under utvikling, og spesielt ved senere vedlikehold.
Pythonprogrammet
AJAX-løsning
Her lager vi en fast side, henter bare den sonetten vi ønsker og plasserer den på siden.
Det involverte Pythonskriptet som leverer den ønskede sonetten fra en XML-fil ser slik ut:
Javascriptkoden som går på vevsiden har de vanlige AJAX-funksjonene og det har kontroll av input. Det ser slik ut:
// relies on jquery.js function getIt(address,targetNodeId) { box = document.forms[0].nr; snr = box.value; $.ajax({ url:address, data:'nr='+snr, success:function(data) { $('#'+targetNodeId).html(data); }, error:function(data) { $('#'+targetNodeId).text('error'); } }); }