A specification nobody can read is just a document. These are the reference implementations: they turn AODM into data your program already knows how to handle, and they check every rule in the specification while doing it.
All of it is Apache 2.0 licensed and ships in the download package. No dependencies in any language — each implementation uses only its standard library.
Reference parsers
A parser reads AODM’s XML form and hands back the JSON model defined by
aodm-core-1.2.schema.json. Both are AODM: the specification
defines two serialisations of one model, and the parsers convert between
them in either direction.
| Language | File | Requires |
|---|---|---|
| Python | parsers/python/aodm.py | Python 3.8+, standard library |
| JavaScript | parsers/javascript/aodm.js | Node 18+ or any browser |
| Java | parsers/java/Aodm.java | JDK 11+, standard library |
| C# | parsers/csharp/Aodm.cs | .NET 6+, base class library |
Python
from aodm import parse_file
doc = parse_file("knowledge.xml")
doc.facts # list of facts
doc.by_id("engine") # look up any element
doc.to_json() # JSON matching the published schema
doc.to_xml() # back to AODM XML
doc.is_valid() # False if any MUST-level rule is broken
for issue in doc.validate():
print(issue) # ERROR R1: The object "ghost" does not match…
JavaScript
const { parse } = require('./aodm');
const doc = parse(xmlString);
doc.facts; doc.byId('engine');
doc.toJSON(); doc.toXml();
doc.isValid(); doc.validate();
In a browser, load it with a <script> tag and use
AODMParser.parse(…). It uses the browser’s own XML parser
where available and falls back to a built-in reader under Node, so there is
no dependency either way.
Java
Aodm.Document doc = Aodm.parseFile("knowledge.xml");
doc.facts(); doc.byId("engine");
doc.toJson(); doc.toXml();
doc.isValid(); doc.validate();
C#
var doc = Aodm.ParseFile("knowledge.xml");
doc.Facts; doc.ById("engine");
doc.ToJson(); doc.ToXml();
doc.IsValid(); doc.Validate();
Each also runs from the command line:
python3 aodm.py knowledge.xml # print the JSON model
python3 aodm.py --validate knowledge.xml # report rule violations
What the parsers check
Validation is not an optional extra bolted on afterwards — every parser
enforces the full rule set from VALIDATION-RULES.md, including
the constraints that no schema language can express:
referential integrity, derivation cycles, duplicate ids, cardinality,
measurement coherence, temporal ordering, polarity handling and digest
format. Errors are MUST-level violations; warnings are SHOULD-level.
Why four implementations rather than one. Beyond covering more stacks, independent implementations are how a specification gets tested. If two of them disagreed about the same document, the fault would be in the specification, not the code. A conformance suite runs all four over the same inputs and requires identical output — currently 18 rule cases across four languages, alongside 21 schema checks, 24 XBRL constructs and 33 graph and reasoning checks.
Converters
Most organisations already hold structured data in a standard format. A converter turns that into AODM without re-authoring anything, which is usually the difference between adopting a format and reading about it.
XBRL
XBRL is mandatory for financial reporting to the SEC, ESMA, HMRC and most other regulators, so essentially every listed company already produces it. The converter implements the whole of the XBRL 2.1 instance document syntax.
python3 xbrl_to_aodm.py instance.xml # AODM JSON
python3 xbrl_to_aodm.py instance.xml --xml # AODM XML
python3 xbrl_to_aodm.py instance.xml --validate
| XBRL | Becomes |
|---|---|
| Reporting entity identifier | entity type="reporting-entity" |
| Reported fact | fact, statement = element name |
| Numeric content + unit | value/@number + @unit |
| Divided unit (USD/share) | @unit="USD/shares" |
| Fraction | @number, numerator ÷ denominator |
| Duration period | valid-from / valid-to |
| Instant period | valid-from = valid-to |
| Forever period | no temporal bounds |
@decimals / @precision | value/@tolerance |
| Explicit & typed dimensions | relationship to a member entity |
| Tuples, nested | entity type="fact-group" + composition |
| Footnotes | appended to the fact statement |
A stated accuracy of decimals="-6" means the figure is rounded
to millions, so the real value sits within half a million either way. That
becomes an AODM tolerance rather than being discarded — which is the
whole point: the precision of a reported number is information, and most
pipelines throw it away.
Scope, stated precisely. This covers the XBRL 2.1 instance document syntax completely. It does not interpret the taxonomy — linkbases, label resolution and calculation trees live in separate files an instance only references, and resolving them is a different problem. Element names therefore appear verbatim rather than as human-readable labels. Inline XBRL (iXBRL embedded in HTML) is a different serialisation and is not read.
Graph compiler
Compiles AODM into graph structures for reasoning engines and graph databases.
Engine ──requires──▶ Spark becomes node, edge, node.
python3 aodm_graph.py doc.xml --format cypher # Neo4j
python3 aodm_graph.py doc.xml --format turtle # RDF, for SPARQL/OWL
python3 aodm_graph.py doc.xml --format graphml # Gephi, yEd
python3 aodm_graph.py doc.xml --format dot # Graphviz
Facts, rules and sources become nodes rather than properties. That is not a stylistic choice: with sources as nodes, “what rests on this source?” is one traversal, and retraction becomes possible. Flattened into text properties it is a full scan with string matching.
Inference engine
Forward chaining over the compiled graph, implementing the inference section of the specification (section 10), so its conclusions are reproducible by any other conformant engine.
$ python3 reasoner.py doc.xml
Derived 2 conclusion(s):
step 1: failure-risk confidence 0.5985
by risk-rule from temp-rise, pressure-nominal
step 1: shorten-service confidence 0.53865
by service-rule from failure-risk
Confidence multiplies along the chain, so a conclusion is never more certain than the weakest premise supporting it. It also answers two questions a reasoner usually cannot:
- Why is this believed?
--explainwalks the chain back to the observed facts and their sources. - What falls if this source is wrong?
--retractfollows the derivations forward and lists every conclusion that depended on it. - What was true then?
--at 2025-06-01reasons as at a date; a rule outside its validity window does not fire.
LLM context
Renders a document into prompt-ready context for any model. Dropping raw facts into a prompt is easy and mostly useless: the model gets a pile of assertions with no way to tell a measurement from a guess, and states them all with equal confidence.
python3 context.py doc.xml # markdown
python3 context.py doc.xml --format text # compact, for tight budgets
python3 context.py doc.xml --format json # structured, for tool use
python3 context.py doc.xml --max-chars 4000 # budget-aware
The renderer states confidence in words as well as numbers, marks known-false facts explicitly rather than omitting them, excludes superseded knowledge while saying that it did, and labels inferred facts as inferred. Those are the signals that let a model hedge accurately instead of asserting everything flatly.