Parsing a Law Is Not Parsing Text
AUG 18, 2026
A technical design for transforming legislative Markdown into a structured, versionable representation: contextual lexing, an Abstract Law Tree, projection to Akoma Ntoso, and consolidation operations.

Processing legislation is not about extracting words from a PDF or rendering Markdown in an interface. It is about recognizing that the document has a grammar, a hierarchy, and a history of changes.
The resulting pipeline separates responsibilities. If you want the path that led to this design — rather than only the outcome — the first two posts tell that story.
Part 1: the origin
“Useless” Projects Are Never Completely Useless
A compiler course and a small Spanish-language educational programming language seemed unrelated to law. Years later, they provided the mental model needed to start interpreting legislation.
Part 2: the research
Finding the Name of the Problem
The parser could already build an Abstract Law Tree. The real challenge came next: partial amendments, identity, temporality, and consolidation. Research changed once the problem found its vocabulary.
Legislative Markdown
↓
Legislative lexer
↓
Tokens
↓
Parser
↓
ALT
↓
Projection
↓
Akoma Ntoso XML
↓
Consolidation operations
That separation matters. Each stage turns a different kind of uncertainty into a more explicit structure.
The input is not free-form text
Consider this reduced document:
# TITLE ONE
## CHAPTER I
Article 1. Text of the article.
I. First item.
II. Second item.
a) First sub-item.
For a human reader, the hierarchy is immediate. For a machine, the same characters may be a heading, an article, a numbered item, or an ordinary sentence. The first problem is classifying fragments without confusing their form with their meaning.
A legislative lexer is contextual
In a programming language, many tokens can be recognized from small symbols:
if (x == 10)
In legislation, delimiters are often expressions, entire lines, or the combination of several lines:
Article 254.- For the purposes of...
TITLE ONE
GENERAL PROVISIONS
I. ...
a) ...
A legislative lexer therefore looks less like a character tokenizer and more like a lightweight parser. It can emit tokens such as:
TITLE("ONE")
CHAPTER("I")
ARTICLE("1")
PARAGRAPH(...)
POINT("I")
POINT("II")
INDENT("a")
To do that, however, it must account for numbering, capitalization, text patterns, position, formatting, the preceding line, and sometimes already-recognized context. An isolated I. does not necessarily mean the same thing as an I. that follows an article.
From token stream to ALT
The parser receives each token and decides where it belongs in the tree. It does not simply append it to the last node: it evaluates the current type, previous type, hierarchy level, indentation, ancestors, and rules particular to the legislation being processed.
The result can look like this:
Law
└── Title One
└── Chapter I
└── Article 1
├── Paragraph 1
├── Item I
└── Item II
└── Sub-item a)
This Abstract Law Tree works very well when the input is a complete version:
Complete Markdown → complete ALT
It also has a clean responsibility: represent what the parser understood correctly, without forcing the parser to know about persistence, temporality, or the target interoperability standard.
The case that breaks symmetry: amendments
An amendment rarely reproduces an entire article, chapter, or law. It may contain conceptual markers such as “...”, meaning: this exists, but is not reproduced here because it did not change.
Article 3. ...
I, II and III. ...
IV. New text.
The ALT for a base law and the ALT for an amendment are not two complete states that can be compared with a conventional diff. The amendment is a partial description of change with implicit context.
Trying to solve that with graphs alone leads to costly and brittle tasks: traversal, subgraph search, partial equivalence, structural matching, and incomplete-reference resolution. If ALT became the canonical model, it would also require a serializer, query engine, identifiers, diffs, patches, versioning, references, a temporal model, and tooling.
The parser stops being the project. The project becomes an entire ecosystem around a proprietary structure.
ALT as an intermediate representation
The answer is not to discard ALT or generate Akoma Ntoso directly from the lexer. Doing so would waste a useful abstraction and mix syntactic recognition with interoperability details.
The architecture becomes:
legislation
↓
parser
↓
ALT (domain IR)
↓
AKN projection
↓
XML document and subsequent operations
It is the same pattern used by compilers:
source code → AST / IR → target representation
ALT is an IR: it preserves a representation convenient for the parser. Akoma Ntoso becomes the structured representation that can leverage XML validation, XPath, XSLT, schemas, metadata, and standard references.
Stable identity before traversal
A legislative operation needs to address its target precisely. “Sub-item b of item III of article 254” should not require traversing the entire tree every time.
A structured identifier can express that destination directly:
art_254__item_III__sub_b
This is more than naming. Stable identifiers turn a navigation problem into an addressable operation:
find node: art_254__item_III__sub_b
With them, an amendment can be decomposed into atomic changes:
replace(target, content)
insert_after(target, content)
delete(target)
renumber(scope)
Consolidation means applying operations
The decisive conceptual change is to stop thinking in terms of:
complete tree vs. partial tree
and instead think in terms of:
base state
+
modification operations
=
new state
Consolidation looks more like applying a patch than calculating a diff between two complete documents. Akoma Ntoso does not provide a finished application, but it does provide a domain model and vocabulary for representing documents and modifications without designing all of those concepts from scratch.
That distinction matters:
no library ≠ no prior knowledge
implementing from scratch ≠ designing from scratch
The result is neither a magical parser nor a fully automatic task. Ambiguous cases remain — for example, an amendment that repeals an introductory paragraph before a list of numbered items — and they need human review. But the architecture reduces ambiguity to concrete, auditable decisions.
Parsing a law, then, is not parsing text. It is building a representation that preserves structure, identity, and time — expressive enough for a partial modification to become a new consolidated version.
And, somewhat ironically, it all starts with a Codexivo series that was left waiting for its parser article. The experiment still lives in its repository; in a sense, the legislative parser is that conversation resumed years later.