Jack of all trades, master of none

För att bygga lagen.nu 2.0 kommer det krävas ett rätt stort lass med teknologier. Jag har väl ungefär samlat ihop alla pusselbitar och känner mig ungefär som när man storhandlat inför en riktigt ambitiös middagsbjudning — alla råvaror och alla verktyg finns på plats, nu gäller det bara att hantera dem. Lite om vad som ingår:

XML: Lagen.nu 1.0 använde XML en hel del bakom kulisserna, men XML-formaten var odokumenterade, ad-hoc’iga och i största allmänhet inte så väldigt XMLiga (inga namespaces, data som borde varit i noder lagrades i attribut och vice versa, inget utnyttjande av befintliga standarder som RDF och XLink). Det här ska på något sätt bli bättre i 2.0 — det finns en hel del internationella projekt kring hur juridisk information ska representeras i XML, men de flesta känns som kommittéprodukter med mycket snack och lite spec — det känns som XML inbjuder till sånt, i högre grad än andra komponenter i stacken nedan. Metalex verkar dock lovande.

XSLT: För att få ut de semantiskt korrekta XML-dokumenten på webben måste de transformeras till nån sorts HTML. För 1.0 gjorde jag en del riktigt knepiga transformationer då mantrat där var ”vem behöver databaser när vi kan slänga in allt i ett gigantiskt XML-dokument och XPath()a oss fram” — för 2.0 kommer en vanlig old-school relationsdatabas att användas, så förhoppningsvis blir det bara en fråga om att ta befintliga stylesheets och trimma lite.

SOAP: Det här är väl mera på nice-to-have-listan snarare än release-blocker-listan, men det vore kul att åtminstone doppa tårna i hela webservicesträsket. Två problem är dock att jag aldrig har jobbat mot någon skarp web service från klientsidan, så jag vet inte riktigt hur ett WS-API ska kännas för att vara bra, samt att jag egentligen inte har en bra känsla för vilka rättskälleinformationsfunktioner som skulle vara vettiga att göra åtkomliga som webservices.

HTML: Allt ska ju bli HTML till slut, så viss koll på läget måste jag ju ha även här. Det blir förmodligen XHTML 1.0 Strict, en viss grad av divitis (den lösning jag skissade på här visade sig vara ohållbar när man kör den på exempelvis inkomstskattelagen och många kommentarer), och förmodligen tyvärr sämre semantisk meningsfullhet än i 1.0 (det största problemet är numrerade listor — för att sätta en kommentar bredvid en punkt i en punktlista kan jag inte representera själva punkten som en LI-tag — det går inte att placera en P-tag med kommentaren vid sidan av när man är i ett UL-kontext). Dock så ska ett flertal tabeller bort och ersättas med DL-listor, efter tipsen här.

CSS: Ärligt talat är inte 1.0 särskilt visuellt upphetsande. Det kanske inte kommer bli pastellfärger och rundade hörn, men en något mer genomtänkt visuell känsla hoppas jag kunna åstadkomma. Jag har med min nya op-center-setup möjlighet att testa på Firefox, IE, Konqueror, Opera och Safari, och ser med skräckblandad förtjusning fram emot utmaningen att få det hela att se bra ut utan att degenerera till tabellsoppa.

DHTML/AJAX: Inte bara för att det är en nödvändig beståndsdel om man vill vara web 2.0, mycket av wikifunktionaliten skulle vinna på att med lite AJAX göra det möjligt att redigera kommentarer rakt på sidan, a la flickr‘s fotobeskrivningsmagi. Och vore det inte coolt om sökrutan föreslog lagtexter a la google suggest? Jag har kollat runt på vad för hjälpramverk som finns på javascriptutvecklingsscenen (jag har läst DHTML Utopia och såg inte alls fram enmot att göra all crossbrowserkompatibilitetssörja för hand) och fastnade tillslut för MochiKit (efter att ha kollat på Dojo, Prototype/script.aculo.us, YUI och den här artikeln) — att det beskrevs som kraftigt pythoninfluerat var ett tungt vägande skäl.

EBNF: En av de bästa sakerna med lagen.nu 1.0 var den EBNF-baserade tolkningen av lagtextreferenser i löpande text. Den är, i ärlighetens namn, mest ihophackad utan någon djupare förståelse för textparsning i den högre skolan, och det känns som att jag borde ägna lite tid åt SimpleParse-dokumentationen för att hantera andra typer av referenser, nu när jag ska hantera flera typer av rättskällor.

Python: Jag hamnar ofta i fällan att när jag, när jag lärt mig ett verktyg tillräckligt bra för att få riktigt jobb gjort med det, slutar lära mig mera. Under våren har jag dock gått tillbaks till grunderna för python och försökt utnyttja mer än de få procent av språket som 1.0 använder. Det blir vettig objektorientering, bättre utnyttjande av standardbiblioteket och kanske lite riktigt funktionell programmerings-tänk (första kapitlet i TPiP är en riktig ögonöppnare här). De tre viktigaste bitarna kommer nog bli Django för allt dynamiskt, BeautifulSoup för allt HTML-tröskande (tillsammans med SimpleParse enligt ovan), och ElementTree för allt XML-byggande.

MySQL: Och så ska ju saker lagras i en databas också. Jag är som tidigare nämnts skeptisk mot RDBMS-användande, men med tanke på hur fint django abstraherar bort det hela känns det motiverat att faktiskt plocka in en databasserver i mixen. Det blir förmodligen MySQL även om alla de coola kidsen använder Postgresql, men då jag redan har en MySQL-server körandes för WordPress, MediaWiki och lite annat, har jag än så länge inte sett nån verklig anledning att byta.

Ungefär så — det blir en ganska diger lista när man kollar på den. Vilket anknyter till den här bloggpostningens titel, det kan inte bli några djupa kunskaper inom varje enskild del (särskilt som en stor komponent inte är med här, nämligen domänkunskapen om just rättsinformation) men förhoppningsvis tillräckligt för att ro det hela i land.

Allt du lärt dig om webutveckling är fel

Ett uttryckligt designmål för lagen.nu har varit att göra så mycket som möjligt med statiska filer. Det var en nödvändighet av prestandaskäl när tjänsten körde på en 166Mhz Pentium, och det är även idag en vettig målsättning, inte minst ur robusthets- och säkerhetssynpunkt.

Så länge som en webtjänst inte förändras på grundval av användarnas interaktion finns det inte någon strikt anledning att göra den med dynamisk teknik som ASP, PHP, CGI-script, servlets/JSP etc. Det kan förstås finnas utvecklingsmässiga fördelar; i princip alla nya tekniker för webutveckling utom möjligtvis XSLT är anpassat för dynamisk sidgenerering, så man når kanske sina utvecklingsmål snabbare med en dynamisk lösning. Men jag har ingen brådska på det viset.

Etiketteringen är dock den första funktionen som tar emot data från användaren, och har som sådan berett lite extra problem. Det första problemet jag hade att lösa var att jag ville att funktionen bara skulle vara tillgänglig för de som explicit ville ha den under en testperiod. I dynamiska system gör man oftast liknande saker med inloggningsförfaranden och sessionsobjekt, samt villkorlig kod som, beroende på inloggningsstatus, spottar ur sig lämplig HTML-gränssnittskod.

Men i en statisk lösning kan man inte göra sådant på servern. Däremot kan klienten åläggas att göra en hel del dynamiska trick! Lösningen fick bli att den gränssnittsdetalj som används för etiketteditering initialt gömdes med en style="display: none;", för att sedan, när sidan laddats klart, eventuellt göras synlig baserat på om kakan tags är satt till enabled med javascript i den här stilen (elementet heter ”comment” av hysteriska skäl):

    if (GetCookie('tags') == 'enabled')
    {
	if (document.getElementById('comment'))
        {
	    document.getElementById('comment').style.display="block";
         }
    }

Naturligtvis kan man inte använda en sådan här lösning om den detalj som man eventuellt vill gömma innehåller någon typ av hemlig information — det är trivialt för en angripare att kolla på HTML-koden för att hitta informationen.

Ett annat designmål med lagen.nu är att så långt som möjligt undvika att använda en traditionell RDBMS som MySQL, SQL Server, Postgres etc. Även här rör det sig om en önskan att hålla saker så enkelt som möjligt genom att undvika en separat körande process, som dessutom implementerar sin helt egen rättighetsmodell (vanligtvis), kräver sina egna backup- och synkroniseringsrutiner. En databasserver är, om man tänker efter, bara ett uppsvällt userland-filsystem med en väldigt bra ls 🙂

På lagen.nu jobbar jag framförallt med dokument – lagtexter och liknande, som är väldigt naturligt att representera som filer i ett filträd, snarare än BLOBar i en databas. Men även för datamodeller som traditionellt skulle representeras i en RDBMS har jag valt att använda filer – XML, närmare bestämt. Ett exempel är kopplingen rättsfall – lagparagrafer. Varje rättsfall kan referera noll eller flera lagparagrafer (inklusive i olika lagar), och varje lagparagraf kan naturligtvis refereras från många rättsfall. Istället för att ha en Verdicts-tabell, en LawParagraphs-dito, och sen en många-till-många-mappingtabell har jag ett stort XML-dokument med grundläggande uppgifter om alla rättsfall, ordnade efter lagar och paragrafer. Sen länkar jag in relevanta rättsfall under XSLT-transformationen, beskrivet här (under ”Accessing data in other documents”). XML-dokumentet innehåller redundant data, men eftersom det inte är den ursprungliga källan till informationen (det skapas av bara farten under den vanliga transformationen av rättsfallen) är det ok.

Den stora fördelen med detta är att mycket funktionalitet kan implementeras i XSLT istället för python eller SQL (vissa skulle ifrågasätta om det är en fördel, men jag tycker det har sin inneboende charm).

Etiketter har en liknande datamodell med en många-till-många-relation mellan etiketter och lagar, och även här är tagdatabasen en stor XML-fil (eller, än så länge är den ganska liten, men ge den tid).

För att ta emot den nya informationen måste jag tyvärr frångå mina principer om en totalt statisk sajt. Ett litet CGI-script tar emot formulärdatan, uppdaterar etikettdatabasen, och ansvarar för att fixa till HTML-filen: när en användare lägger till en etikett på en lag måste den statiska HTML-filen som utgör den formatterade lagen ändras för att inkludera den nya etikettexten.

Och här råkar vi på ett problem som inte finns i en helt statisk sajt: prestandakrav.

Sidorna på lagen.nu genereras vanligtvis (i sista steget) från XML till XHTML genom en XSLT-transformation från helvetet. Den gör mycket magiska saker, och den tar lång tid – den mest krävande lagtexten, Rättegångsbalken, tar strax under 45 sekunder. Det är inte OK om användaren måste vänta så länge för att sätta en tag. Istället opererar CGI-scriptet på den färdiggenererade HTML-filen genom att mmap’a den, söka sig fram till en markör-kommentar, och dumpar sedan in den nya taglistan.

För att tokfort hitta relevanta taggar för lagen i fråga använder jag cElementTree , och sen spottar jag ut HTML på gammalt klassiskt f.write("<a href='foo'>bar</a>")-manér.

Det är dock fortfarande långsamt att lägga till stora mängder etiketter på en lag, detta på grund av lite suboptimalitet på ett annat ställe som jag för tillfället helst sopar under mattan. Dessutom skalar det inte, men när jag får så mycket etiketter att det blir ett problem ska jag jubla.

Så, för att summera: Undvik dynamiska webutvecklingsramverk, och undvik relationsdatabaser. För att vara mer tvärtemot etablerad webutvecklingskutym skulle jag behöva programmera i assembler.

Gränssnittet för etikettering i sig är däremot en dynamisk HTML-festival i miniatyr. Imorgon ska jag berätta om min nyvunna fascination för den här utskällda webdesigngrenen.

Part 6: Transforming with XSLT

Now, after having downloaded, analysed and XML-ified the lawtext,
theres just one step left: Convert them to HTML. Enter XSLT.

XSLT is a complex beast, and I find that it’s better to approach
it as a programming language, albeit with an unusual syntax, than
a stylesheet language. I have one master stylesheet that I use for
the transformation (now over 600 lines of XSLT code), and during
devlopment I found out quite a few tricks. By the way, if you want
to see the original XML code for any law on lagen.nu, just add the
suffix ”.xml” to the url, ie http://lagen.nu/1960:729.xml.

Creating useful tooltips: An important aspect of the work
done with lagen.nu is that I’m trying to not only produce more
astethically pleasing layouts of the text, I try to
cross-reference as much as possible, to really take advantage of
the medium.

As one example: The internal references that were discussed in the
last post, should of course be transformed to ordinary hypertext
links, on the form <a href="#P26c">26 c
§</a>
, so that you quickly can jump around in the
document and follow the references. But we can do better than
that, by extracting the first 20 or so words from section 26 c,
and stick them into the title attribute of the a tag:

    <a href="#P26c" title="Ägaren till en byggnad eller ett
  bruksföremål">26 c §</a>
  

Now, if you hover with the mouse over the link (assuming you have
browser hard/software where these things are possible), the
title text will be shown as a tooltip. This makes it even
easier to make sense of a section, since you get an instant
reminder of what the referenced section says — in many cases you
don’t even have to click on the link.

So, initially, my plan was to have things like these tooltip
strings prepared in the XML document, and just do a very simple
transform into HTML. But as the work progressed, I found that I
was almost always able to do it in XSLT instead. This is the
relevant part of the link template:

<xsl:attribute name="title">
  <xsl:variable name="text">
    <xsl:choose>
	<xsl:when test="$hasChapters and $sectionOneCount = 1">
	  <xsl:value-of select="/law/chapter/section[@id=$section]/p[position() = $piece]"/>
	</xsl:when>
	<xsl:when test="$chapter != ''"><xsl:value-of select="/law/chapter[@id=$chapter]/section[@id=$section]/p[position() = $piece]"/></xsl:when>
	<xsl:otherwise><xsl:value-of select="/law/section[@id=$section]/p[position() = $piece]"/></xsl:otherwise> 
    </xsl:choose>
  </xsl:variable>
  
  <xsl:variable name="real-width">
    <xsl:call-template name="tune-width">
	<xsl:with-param name="txt" select="$text"/>
	<xsl:with-param name="width" select="160"/>
	<xsl:with-param name="def" select="160"/>
    </xsl:call-template>
  </xsl:variable>
  <xsl:value-of select="normalize-space(substring($text, 1, $real-width - 1))" />
</xsl:attribute>
  

The variables $chapter, $section, and $piece gets their values
earlier in the template, and are set to the place the link goes
to. $hasChapters and $sectionOneCount are set globally for the
document and are used to tell what kind of section numbering this
particular lawtext is using. There are three variants commonly
used:

  • No chapters, just simple ascending section numbering
  • Chapters with restarting section numbering (ie, regardless of
    the number of sections in chapter 1, the first section in chapter
    2 will be numbered ‘1 §’ — ie, we need to know the chapter as
    well as the section — just ’17 §’ is ambigious)
  • Chapters with continous section numbering (ie, if the last
    section in chapter 1 is ’16 §’, the first section of chapter 2
    will be numbered ’17 §’ — ie, the section number is never needed
    to unambigosly determine what ’17 §’ refers to).

The code constructs a XPath expression and finds the node that the
link refers to, and stores it in the variable text. Then,
it trims the string down to a suitable length (max 160 chars, in
this case) by using the user-defined
function tune-witdh
, together with normalize-space and
substring. tune-width ensures that we end the string on a word
boundary. The result of all this is assigned to the title
attribute.

Generating a TOC: Again, if you look at the swedish
copyright law, you will notice a big blue link titled ”Visa
innehållsförteckning”. Clicking on this yields (if you have a
browser that supports javascript and DOM level 1) a table of
contents (TOC), generated from chapter headings and other
headlines. It starts out as hidden, since it usually is in the
way, but sometimes it’s very useful.

The XML document in itself do not contain any TOC data. To
generate the TOC, we use a number of mode-specific templates that
extract the relevant information from headlines contained in the
document, all triggered by a <xsl:apply-templates> call:

<div id="toc" style="display:none;">
  <xsl:apply-templates select="law/chapter[(headline or section)]" mode="toc"/>
</div>

...

<xsl:template match="headline" mode="toc">
  <xsl:if test="@level = '1'">
	<div class="l1">
	  <a>
	    <xsl:attribute name="href">
	      <xsl:choose>
		<xsl:when test="substring(.,1,5) = 'AVD. '">#R<xsl:value-of select="@id"/></xsl:when>
		<xsl:when test="../../chapter">#K<xsl:value-of select="../@id"/></xsl:when>
		<xsl:otherwise>#R<xsl:value-of select="@id"/></xsl:otherwise>
	      </xsl:choose>
	    </xsl:attribute>
	    <xsl:value-of select="."/>
	  </a>
	</div>
  </xsl:if>
  <xsl:if test="@level = '2'">
	<div class="l2">
	  <a href="#R{@id}"><xsl:value-of select="."/></a>
	</div>
  </xsl:if>
</xsl:template>
<xsl:template match="section" mode="toc"/>

<xsl:template match="changes" mode="toc"/>
<xsl:template match="appendix" mode="toc"/>
<xsl:template match="preamble" mode="toc"/>
  

Things to note: The text-to-XML conversion is responsible for
determining the ‘level’ of the headlines. Level 1 headlines are
usually associated with a chapter (though not always), and we use
some tests to determine if that is the case. If so, the resulting
link uses a ”#K<number>” anchor fragment, otherwise a
”#R<number>” fragment. ”K” is for ”kapitel” (chapter), while
”R” is for ”rubrik” (headline). Not strictly neccesary, but I
prefer a link that explicitly says ”this link goes to chapter 4”,
rather than ”this link goes to the 14th headline”, particularly as
the number of headlines can change in the future, which would make
the link point to the wrong place.

I have a number of ”empty” templates. They are needed, since if I
don’t have them, the base template kicks in and just copies the
entire text, which seriously messes up the TOC. Now, I should be
able to limit that with the select attribute of the
<xsl:apply-templates> tag, but I have been unsuccesful (the
reason I select both headlines AND sections, then do nothing with
the sections, is that I’ve been experimenting with using the first
lines of each section in the TOC as well, but that came out too
messy).

Accessing data in other documents: To properly understand a
section in a law, it helps to read court verdicts that reference
it. In part 2, I described how to fetch data from Domstolsväsendets
rättsinformation
, which has this data. Basically, I have a
python code snipped that goes through all 1800+ verdicts, uses the
parser that was mentioned in part 5 to find references
to laws and
sections therein, and then generates a ”cache.xml” file, that
contains references to all verdicts, sorted by law, chapter and
section, like this:

<?xml version="1.0" encoding="iso-8859-1"?>
<verdicts>
<law id="1736:0123_2">
<chapter id="9">
  <section id="5">
    <verdictref caseid="NJA 2002 s. 577 (alt. NJA 2002:70)" casenumber="T3933-01" id="2002/758" verdictdate="2002-11-22">
      Gäldenär, som hade flera skulder till en borgenär, har ansetts ha rätt att destinera sin be
    </verdictref>
  </section>
</chapter>
<chapter id="10">
  <section id="1">
    <verdictref caseid="NJA 2000 s. 667 (alt. NJA 2000:97)" casenumber="T4689-98" id="2000/772" verdictdate="2000-12-18">
      Sedan A och B var för sig ställt pantsäkerhet för C:s lån i en bank, har banken gjort sig f
    </verdictref>
    <verdictref caseid="NJA 2000 s. 88 (alt. NJA 2000:13)" casenumber="Ö3863-98" id="2000/923" verdictdate="2000-02-23">
      Ett bolags upplåtelse av företagshypotek har ansetts bli sakrättsligt gällande när företags
    </verdictref>
  </section>
  [...]
  

In the top level of the stylesheet, I select the relevant nodeset
from this cache document, and store it in a variable. To be able
to select, I first need to know the id of the law (the
‘SFS-nummer’), and so I pass it as a command line parameter:

<xsl:param name="lawid"/>
<xsl:variable name="relevantVerdicts"
  select="document('generated/verdict-xml/cache.xml')//law[@id=$lawid]"/>
  

Then, as I process each section, I check the nodeset to see if
there’s any verdicts relevant to the section:

<xsl:variable name="sectionChapterVerdicts" select="$relevantVerdicts//chapter[@id=$chapterid]/section[@id=$sectionid]/verdictref"/>
<xsl:if test="$sectionChapterVerdicts">
<div class="metadata">
<xsl:for-each select="$sectionChapterVerdicts">
  <xsl:variable name="linktext">
    <xsl:choose>
      <xsl:when test="@caseid"><xsl:value-of select="@caseid"/></xsl:when>
      <xsl:when test="@casenumber">Målnummer <xsl:value-of select="@casenumber"/></xsl:when>
      <xsl:when test="@diaryid">Diarienummer <xsl:value-of select="@diaryid"/></xsl:when>
      <xsl:otherwise>Vägledande dom</xsl:otherwise>
    </xsl:choose>
  </xsl:variable>    
  <xsl:variable name="real-width">
    <xsl:call-template name="tune-width">
      <xsl:with-param name="txt" select="."/>
      <xsl:with-param name="width" select="80"/>
      <xsl:with-param name="def" select="80"/>
    </xsl:call-template>
  </xsl:variable>
  <a href="/dom/{@id}"><xsl:value-of select="$linktext"/></a>: <xsl:value-of select="normalize-space(substring(., 1, $real-width - 1))" />... (<xsl:value-of select="@verdictdate"/>)<br/>
</xsl:for-each>
</div>
</xsl:if>
  

Again, a little extra work is done to make sure the explaining
text is cut at a word boundary (we could‘ve done that in
the python code that generates cache.xml), and also that the text
for the actual link makes sense. You see, different courts have
different systems for assigning ID’s to cases: HD (the swedish
supreme court) uses the page number as the case is published in
that year’s anthology of relevant verdicts (Nytt Juridiskt Arkiv,
NJA), other uses a court-specific identifier, and some use a
derivative of the date when it was handled. Since these
identifiers represent different things, they are also represented
with different attributes in the XML file, and a little
<xsl:choose> trickery selects the most appropriate ID.

Optimization hints: Some of the law texts are quite big, and
processing them can take a long time. To speed things up, here are
some of the things I did:

  • Don’t use the python interface to libxsl! I started out with
    this, but it turned out to take twice or even three times as long
    for a transformation, as compared to running command-line xsltproc (win32 binaries)
    through an os.system() call.
  • Use the –profile switch to xsltproc. It’s pointless to
    optimize if you don’t know where the bottlenecks are, and with
    xsltproc it’s so easy to find them.
  • Store frequently-referenced nodes, nodesets and values in
    variables, instead of selecting them through XPath queries all the
    time. Yeah, this one is kind of obvious, but it really helps,
    particularly in those ”inner” templates that are used all the
    time.

Just by using the above tips, the transformation of my standard
test case (1960:729) went
from 90 seconds to three. Still, I have other test cases that
still takes several minutes, so clearly there’s still some work to
do…

Part 4: Converting stuff to XML

(If you missed part 1-3, they are here,
here
and here)

If you look at a sample law text as they are presented in SFST,
they are 100% plaintext. In order to convert them to semantically
sensible XML, we must look for patterns in the plaintext, to
identify things like headlines, start of sections and references.

I did this with a two-part approach. First; I break down the text
into it’s individual paragraphs and determine what each paragraph
is. This analysis operate on a ‘block level’ — either a block of
text is a headline, part of an ordered list, the start of a
section etc, or it isn’t. A block can’t be half headline and half
ordered list.

Secondly, if the paragraph can contain references to other parts
of the law (or parts of other laws, for that matter), I analyze
the text in greater detail to find and resolve these
references. This step operates on a ‘token’ or character level —
a block of text can contain zero, one or many of these references.

The first part is fairly easy, at least conceptually. I wrote a
bunch of functions like is_chapter(p),
is_section(p), is_headline(p), where each
individual function just performs a simple test. These are then
used from a simple loop that uses a bunch of local variables to
keep track of what kind of structures we’ve encountered so far —
a so-called state machine.

These functions started out as very simple regexp-based inline
expressions, but as I encountered more and more exceptions to my
simple rules, their complexity grew. The body of current swedish
law is over 250 years old, and consistency has not been the law
makers forte. Here’s an example of how to recognize the
start of a section:

    re_SectionId       = re.compile(r'^(\d+ ?\w?) §[ \.]') # used for both match+sub
    re_SectionIdOld    = re.compile(r'^§ (\d+ ?\w?).')     # as used in eg 1810:0926

    def is_section(self,p):
        section_id = self.section_id(p)
        if section_id == None:
            return False
        if section_id == '1':
            if self.verbose: print "is_section: The section numbering's restarting"
            return True
        # now, if this sectionid is less than last section id, the
        # section is probably just a reference and not really the
        # start of a new section. One example of that is
        # /1991:1469#K1P7S1. We use util.numsort to get section id's
        # like "26 g" correct.
        a = [self.current_section,section_id]
        
        if a == util.numsort(a):
            # ok, the sort order's still the same, which means the potential new section has a larger ID
            if self.verbose: print "is_section: '%s' looks like the start of the section, and it probably is (%s < %s)" % (
                p[:30], self.current_section, section_id)
            return True
        else:
            if self.verbose: print "is_section: Even though '%s' looks like the start of the section, the numbering's wrong (%s > %s)" % (
                p[:30], self.current_section, section_id)
            return False
    
    def section_id(self,p):
        match = self.re_SectionId.match(p)
        if match:
            return match.group(1).replace(" ","")
        else:
            match = self.re_SectionIdOld.match(p)
            if match:
                return match.group(1).replace(" ","")
            else:
                return None
  

So, the start of a section looks like ‘<number> [letter] §’,
unless it looks like ‘§ <number> [letter]’, and as long as
the section id is larger than the previous section id, unless it’s
restarting at 1, and also taking into account that section ids can
contain an optional letter (like ’26 g’). Simple as that.

For example, below is the start of the swedish copyright law
(which has, during development, been my foremost test case). Now,
if you don’t read Swedish, just know that the first paragraph
signifies the start of chapter one (”1 Kap.”), the second the
start of a section(”1 §”), and then there are three items in an
ordered list, and finally a plain ol’ paragraph of text. (By the
way, for my swedish readers: The swedish legal term ‘paragraf’ is
NOT the same as the english typographical term ‘paragraph’, but
rather translates into ‘section’. When the english word
‘paragraph’ is used, it is in the same sense as the swedish word
‘stycke’)

1 Kap. Upphovsrättens föremål och innehåll

1 § Den som har skapat ett litterärt eller konstnärligt verk har
upphovsrätt till verket oavsett om det är

1. skönlitterär eller beskrivande framställning i skrift eller tal,

2. datorprogram,

[...other items in the ordered list omitted for brevity...]

Till litterära verk hänförs kartor, samt även andra i teckning eller
grafik eller i plastisk form utförda verk av beskrivande art.

[...more things omitted for brevity...]

2 § Upphovsrätt innefattar, med de inskränkningar som nedan stadgas,
uteslutande rätt att förfoga över verket genom att framställa exemplar
därav och genom att göra det tillgängligt för allmänheten, i
ursprungligt eller ändrat skick, i översättning eller bearbetning, i
annan litteratur- eller konstart eller i annan teknik.
  

So, to make sense of this, the following state transitions are done:

  • For the first paragraph, is_chapter() will return True,
    so we transition to the in_chapter state. This will emit a
    <chapter id="1"> tag to the result, along with
    the text.
  • For the second paragraph, is_section() will return
    True, transitioning us to the in_section stage as
    well. It’s important to realize that these states are mostly
    independent; we can be in a chapter w/o being in a section, and
    vice versa (some laws have only sections, no chapters). This
    transition will of course emit a a <chapter id="1"> tag
    to the result.
  • For the third paragraph, is_ordered_list() will return
    True, transitioning us to the in_ordered_list state, and
    emitting <ol><li>1. skönlitterär eller
    [...]</li>
    to the result. A couple of things to
    note about this:

    • These tags may look like HTML tags, but they’re not. They do, in
      this case, share the same semantics, though.
    • A HTML ordered list (<ol>) keeps track of
      it’s numbering, and any user-agent should add the numbers to
      the displayed result. Since this is not HTML, we don’t do
      that, and instead keep the number that was in the original
      text. Mostly because we’re not sure that no ordered list in
      the entire body of swedish law doesn’t contain sequence gaps
      or things like ’26 g’.
  • For the fourth, is_ordered_list() will again return
    true, but now we’re already in the in_ordered_list
    state, so we don’t emit the initial <ol> tag.
  • Then we omit some boring junk, and then we encounter a normal
    paragraph. There is no function named
    is_ordinary_paragraph(), this is just infered from the
    fact that none of our other test matched. Now, the start of a
    normal paragraph is implicit evidence that our ordered list must
    have ended, and so the code to transition into
    in_normal_paragraph state checks to see if we’re in the
    in_ordered_list state, and if so, emits the trailing
    </ol>. After that, the normal paragraph gets
    emitted as <p>Till litterära verk [...]</p>.
  • Similarly, when we encounter the start of a new section (”2
    § Upphovsrätt innefattar
    ”), we transition out of any
    ordered lists we might be in, out of the in_section state, emit
    </section>, and then transition into the same state
    again.

The largest part of this high-level parsing was to find all the
different structures and discover the implicit state transitions
that needed to take place. One interesting problem is determining
wheter a given paragraph is a headline or just a really short
ordinary paragraph. Well, it turns out that a headline never ends
with a period, and a ordinary paragraph always does. Except for
headlines that end in ”m.m.” (swedish for ”etc.”). And ordinary
paragraph that end with ”,”, ”och” or ”samt”. But a headline is
always followed by a section, so we can peek ahead to see if the
next paragraph matches is_section(). Except for those cases where
a headline is followed by ANOTHER headline, which is then followed
by a section…

A lot of work, and there are still a lot of places
where we break (for example, things like definition lists, nested
ordered lists, and tables, are not yet supported). Furthermore,
tweaking to satisfy one case can easily make other cases break. I
will return to this problem in the part about regression testing.

Some other things: As you may have guessed by the usage of the
term ”emit”, I construct the XML by hand in a single pass. This
means that I write XML data straight to a file, without using DOM
or anything similar. It was just easier to start out that way. I
am thinking of overhauling the state machine mechanism a bit, and
I might take a DOM approach then.

Some other parts of the code that constructs XML documents (like
the code that handle court verdicts) use DOM, and it works pretty
fine, with one small exception: It does not play nice with xml
fragments in string form. I have a separate class to find law
references in text (to be covered in deeper detail in the next
post), and the interface of that class is a plain string one: it
returns strings like ”<link law="1960:644" piece="2"
section="1">1 § 2 st.</link> varumärkeslagen
”. Since
there isn’t any method on individual element objects like
ele.ParseAndAppendMixedContent(), I first have to create
a ‘fake’ XML document and transform it into a node tree with
parseString (from minidom):

    s = '<?xml version="1.0" encoding="iso-8859-1"?><%s>%s</%s>' % (
                        element, string_containing_mixed_xml_content, element)
    fragment = parseString(s)
    subele = fragment.documentElement
    ele.appendChild(subele)
  

Another drawback of writing XML the raw way is that there is no
guarantee that your output will be valid. Special care is taken to
escape things like < and &, and to ensure the document is
well-formed, it’s also run through HTML Tidy (with the
options -q -n -xml --indent auto --char-encoding latin1),
which, despite it’s name, is an excellent tool to tidy up XML as
well.

Legal document standards, part 2

Rasmus blogs
about
open standards and open access for law texts, a topic of
great interest to me as of lately (or ‘obsession’, apparently :-). We
both agree that there are too little of that, and that the
much-heralded open governement could do better in this area.

Anyway, I came across an interesting
report
, a summary from a conference held about two years ago. It
featured various people working with legal information systems, both
in the government and private companies, sharing their views on
standardisation of document formats and systems. There are views from
the people behind Rixlex, Infodata and Notisum, amongst others, but
also an interesting view into the state of legal information standards
in Norway. They seem to be way ahead of Sweden in this area.

The general consensus seemed to be ”standardization is good, and we
should do it”, but with no real commitments or timeplans. Maybe there
has been developments that I don’t know about since then. This was,
after all, two years ago.

Meanwhile, if you want to do interesting stuff today with
the body of swedish law, such as making a WAP version or performing
graph analysis of all references contained in the 7500+ texts, just download my completely
non-{standardized,documented} XML version
and go nuts!

There are now at least three document standards, or efforts to
create such, for marking up law texts and other legal doucments on my
radar: uscfrag
(mentioned earlier), used
by Cornell University for marking up US Code, LegalXML which seems to be
US-centric, and LEXML, which
appears to be more EU-centric. It even has it’s own Sourceforge page!

I had no idea so much was going on in so many committees when I
started working on the XMLization of swedish law. In a way I’m glad
that I didn’t, since I probably would have focused too much on
adhereing to these emerging standards and less time to, you know,
getting things done. Or worse, just waited for them to actually finish.

The US Code in XML

From this
groklaw post
, I learned that Cornell University has transformed the
entire US Code to XML
. Now, I’m not well versed in US Law, but
this is basically all federal laws currently in effect in USA, right?
This is a very cool project. I’ve started to look around, but
seemingly as I only barely can navigate around in swedish law texts,
there’s a lot of exploring to be done. If you want to just read
the laws, this
seems to be a good place to start.

(By the way, could any US law scholar tell me whether the US
constitution is a part of USC, or if it’s a separate collection of
documents? I cannot seem to find them, only references to it.)

As I’ve been working
on a project with similar goals for the
last few months, I’m particularly interested in the XML format
looks. I’ve only started to scratch the surface, but initially it
seems to be somewhat more presentation-oriented (and way more complex)
than the simple structures I use.

Maybe this format could be used anyway, or at least a XSLT
transformation to transfer from Lagen.nu-ML (not yet documented) to uscfrag.