AKN → Korean model roundtrip
kr2akn is bidirectional for the fields that affect AKN output:
raw eflaw / precedent XML
│ kr2akn emit / emit-case
▼
AKN XML
│ kr2akn akn2kr
▼
kr2akn.raw-law.v1 / kr2akn.raw-case.v1
│ kr2akn emit / emit-case
▼
AKN XML (canonically identical)
The guarantee is canonical equality, not byte equality: the second AKN document is compared after XML canonicalization, so formatting and namespace prefixes do not matter.
CLI
# AKN act → raw-law model JSON
kr2akn akn2kr --input ../data/akn/001706.akn.xml --output /tmp/001706.model.json
# AKN judgment → raw-case model JSON
kr2akn akn2kr --input ../data/akn/prec/624945.akn.xml --output /tmp/624945.model.json
# Re-emit directly from a decoded model
kr2akn emit --model /tmp/001706.model.json --data-dir ../data --validate
kr2akn emit-case --model /tmp/624945.model.json --data-dir ../data --validate
# emit → decode → emit for every law and case under data/raw
kr2akn roundtrip --all --data-dir ../data
# also compare the decoded model field by field with the parsed model
kr2akn roundtrip --all --data-dir ../data --strict-model
# preserve the original source blobs for exact model recovery
kr2akn emit --all --data-dir ../data --preserve-source-text
kr2akn roundtrip --all --data-dir ../data --strict-model --preserve-source-text
# one law / one case
kr2akn roundtrip --law-id 001706 --data-dir ../data
kr2akn roundtrip --case-id 624945 --target prec --data-dir ../data
roundtrip exits 0 only when every document is canonically identical and
prints the first structural difference (element path and attribute/text) when
one is not.
--strict-model additionally compares the decoded model with the parsed model
field by field. It ignores raw ingestion maps and trailing whitespace on
structured text. Without --preserve-source-text, source blobs such as
Bylaw.text and judgment full_text may differ because the emitter stores the
structured form. With --preserve-source-text, those blobs are written to
kr:sourceTexts / kr:sourceText and the strict model check passes exactly.
What the decoder reconstructs
Statutes
- FRBR identity: law ID, name, type, ministry, promulgation/effective dates, language, short/English/Hanja titles.
kr:lawMetaprovenance: law key, type code, ministry code, promulgation number, revision type, source URL, raw path/SHA-256, fetch time.- Departments, contact department, and
extrafields. - The full unit hierarchy (
part…indent) witheId,num,heading, text, inline citation anchors, and authorial notes. - Per-unit effective dates through
periodandkr:effectiveDate, plus optional end dates throughtimeInterval endandkr:effectiveEndDate. - Bylaws as
hcontainer name="부칙"with preamble and article units, and amendment-scoped inline citations regenerated from the paragraph text. - Annexes as
attachment/doc/mainBody, including paragraph lines and tables withrowspan/colspan. - 개정문 / 제개정이유 components.
Judgments
kr:caseMeta: case ID, case number, name, court, decision date/type, case type, target, source, and raw provenance.- The packed 43-bit header from
kr:caseHeader, including overflow flags. judgmentBodysections, headings, and paragraph text (deliberate spacing is preserved; full-text whitespace is not collapsed).referenceswith case number, court, decision date/kind, law name, and article chain.
kr: provenance
AKN's core attribute group permits foreign-namespace attributes, so Korean
fields that have no AKN equivalent travel on the element they describe:
<article eId="art_1" period="#period_20260701"
kr:revisionType="일부개정"
kr:effectiveDate="2026-01-01">
<hcontainer name="부칙" eId="hcontainer_buchik_1"
kr:key="..." kr:promulgationDate="2026-01-01"
kr:promulgationNo="00001">
<jurisprudence href="/akn/kr/judgment/456" showAs="대법원 2024다2 판결"
eId="ref_1" kr:caseNo="2024다2" kr:court="대법원"/>
These attributes are optional: akn2kr also accepts third-party AKN and falls
back to FRBR metadata, classification keywords, and showAs parsing.
Annex tables
kr2akn.statute.table parses box-drawing tables into rows and merged cells.
It accepts both heavy (┏ ┳ ┓ ┠ ╋ ┨ ┗ ┷ ┛) and light (┌ ┬ ┐ ├ ┼ ┤ └ ┴ ┘)
box-drawing characters. kr2akn.akn2kr.table renders the inverse geometry:
- a cell's full text is placed in its first column, so the parser never splits
a word across a
colspanboundary; - a missing horizontal segment becomes a
rowspan; - column widths are at least three display columns, the parser's minimum.
Three geometry details matter for real eflaw annexes:
- Display width. Korean glyphs occupy two display columns while the borders are drawn in display columns too. Lines whose codepoint lengths are inconsistent are parsed in expanded display coordinates; codepoint-aligned tables (including the synthetic fixtures) keep the original coordinates.
- Partial separators and wrapped cells. A header can subdivide only some
of its columns (
├───┼───┼───┬───┬───┤). The parser uses the widest full grid and maps the header's wider cells tocolspan. Lines with no horizontal rule before them are treated as wrapped continuations of the previous row, unless every column carries new text (dense tables such as coefficient tables). - Multi-row and full-width rowspans. A rowspan cell stays in the parser's grid for every row it covers, so spans longer than two rows extend correctly. A rowspan that covers every column has no horizontal segment to anchor the merge; the renderer omits that separator. The parser now counts an empty full-width continuation line as another row of the same cell, recovering the span while keeping the text in the first visual row.
The real merged-table corpus includes 003793 (산업재해보상보험법 시행령) and
an excerpt of the public 위험물안전관리법 시행령 [별표 1] table
(tests/fixtures/merged_annex_table_2.txt). The latter exercises a ten-row
rowspan and a nested colspan header.
A full-width rowspan whose text wraps over every covered row still cannot be distinguished from a multi-line cell. The text survives; only the exact span may be flattened.
Amendment-scoped citations
Bylaws and amendment documents are no longer emitted as plain text only. A
bare 제N조 inside a 부칙 or 개정문 is not resolved against the
consolidated main-law index, because it usually refers to the amended law or
to the amending instrument. Instead it becomes an amendment-scoped reference:
<ref href="urn:kr:amendment:001697:10580:hcontainer_buchik_1:%EC%A0%9C3%EC%A1%B0%EC%A0%9C7%ED%98%B8"
kr:refType="amendment">제3조제7호</ref>
urn:kr:amendment:{law_id}:{promulgation_no}identifies the instrument. A bylaw adds itseIdso repeated bylaws stay distinguishable.- The cited article chain is percent-encoded in the final segment.
이 부칙 제N조/같은 부칙 제N조resolves to the bylaw's own article#eIdwhen that article exists.이 법/같은 법still resolves to the main law, because it names the amended law rather than an article inside the amendment.kr:refType="amendment"is the only new attribute; ordinary main-lawrefelements are unchanged.
The decoder reads the paragraph text back with the inline ref text, so the
same references are regenerated deterministically on re-emission.
Temporal intervals
timeInterval now supports an end date. The reader accepts
시행종료일자, 효력종료일자, 폐지일자, 폐지일, or 종료일자 at the law
level and 조문시행종료일자, 조문효력종료일자, or 조문폐지일자 on a unit.
The current eflaw corpus has no such fields, so all existing intervals remain
open-ended.
When an end date is present:
meta/lifecyclegets aneventRef type="repeal"for the end date;- the
temporalGroupid becomesperiod_{start}_{end}; timeIntervalcarries bothstartandend;- the unit keeps
kr:effectiveEndDatefor lossless decoding.
Scope and limitations
The roundtrip covers document content and identifiers, not the raw ingestion bookkeeping:
Unit.raw,Bylaw.raw, andAnnex.rawfield maps are not emitted, so they are absent from decoded models. They remain inparseoutput.source_keyis preserved only when present (it is empty in the current corpus).revision_type,changed, andmoved_from/moved_toare carried askr:attributes.- Bylaw
textis re-rendered from preamble and article units by default. With--preserve-source-text, the original blob is stored inkr:sourceTextsand restored exactly. issues,summary, andfull_textare reconstructed from judgment sections by default. With--preserve-source-text, the original fields are stored inkr:sourceTextand restored exactly. The emitter only usessections.
Validation status (2026-10-29)
pytest: 64 passed.- Laws: 11/11 AKN valid, 11/11 in-memory roundtrip, 11/11 strict-model
roundtrip with
--preserve-source-text. - Cases: 4/4 AKN valid, 4/4 in-memory roundtrip, 4/4 strict-model roundtrip
with
--preserve-source-text(prec2,detc2). - The 11th law (
003793, 산업재해보상보험법 시행령) adds real merged and nested-header annex tables to the corpus. - The public 위험물안전관리법 시행령 [별표 1] excerpt adds a ten-row rowspan fixture.