Table codes and filing indicators¶
A report says which templates it reports through its filing indicators,
codes such as C_07.00 with a reported flag. Its xBRL-CSV tables are named
by table codes, the file stems such as c_07.00.a. One template can be
split over several tables, so the two codes differ.
The mapping¶
dpm-xbrl maps a table code to its filing indicator in two steps:
- Single-letter parts are dropped. A part is the text between dots; a part of one letter (any case) is a table's letter within its template.
- Codes are compared case-insensitively.
| Table file | Template id | Filing indicator |
|---|---|---|
c_01.00.csv |
c_01.00 |
C_01.00 |
c_07.00.a.csv, c_07.00.b.csv |
c_07.00.a, c_07.00.b |
C_07.00 |
f_18.00.a.dp.csv |
f_18.00.a.dp |
F_18.00.dp |
c_43.00.c.csv |
c_43.00.c |
C_43.00 |
The template id is the file stem, unless the metadata's tables maps the
file URL to another template.
dpm-xbrl uses this mapping for xBRL-CSV rule 6: a package must not contain the table file of a template whose filing indicator is false.
Where the mapping applies, and where it does not¶
Fact.template is always the template id, c_07.00.a, never the filing
indicator. Report.facts_for_template
compares case-insensitively and matches a table by its template id or by
its filing indicator, so C_07.00 selects the facts of every lettered table
of the template and c_07.00.a those of one table.
filing_indicator_code gives a table's
filing indicator:
import io
from zipfile import ZipFile
from dpmxbrl import filing_indicator_code, read_report
# report.zip plus a template split into two tables, and one filed as not reported.
buffer = io.BytesIO()
with ZipFile("report.zip") as source, ZipFile(buffer, "w") as target:
for name in source.namelist():
data = source.read(name)
if name.endswith("FilingIndicators.csv"):
data += b"C_07.00,true\r\nF_18.00.dp,false\r\n"
target.writestr(name, data)
target.writestr(
"report/reports/c_07.00.a.csv", "datapoint,factValue\r\ndp1001,500\r\n"
)
target.writestr(
"report/reports/c_07.00.b.csv", "datapoint,factValue\r\ndp1002,700\r\n"
)
target.writestr(
"report/reports/f_18.00.a.dp.csv", "datapoint,factValue\r\ndp1003,1\r\n"
)
report = read_report(buffer.getvalue(), name="report.zip")
print(
len(report.facts_for_template("C_07.00")),
len(report.facts_for_template("C_07.00.A")),
)
To group every fact by filing indicator:
by_indicator = {}
for fact in report.facts:
code = filing_indicator_code(fact.template).casefold()
by_indicator.setdefault(code, []).append(fact)
reported = {code.casefold(): filed for code, filed in report.filing_indicators.items()}
for code, facts in sorted(by_indicator.items()):
print(code, len(facts), reported.get(code))
The table filed as not reported breaks rule 6:
print(
[
(finding.rule, finding.examples)
for finding in report.filing
if finding.rule == "xBRL-CSV 6"
]
)
The frames reader keys ReportFrames.tables by template id too, so the
same recipe, with filing_indicator_code, groups frames.
XML reports¶
XBRL-XML facts carry no template: the filing indicators say which
templates are reported, but which template a fact belongs to is only known
from the taxonomy. facts_for_template returns nothing for XML reports.