GPL, CC och skillnadens betydelse för Remix

Som jag nämnde tidigare idag har jag konverterat en bok till epub-format. Det krävde några kvällars arbete, och gav stoff till åtminstone tre blogginlägg. Jag slår ihop dem till ett genom att fuska mig igenom de första två i förbigående.

1: Epub är inget bra format för eböcker. Jag skaffade nyligen en Sony PRS-300, vilken jag är riktigt nöjd med (åtminstone nöjdare än Jocke). Den läser, i likhet med en lite mer hajpad läsplatta, epub-formatet. Som flera andra moderna format är det i princip en zippad hög med XHTML-filer, samt övriga resurser (bilder, stylesheets osv). Det är en bra början att bygga på standardiserade format som dessutom kan undersökas med enkla verktyg (vilket kan jämföras med betydelsen av ”view source”-konceptet för webben), men det finns ett par problem:

  • I böcker används fotnoter. Det finns inget bra och etablerat sätt att med XHTML/CSS2.1, och därmed i ePub, representera fotnoter (det finns i CSS3, men det stöds inte av epub-standarden).
  • I böcker används sidnummer. Det finns inget standardiserat och väletablerat system för att koppla sidnummer till textavsnitt (det finns däremot ett standardiserat, och ett helt annat, väletablerat, system). Vilket är trist för den som vill hänvisa till ett visst ställe i en epub-bok.
  • Epub-formatet har inte annammat ”convention over configuration”-principen, vilket leder till en rad filer vars innehåll är statiskt eller upprepningar av information som redan finns någon annanstans. Varje enskild del av en bok hänvisas två gånger i content.opf, och ytterligare en gång i toc.ncx.

Kanske hade det varit bättre att bygga på DocBook eller TEI?

2: Att konvertera PDF till epub på ett bra sätt är icketrivialt. Epub är, genom att det bygger på XHTML, ett format som låter oss uttrycka semantiken i en text (eller åtminstone textens yttre form). Vi kan tala om att en rubrik är just det, och inte bara en textsnutt som råkar ha ett visst typsnitt, i en viss storlek, placerad på ett visst ställe på en sida (vilket är allt PDF låter oss göra). I Remix används kapitel (samt ett antal andra typer av textsektioner), fyra rubriknivåer, blockcitat, fotnoter, slutnoter, kapitäler, anfanger, index, sidhuvuden, sidfötter samt på ett ställe dialog.

All information om att en viss textsnutt representerar någon av dessa konstruktioner är borttagna i en PDF. Allt som återstår är information om var på en sida varje enskild textsnutt ska placeras, och med vilket typsnitt det ska visas. Om man i löpande text  exempelvis fetstilar något representeras detta som en separat textsträng. Att avgöra vilka textsträngar som tillsammans utgör ett stycke är ganska svårt.

Man får en bild av hur svårt det är om man tar en PDF-fil och använder Adobe Readers inbyggda ”Save as text”-funktion. Det var så jag började konvertera hela texten. Genom lite sök-och-ersätt samt dess kusin-på-stereoider, tangentbordsmakron i emacs, kunde jag steg för steg återskapa den semantik som ursprungligen fanns i Lessigs text, innan den konverterades till PDF. Det var detta arbete som tog några kvällar.

3: Allt remixarbete förutsätter tillgång till råformat. Den remixare som inte har råformat måste först ägna tid åt att konvertera vad han/hon nu har tillgång till, till ett format som duger för att bygga vidare på.

Råformatet är det format man använder för att skapa eller vidareutveckla ett verk. Det är sällan det slutformat som man faktiskt vill använda för att uppleva verket. Råformatet kan vara ett gäng wav-filer (ett för varje inspelat instrument), och slutformatet en mp3-fil. Råformatet kan vara en LaTeX-fil, några EPS-filer samt en Bibtex-databas, och slutformatet en PDF. Råformatet kan vara en filstruktur fylld med källkod och slutformatet en exekverbar binär. Ni fattar.

Lessig har tillgängliggjort verket som PDF-fil under en CC-licens, vilket förstås är generöst (även om det tog tid), men jag som  remixare av innehållet hade hellre velat ha tillgång till de ursprungliga .doc/.odt-filerna. Istället fick jag ägna mycket tid åt att rekonstruera ett råformat genom att ta den textfil som Adobe Reader konstruerat och sedan manuellt märka upp de semantiska element som gått förlorade i PDF-konverteringen.

Det här är relativt vanligt bland Creative Commons-licensierat material, att man enbart slutformatet, inte råformatet, tillgängliggörs. I öppen källkod-världen skulle ingen drömma om att släppa en kompilerad binär utan att samtidigt den källkod som använts för att bygga densamma (och de som prövar blir förstås utskällda).

På FSCONS 2008 höll Mike Linksvayer från Creative Commons ett föredrag om skillnaden mellan ”Free Software”-rörelsen (dvs öppen källkod) och ”Free Culture”-rörelsen (dvs Creative commons), eller kanske snarare hur långt efter den senare ligger efter den förra (Det finns sammanfattat i hans text i boken som gjordes från den konferensen). Bland annat berördes att skillnaden mellan råformat och slutformat för programkod är knivskarp, medans den är betydligt suddigare för exempelvis en bok eller en musikinspelning.

Kanske är det anledniningen till att favoritlicensen inom öppen källkod-rörelsen (GPL) redan i sin andra klausul sätter en viktig definition:

The “source code” for a work means the preferred form of the work for making modifications to it.

Creative commons-licenserna innehåller inget liknande.

En kompilerad binär är relativt hopplös att bygga vidare på, även om man har juridisk tillåtelse. En färdigställd PDF kan man faktiskt bygga något från, även om det tar tid. Kanske är det anledningen till att Lessig nöjer sig med att släppa sina verk enbart i slutformat. Men om man stannar där tror jag att man missar något viktigt. Nämligen:

4: Ju enklare det är att skapa ett nytt slutformat, ju enklare är det att göra en remix. Om det första man måste göra är att konvertera en excelfil med ett inbäddat epostmeddelande med en digitalkamerabild av en utskrift av en skärmdump av en accessdatabas så kommer färre personer att göra något kul med informationen. Och om man har skapat det ursprungliga verket med verktyg som gör det svårt eller dyrt att bygga en slutversion så får det samma effekt. När Lawrence Lessig skrev ”Remix” gissar jag att han använde Microsoft Word eller OpenOffice Writer, för att skapa en eller flera .doc eller .odt-filer, som sedan en typograf laddade in i InDesign och skapade en .indd-fil utav. Efter en hel del typografiskt finlir skapades slutligen en tryckfärdig PDF. Slutformatet blev mycket grafiskt tilltalande, men krävde säkerligen en hel del manuellt arbete. Om författaren, efter att ha lämnat textmaterialet till typografen, velat göra en omstrukturering, krävs förmodligen att detta manuella arbete till stor del görs om. Nu är jag ingen expert på InDesign, men jag gissar att det är svårt till omöjligt att bara med ett knapptryck (eller hellre en kommandorad) gå från råformat till slutformat. Om inte annat så krävs det tillgång till Adobe InDesign, en proprietär programvara som definitivt är utanför min budget.

I ”Free Culture” skriver Lessig i sitt förord:

I realize that all of the theoretical insights I develop here are insights Stallman described decades ago. One could thus well argue that this work is “merely” derivative.

I  accept that criticism, if indeed it is a criticism. The work of a lawyer is always derivative, and I mean to do nothing more in this book than to remind a culture about a tradition that has always been its own.

Jag menar att det finns mer att lära av Richard Stallman. Exempelvis kan man uppmärksamma att en av de första program han skrev för sitt helt fria operativsystem var en implementation av make, ett fritt system för att helt automatiskt från råformat (källkod) skapa ett slutformat (körbart program). Hade Lessig använt det (tillsammans med exempelvis LaTeX) för att skriva Remix hade han säkert fått se flera remixer av det.

Tre antipatterns i webinteraktionsdesign

Ett antipattern är ett sätt att göra något på, som vid första anblicken verkar vara en vettig approach, men som egentligen gör saker värre. Inom webbutvecklingsvärlden finns det en rik flora av dessa. Här är några exempel:

Pagers som visar ett löjligt litet antal saker åt gången
En pager är alltså den gränssnittskonstruktion som visar ett visst antal saker åt gången – exempelvis sökträffar eller bloggkommentarer. Eftersom det är mycket bökigare att konstruera ett pagingsystem än att helt enkelt visa alla saker på en gång vill folk förstås använda det, och sätter därför gränsen för antal saker som ska visas alldeles för lågt. Bredband är billigt, och moderna webbläsare klarar numera sidor över 15 kb. Minst 100 saker åt gången, tack.
För korta sessionstimeouts
Alla moderna webbprogrammeringsramverk har någon typ av sessionshanteringssystem, så att programeraren ska kunna spara ner en massa information om vad en viss användare gör i steg 1, så att man kan läsa upp det igen i steg 2. Att spara denna information tar förstås lite minne i webbserverprocessen, och har man många användare vill man förstås se till att rensa bort sådant som aldrig kommer användas, eftersom användaren lämnat webbplatsen och inte kommer göra något steg 2-request. Så alla webbprogrammeringsramverk har en sessionstimeout – om inte användaren begär en ny sida på x minuter rensas den data som associerats med användaren. Och eftersom minne var dyrt under förra årtusendet är denna timeout vanligtvis löjligt lågt satt. Vilket får till effekt att den som skickar in ett långt och genomarbetat webbforuminlägg upptäcker att sessionen timat ut, och att de senaste 21 minuternas arbete gått upp i rök. Minne är billigt, men användares tid är det inte. Sätt upp sessionstimeouten till minst 24 timmar, tack.
Reset-knappar på formulär
HTML-standardens avsnitt om hur man gör formulär innehåller ett antal olika typer av formulärelement – textfält, radioknappar, selectmenyer, submit-knappar samt, av någon outgrundlig anledning, en knapp som tar bort allt man mödosamt skrivit in i formuläret, och återställer det till sitt ursprungstillstånd. Risken för att råka klicka på denna knapp är visserligen inte stor, men det lär ändå inträffa mångdubbelt fler gånger än att någon faktiskt har nytta av det. Det första exemplet i standarden använder denna vansinniga funktion, vilket får till effekt att folk som inte tänker efter tror att det är en bra idé att ge användaren tillgång till något som bara kan användas till att skjuta sig i foten. Sluta med det, tack.

Mediawiki som datalager

lagen.nu använder jag ingen
relationsdatabas. Alla dokument ligger i varsin statisk fil, och den
samling av metadata som behövs för att jag ska kunna exempelvis skapa
index över alla dokument ligger i en gigantisk .n3-fil som jag går
igenom med RDFLib. Anledningen är
förstås min djupt
kända misstro
mot konceptet databasserver i allmänhet och
relationsdatabaser i synnerhet. Jag tycker filsystemet är underskattat
som databas. Det finns alltid där, är snabbt, går att debugga och
manipulera med välbekanta verktyg (ls, find,
grep, xargs, tar, rsync), har ett
begripligt rättighetssystem integrerat med operativsystemet, osv.

Till nästa stora iteration av lagen.nu-koden kommer jag ändå att
börja använda någon sorts server för datalagring. Men det blir
förmodligen inte en traditionell relationsdatabas med
SQL-gränssnitt. Min datamodell är inte särskilt relationell. Med tanke
på hur djupt jag integrerat RDF i systemet blir det förmodligen en
kombination av en triplestore tillsammans med någon form av dokumentdatabas.
För det tidigare blir det förmodligen Sesame, för det senare har jag
tittat nyfiket på CouchDB.

Men i kommentarerna till ett tidigare
inlägg
om en mediaövervakningsbot föreslog Peter Krantz att använda Mediawiki som
datalagring. Jag började kolla på hur man kan automatisera hämtning
och lagring av data från en Mediawikiserver, och det visar sig att det
finns en mycket kompetent pythonmodul, mwclient, för
ändamålet (det finns även ett annat ramverk, pywikipedia,
men det gav inte alls ett lika bra första intryck). Så här enkelt är
det att skapa och ändra en sida:

    import mwclient
    
    site = mwclient.Site('www.example.org','/path/to/mediawiki/')
    site.login('myuser','secret')
    page = site.Pages['Testpage']
    page.save("Hello world", summary="initial version")
    page.save("Goodbye world", summary="updated version")
    print "Page has %d revisions" % len(page.revisions())

Allt det som mediawiki ger — revisionshantering med diffar,
användarhantering, admin- och slutanvändargränssnitt, spamkontroller,
roll- och rättighetssystem, och utökningsmöjligheter
— får man på köpet. Det är kanske inget man vill använda för att
hantera jättemånga updateringar i sekunden, men om man kan se till att
exv cachea de anrop som bara hämtar data kan man nog få det snabbt
nog.

Lagen 1.5 rycker närmare

I natt pushade jag ut en ny uppdatering av lagen.nu 1.5-betan — ta gärna en titt och säg vad ni tycker! Det är inga radikala förändringar sen sist, men lite grafisk puts med bland annat en snyggare vinjett och ett konsekvent sepiatema. För att uppmuntra feedback har även alla sidor ett formulär för felanmälan, som postar tickets rakt in i den utvecklings-trac jag använder.

Nästa steg är att skapa en epostlista för de som är intresserade av att följa, påverka och kanske delta i lagen.nu-utvecklingen. Har du varit i kontakt med mig tidigare angånde tjänsten kommer du säkert få ett mail när den är igång, hör av dig annars!

Destroy, erase, improve

Nu har det varit tyst här ett tag igen. Jag har ägnat sommaren åt
extrajobb, studier inför tentan i C4, samt jobb på nästa version av
lagen.nu, som nu börjar närma sig ”färdig”-stadiet. På ferenda.lagen.nu finns en betaversion av
siten, och de utåt sett viktigaste nyheterna är att
formgivningen är fräshare, samt att rättsfallsreferaten nu finns med i
fulltext.

Men den stora nyheten bakom kulisserna är att kodbasen till 90% är
helt omskriven, och att den nu är öppen källkod under
BSD-licensen
. Det har tagit lång tid – betydligt längre än det tog
att utveckla den ursprungliga versionen – och frågan som inställer sig
är om det verkligen var en sån lysande idé? Det finns två
förhållningssätt till att slänga gammal kod och skriva om den från
scratch — Joel säger att det är en av sakerna you
never should do
, medans Fred menar att man ska plan to throw one
away; you will, anyhow
.

De flesta utvecklares första impuls när de sitter med en kodbas som
vuxit till en ogenomtränglig röra är att slänga skiten och starta
om. Det är för det mesta en dålig idé, inte minst för att det inte
finns någon garanti för att man inte hamnar i samma sits tre år
senare, när man är klar. Men eftersom det är mycket roligare att bygga
nytt än att reparera gammalt skrivs ofta system om från scratch, trots
att det skulle varit mycket billigare att steg för steg rensa i det
gamla röriga systemet.

Så varför skrev jag då om koden? På grund av glädje och skam. Glädje,
eftersom lagen.nu inte har någon affärsplan, några inkomster ellern
några krav på företagekonomiskt rationell styrning. Det är ett
hobbyprojekt som jag sysslar med för att det är kul, och det har varit
mycket roligare att skriva nytt än att rota runt i den gamla
koden. Skam, för att det hela tiden har varit meningen att släppa
koden fri, och den gamla koden var helt enkelt för dålig för att visa
för folk. En kompis har teorin att det här är anledningen till att
inte mer kod är öppen — det är helt enkelt för pinsamt.

Beslutet att släppa koden fri, tillsammans med en viss andra
systemet-effekt
, har gjort att jag i varje steg i utvecklingen har
funderat kring det bästa sättet att göra en viss sak. För att slippa
skämmas måste man helt enkelt skriva så bra kod som man någonsin
kan. När jag skrev det första systemet var jag ganska grön på python,
och försökte mest komma på något sätt att göra samma sak. Det tar
mycket mer tid att göra rätt än att göra snabbt — särskilt i början
— men känslan av yrkesstolthet gör att det är värt det.

Det betyder inte att det inte finns en massa fulheter i koden. Jag är
inte superstrukturerad, och inte min kod heller. När jag kommit på ett
visst mönster för att göra saker överanvänder jag det gärna, fram till
att jag kommer på nästa mönster. Och namngivning samt övrig
kodstandard ska vi inte prata om. Men grunden är stabil. Arkitekturen
är ganska enkel att förklara, även om det är många (drygt 9000) rader
kod. Jag tror att en ny programmerare kan sätta sig in i det hela
ganska snabbt, och att det kan vara ett ganska kul system att vara med
och bygga på.

Dagens patch

Det blir mycket RDF i lagen.nu 1.5. Och det blir mycket användande av RDFLib. Efter att ha hittat finfina instruktioner om hur man får biblioteket – inklusive SPARQL-parser – att snurra under windows har jag gett mig på min pet peeve i n3-serialiseringskoden, nämligen dess ovana att definera egna anonyma namespaceprefix. Normalt serialiserar den nämligen n3-formatet något i stil med såhär:

@prefix _8: http://lagen.nu/.
@prefix _9: http://lagen.nu/1962:700#.
@prefix dct: http://dublincore.org/documents/dcmi-terms/.
@prefix rinfo: http://rinfo.lagrummet.se/taxo/2007/09/rinfo/pub#.

_8:NJA_2005_s_878 dct:identifier "NJA 2005 s. 878 (NJA 2005:95)";
rinfo:lagrum _9:K29P7;
rinfo:rattsfallshanvisning _8:NJA_1996_s_63,
_8:NJA_2000_s_421;

Men nu blir det det oändligt mycket mer läsbara:

@prefix dct: http://dublincore.org/documents/dcmi-terms/.
@prefix rinfo: http://rinfo.lagrummet.se/taxo/2007/09/rinfo/pub#.

 <http://lagen.nu/NJA_2005_s_878> dct:identifier "NJA 2005 s. 878 (NJA 2005:95)";
     rinfo:lagrum <http://lagen.nu/1962:700#K29P7>;
     rinfo:rattsfallshanvisning <http://lagen.nu/NJA_1996_s_63>,
         <http://lagen.nu/NJA_2000_s_421>;

Här är patchen:

C:\Users\staffan\tmp\rdflib-2.4.0\rdflib>diff -u syntax\NamespaceManager.py~ syntax\NamespaceManager.py
--- syntax\NamespaceManager.py~ 2007-04-04 22:05:32.000000000 +0200
+++ syntax\NamespaceManager.py  2008-06-14 21:36:32.606307200 +0200
@@ -59,8 +59,7 @@
namespace = URIRef(namespace)
prefix = self.store.prefix(namespace)
if prefix is None:
-                prefix = "_%s" % len(list(self.store.namespaces()))
-                self.bind(prefix, namespace)
+                raise Exception("Prefix for %s not bound" % namespace)
self.__cache[uri] = (prefix, namespace, name)
return self.__cache[uri]

Den som förstår RDFLib bättre kan säkert få till samma effekt utan att patcha källkoden genom att subklassa NamespaceManager och trycka in den i kedjan någonstans, men mina försök till det misslyckades.

Dagens bugg

Följande kod, djupt nere i innanmätet på lagen.nu 1.0-koden, har en
bugg, som stått orättad i över tre år (det den ska göra är att stoppa in ett ‘|’-tecken innan ändelser i
stil med ‘lagen’, ‘balken’, osv — dvs ‘upphovsrättslagen’ ska bli
‘upphovsrätts|lagen’ — detta av
EBNF-tekniska skäl
.

fixedindata = re.sub(r'\B(lagens?|balkens?|förordningens?)\b',
                     r'|\1', self.indata)

Hittar ni felet? Ledtråd — det uppträder bara för en av de tio
balkarna, samt för ett mycket litet fåtal lagar och förordningar.

XHTML2, CSS3 och PDF

Tidigare frågade
jag runt
vilket som var det bästa sättet att skapa PDF från nån
typ av strukturerad XML-data. De svar jag fick från olika håll pekade
på att köra det gen om en CSS3-kapabel layoutmotor vore
lämpligt. Så jag har ägnat lite tid åt att trimma in ett stylesheet
anpassat för lagtext uttryckt XHTML2 tillsammans med metadata från
ESFR-vokabulären.

Som testobjekt använde jag den
lagtext som utgör kursfordran
för förvaltningsrätt, dvs den kurs
jag läser för närvarande. Tidigare har ett förlag tryckt upp en särskild
författningssamling
för detta ämne, men på
introduktionsföreläsningen nämndes att detta inte skulle göras i år,
då kostnaden för att ta fram uppdaterade tryckorginal för varje kursstart var för stor
(kursen går två gånger om året).

Nu har jag ett automatiserat publiceringsflöde, som utgående från
en huvudfil,
uttryckt i XHTML2, och en samling lagtexter, också uttryckt i XHTML2,
genererar en sammmanslagen
fil
. Denna innehåller alla författningar (eller delar därav) som
huvudfilen hänvisar till genom XInclude/XPointer. Från den
sammanslagna filen och ett CSS3-stylesheet skapas sen en PDF. Första
steget görs med xmllint --xinclude,
andra med Prince. Kostnad för att ta fram uppdaterade tryckoriginal: i princip
noll.

Resultat:
enkelspaltig
(css),
dubbelspaltig
(css).

Några saker att lägga märke till:

  • Innehållsförteckningen har korrekta sidnummerhänvisningar
  • Sidhuvudet visar var och i vilken lag man befinner sig på (och
    växlar utseende beroende på om det är en kapitelindelad lag eller inte)
  • Huvudfilen anger vilka förkortningar som ska användas för aktuell
    lag i sidhuvudet
  • Höger- och vänstersidor ser olika ut (precis som i riktiga böcker!)
  • Avstavning sker automatiskt efter svenska regler
  • PDF-bokmärkena ger en hierarkisk översikt över hela filen
  • Det går att inkludera bara enstaka kapitel (eller andra avsnitt) från en
    lag

Det finns förstås mycket kvar att fixa (kolla exv SekrL 16 kap –
inte många rätt i formatteringen där), och även mer att skriva om hur
man kan använda CSS3 och Prince XML, men det
får bli efter julen.

Tablet PC:s, studieteknologi och PDF-byggande

Sedan någon månad tillbaka använder jag min Tablet PC som studiehjälpmedel i kursen förvaltningsrätt. Mitt huvudsakliga verktyg för antecknande är Evernote, som håller reda på en samling anteckningar i både och maskin- och handskrivet format, och organiserar dem med taggar (tyvärr dock ingen svensk handstilsigenkänning). På föreläsningar där jag är en student bland hundra använder jag datorn som en vanlig laptop och skriver på tangentbordet, men på mindre seminarier och lektioner där interaktivitet och diskussion förekommer använder jag den i tabletläge och skriver på skärmen, för att inte gömma mig bakom en uppfälld skärm.

Istället för en lagbok använder jag en PDF-fil som jag skapat med betalversionen av Adobe Acrobat, som vi har på jobbet. Den antecknar jag sedan i med PDF Annotator, både i tablet- och laptopläge, och har numera en någorlunda genomklottrad fil. Tyvärr får jag inte ta med mig datorn på tentan, så dagarna innan har jag tänkt överföra de understrykningar (men inga anteckningar)

Jag tycker det här sättet att jobba på funkar riktigt bra. Om kurslitteraturen fanns att köpa elektroniskt skulle datorn vara det enda jag behövde släpa på till och från skolan. Men det finns några problem utöver att jag måste övergå till amishteknik inför tentan, varav det största är att lagtext-PDF:en är undermålig. Det vore ju mycket bättre om lagen.nu hade nån sorts ”generera författningssamling i PDF-form”-funktion. Jag ser fyra sätt att bygga en sådan, givet källmaterial är i XHTML2 och RDFa och följande krav:

  • Automatisk avstavning som följer svenska regler
  • Kontroll över sidfötter och huvuden som automatiskt reflekterar vilken lag och vilka paragrafer som finns på varje sida (tänk
    sidhuvuden i typisk telefonkatalog eller lexikon)
  • Automatisk generering av innehållsförteckning och index
  • Fungerande interna och externa hyperlänkar i resultatet
  • Kontroll över generering av PDF-bookmarks
  • Andra saker som blir uppenbara när en lösning som saknar dem står färdig.

Jag kan se fyra sätt:

  1. Old school: Transformera XHTML2-koden till (La)TeX och låt pdftex bygga en snygg PDF
    + Snygg typografi, riktigt bra svensk avstavning
    – Jag och (La)TeX har, trots upprepade försök, inte bondat riktigt
  2. New school: Transformera XML-koden till XSL-FO och låt fop eller
    någon annan processor göra PDF av det hela
    + Standardiserat och fint
    – Jag kan inte XSL-FO. Finns det nån gratis XSL-FO -> PDF-processor
    som är bra?
  3. Bleeding edge: Skriv ett superavancerat CSS3-stylesheet, koppla
    direkt mot XHTML2-datat och koppla in en CSS3-kapabel
    PDF-genererare

    + Ingen mellantransformering
    – Jag kan inte CSS3 (och är djupt misstänksam mot tidigare
    CSS-varianter). Prince XML är svindyrt.
  4. NIH-syndromet: Använd iText eller annat lib för att generera PDF
    direkt.
    + Jag slipper bli expert på ett sidbeskrivningsspråk
    – Jag måste bli expert på ett API

Dear lazyweb: vad skulle ni välja (givet att ni inte är experter på LaTeX, XSL-FO eller CSS3)?