Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
31
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

ゼロから始めないXBRL解析(Arelleの活用)

1.はじめに

 XBRLは、金融庁(EDINET)、東証(TDnet)、国税庁(e-Tax)、日本銀行、環境省など多数の監督当局が採用している一方で、その複雑さゆえ、ネット上で密かにぷち炎上するような、知る人ぞ知るアンダーグラウンドな技術である。
本記事では、そんなXBRLを”簡単”かつ”仕様通り”に解析し、情報を取得してくる方法を記載する。解析をゼロから始めると泥沼に嵌るため、難解な技術やパズルが大好物という方以外は、本記事で紹介する方法などで楽をして解析することを推奨する。これにより、XBRL解析機能の車輪の再開発に係る労力を、Webサービス開発等に回せたならば幸い。

2.XBRLについて

 XBRLは、財務諸表やコーポレートガバナンス報告書など、レポートを電子化するためのXMLベースの言語。「インスタンス」と「タクソノミ」から成る。インスタンスは、報告の金額、数値、テキスト以外にも、コンテキスト情報(期、年度など)や単位情報が記述される。タクソノミは、インスタンスの構造・扱われ方などを定義する。タクソノミで用いられる「xlink」が、XBRLを複雑化させた原因の一つであることは、ここでは混乱を招くため書かないでおく

3.XBRL解析ソフトウェアについて

 EDINETやTDnetで開示されているXBRL形式の財務データを分析し、投資に活用するために、個人でXBRL解析ソフトウェア(XBRLを検証、処理できるソフトウェア)を開発する方もいるが、仕様どおりに開発するのは難しい。XBRLの各種仕様は、XBRLInternationalが公開している。日本で主に採用されている仕様は、XBRL 2.1(Spec2.1)XBRL Dimensions 1.0、そしてInline XBRL Specification 1.0の3つ。基本仕様のXBRL2.1だけでも200頁近い大作。これを仕様通りに開発するのは本当に難しい。
なお、ソフトが仕様通りの挙動か否かは、XIIの各仕様のページにある「Conformance Suite」を利用し、検証するのが一番の近道。この検証に合格した上で、その他様々な手続きをパスすると「XBRL Certified Software」というXIIが認定するXBRLソフトウェアの称号を得ることができる。カッコいいロゴがその証。
xbrl-certified-software-logo.png
記事の途中であるが、概ね言いたいことが出てきたので、本記事の結論をここに書いておく。

『XBRLを”簡単”かつ”仕様通り”に解析し、情報を取得してくるには「XBRL Certified Software」を得ているソフトウェアを使うのがよい』

「XBRL Certified Software」はこのサイトに全て記載されている。2019年8月時点では、10件あるようだ。(Report Consumption Softwareに該当するものをカウント)
しかし、そんな苦労して作ったソフトウェアなんだから、ライセンス料高いんでしょ?と思うかもしれない。・・・ある、この中にOSSがある。

4.Arelleについて

 Arelleは「XBRL Certified Software」を保有するOSS。つまり無償。
それでいて、他の有償のXBRL解析ソフトウェアと同様に殆どの(あるいは全ての)仕様をカバーしている。

【Arelleがカバーしている主な仕様】
- XBRL v2.1
- Dimensions v1.0
- Inline XBRL v1.1
- Formula v1.0

Arelleのギフハブはこちら。
特徴を羅列する。ライセンスはApache License 2.0なので改修してビジネスにも使える。既存のXBRLソフトウェアのバックでこいつが走ってたりもする。開発者は主要なXBRL仕様のEditor、Contributor。GUI版もある。Pythonで開発されている。便利。RESTベースのWebサービスAPIが提供されており、Excel、Java、C#などに対応。その他色んな機能があるっぽいが、把握できていない。詳しい人からのコメント求む。最新の情報は、公式サイトを確認するのがよい。

やや古めだが、資料もこちらに記載しておく。本記事では紹介しないGUIでの利用方法などが書いてある。
http://www.openfiling.info/wp-content/upLoads/data/ArelleUsersManual.pdf
https://studylib.net/doc/10221035/xbrl-arelle-tutorial

ということで、次の章からArelleを使ってデータ解析をしていく。

5.ArelleでXBRLデータ解析

環境構築

以下公式サイトからの抜粋。macOS Sierra 10.13.4、Python 3.5.2で構築。その他、Windows7の64bit版でも動作を確認済み。

The implementation is in Python 3.5, and is intended for Windows (any recent), Mac OS-X 10.9-11, Unix or Linux.

おもむろに必要なライブラリをインストールする。現時点でarelleのバージョンは2.2が最新の模様。

$ pip install lxml
$ pip install isodate
$ pip install arelle

※arelleはPyPIに登録されている

データ準備

今回は、EDINETから有価証券報告書のXBRLデータを手動でダウンロードしてきた。
時間がある人は、金融庁や企業で提供しているAPIなどでダウンロードしてみるとよい。
(公式に、平成31年3月17日からEDINETに提出された書類をAPIで取得できるようになった)

プログラム説明

Arelleでインスタンスを処理させて、取得した情報をテキストに吐き出すサンプルプログラムを作成。(プログラムは[7.ソースコード]を参照のこと)
なぜか出力に標準出力を採用。100個近いprint文がコーディングされ、1つのテキストファイルに情報が吐き出されるパンチのあるプログラムが完成した。もう後戻りはできない。本プログラムの利用用途は、Arelleが出力する情報の構造理解、という観点であることは忘れないでほしい。

ここでは、ポイントとなるコードのみ解説する。
また、オブジェクトの関係や構造などは、設計書っぽいものに書いてあるので、適宜参照すると理解が捗る。

ポイント1:

ModelManagerから、インスタンスをロードし、ModelXbrlを作成する。
ModelXbrlからは、インスタンスが参照している全ドキュメント情報を取得できる。その他取得できる情報は、WhitePaperっぽいものに記載されているPropertiesや、ソース(ModelXbrl.py)を見れば分かる。

modelXbrl =modelManager.load(filePath)
for urlIndex, urlDoc in enumerate(modelXbrl.urlDocs):
    print(" -【ModelXbrl.urlDocs】 :","[",urlIndex+1,"]",urlDoc)

出力結果(ModelXbrl)
************ModelXbrl************
 -【ModelXbrl.urlDocs】 : [ 1 ] C:\PublicDoc\jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl
 -【ModelXbrl.urlDocs】 : [ 2 ] C:\PublicDoc\jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xsd
 -【ModelXbrl.urlDocs】 : [ 3 ] http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp/2018-03-31/jpcrp_cor_2018-03-31.xsd
 -【ModelXbrl.urlDocs】 : [ 4 ] http://www.xbrl.org/2003/xbrl-instance-2003-12-31.xsd
 -【ModelXbrl.urlDocs】 : [ 5 ] http://www.xbrl.org/2003/xbrl-linkbase-2003-12-31.xsd
 -【ModelXbrl.urlDocs】 : [ 6 ] http://www.xbrl.org/2003/xl-2003-12-31.xsd
・・・(省略)

ポイント2:

modelxbrl.urlDocsからModelDocumentを取得。
ModelDocumentからは、各ドキュメントのType(インスタンス、スキーマ、リンクベース等)情報や、targetNamespace、名前空間などを取得できる。

for docIndex, urlDoc in enumerate(modelXbrl.urlDocs):
    print("[", docIndex+1, "]", ":ModelDocument")
    print(" -【ModelDocument.type】 :",modelXbrl.urlDocs[urlDoc].type,"[",docType,"]")
    print(" -【ModelDocument.uri】 :",modelXbrl.urlDocs[urlDoc].uri)
    print(" -【ModelDocument.targetNamespace】 :",modelXbrl.urlDocs[urlDoc].targetNamespace)
    print(" -【ModelDocument.referencedNamespaces】 :", modelXbrl.urlDocs[urlDoc].referencedNamespaces)
    print(" +【ModelDocument.xmlRootElement】 :", modelXbrl.urlDocs[urlDoc].xmlRootElement)
    # 【ModelObject Properties】
    print(" - -【ModelObject.localName】 :", modelXbrl.urlDocs[urlDoc].xmlRootElement.localName)
    print(" - -【ModelObject.attrib】 :", modelXbrl.urlDocs[urlDoc].xmlRootElement.attrib)
    print(" - -【ModelObject.defaultNamespaceURI】 :", modelXbrl.urlDocs[urlDoc].xmlRootElement.namespaceURI)
    for i, ns in enumerate(modelXbrl.urlDocs[urlDoc].xmlRootElement.nsmap):
            print(" - -【ModelObject.nsmap.prefix","[", i, "]", ns)
            print(" - -【ModelObject.nsmap.namespaceURI","[", i, "]", modelXbrl.urlDocs[urlDoc].xmlRootElement.nsmap[ns])

出力結果(ModelDocument)
************ModelDocument************
[ 1 ] :ModelDocument
 -【ModelDocument.type】 : 4 [ instance ]
 -【ModelDocument.uri】 : C:\PublicDoc\jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl
 -【ModelDocument.targetNamespace】 : None
 -【ModelDocument.referencedNamespaces】 : set()
 +【ModelDocument.xmlRootElement】 : ModelObject[1, jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl line 2)
 - -【ModelObject.localName】 : xbrl
 - -【ModelObject.attrib】 : {}
 - -【ModelObject.defaultNamespaceURI】 : http://www.xbrl.org/2003/instance
 - -【ModelObject.nsmap.prefix [ 0 ] link
 - -【ModelObject.nsmap.namespaceURI [ 0 ] http://www.xbrl.org/2003/linkbase
 - -【ModelObject.nsmap.prefix [ 1 ] jpdei_cor
 - -【ModelObject.nsmap.namespaceURI [ 1 ] http://disclosure.edinet-fsa.go.jp/taxonomy/jpdei/2013-08-31/jpdei_cor
 - -【ModelObject.nsmap.prefix [ 2 ] iso4217
 - -【ModelObject.nsmap.namespaceURI [ 2 ] http://www.xbrl.org/2003/iso4217
 - -【ModelObject.nsmap.prefix [ 3 ] xbrldi
 - -【ModelObject.nsmap.namespaceURI [ 3 ] http://xbrl.org/2006/xbrldi
 ・・・(省略)

ポイント3:

modelxbrl.factsからModelFactを取得する。
要は、繰り返し処理でインスタンスに定義されている全factの情報をMoldelFact型で取得してくるもの。※構造を考慮すれば、ModelDocumentにぶら下がるModelObjectからModelFactを取得するようだが、今回は簡略化した処理にしている
このModelFactからは、concept、context、unitやvalueなどを取得できる。既にタクソノミの情報と紐づけがされている状態なのはありがたい。各種情報は、いずれもModelConceptModelContextModelUnitでオブジェクト化されている。そのため、ModelFactの取得に合わせ、これらのオブジェクト情報の詳細も取得し、テキストに吐き出すようにした。以下に1つのfact分のみを抽出し結果として貼り付けている。

print("************ModelFact************")
for i,fact in enumerate(modelXbrl.facts):
        print("[", i+1, "]",":modelFact")

        #【ModelFact Properties】
        print(" +【modelFact.concept】:",fact.concept)

        # 【modelConcept Properties】
        print(" - -【modelConcept.qname】:", fact.concept.qname)
        print(" - -【modelConcept.abstract】:", fact.concept.abstract)
        print(" - -【modelConcept.periodType】:", fact.concept.periodType)
        print(" - -【modelConcept.typeQname】:", fact.concept.typeQname)
        print(" - -【modelConcept.niceType】:", fact.concept.niceType)
        print(" - -【modelConcept.isNumeric】:", fact.concept.isNumeric)
        print(" - -【modelConcept.isFraction】:", fact.concept.isFraction)
        print(" - -【modelConcept.isMonetary】:", fact.concept.isMonetary)
        print(" - -【modelConcept.isShares】:", fact.concept.isShares)
        print(" - -【modelConcept.isTextBlock】:", fact.concept.isTextBlock)
        print(" - -【modelConcept.type】:", fact.concept.type)

        #・・・(省略)

出力結果(ModelFact)
************ModelFact************

[ 613 ] :modelFact
 +【modelFact.concept】: modelConcept[5049, qname: jppfs_cor:CashAndDeposits, type: xbrli:monetaryItemType, abstract: false, jppfs_cor_2018-03-31.xsd, line 16]
 - -【modelConcept.qname】: jppfs_cor:CashAndDeposits
 - -【modelConcept.abstract】: false
 - -【modelConcept.periodType】: instant
 - -【modelConcept.typeQname】: xbrli:monetaryItemType
 - -【modelConcept.niceType】: Monetary
 - -【modelConcept.isNumeric】: True
 - -【modelConcept.isFraction】: False
 - -【modelConcept.isMonetary】: True
 - -【modelConcept.isShares】: False
 - -【modelConcept.isTextBlock】: False
 - -【modelConcept.type】: modelType[500, qname: xbrli:monetaryItemType, derivedFrom: xbrli:monetary, xbrl-instance-2003-12-31.xsd, line 269]
 - +【modelConcept.substitutionGroup】: modelConcept[729, qname: xbrli:item, type: anyType, abstract: true, xbrl-instance-2003-12-31.xsd, line 739]
 - - -【modelConcept.qname】: xbrli:item
 - - -【modelConcept.abstract】: true
 - - -【modelConcept.niceType】: anyType
 - -【modelConcept.substitutionGroupQnames】: [xbrli:item]
 - -【modelConcept.nillable】: true
 - -【modelConcept.isItem】: True
 - -【modelConcept.isTuple】: False
 - -【modelConcept.isPrimaryItem】: True
 - -【modelConcept.isDomainMember】: True
 - -【modelConcept.isHypercubeItem】: False
 - -【modelConcept.isDimensionItem】: False
 - -【modelConcept.isTypedDimension】: False
 - -【modelConcept.isExplicitDimension】: False
 - -【modelConcept.typedDomainElement】: None
 -【modelFact.contextID】: CurrentYearInstant_NonConsolidatedMember
 +【modelFact.context】: modelContext[CurrentYearInstant_NonConsolidatedMember, period: instant 2019-03-31, dimensions: (1) (('jppfs_cor:ConsolidatedOrNonConsolidatedAxis', 'jppfs_cor:NonConsolidatedMember'),),jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl line 1544]
 - -【modelContext.isStartEndPeriod】: False
 - -【modelContext.isInstantPeriod】: True
 - -【modelContext.isForeverPeriod】: False
 - -【modelContext.startDatetime】: None
 - -【modelContext.endDatetime】: 2019-04-01 00:00:00
 - -【modelContext.instantDatetime】: 2019-04-01 00:00:00
 - +【modelContext.period】: ModelObject[90621, jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl line 1548)
 - - -【ModelObject.elementQname】: xbrli:period
 - +【modelContext.entity】: ModelObject[90620, jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl line 1545)
 - - -【ModelObject.elementQname】: xbrli:entity
 - +【modelContext.entityIdentifierElement】: ModelObject[90623, jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl line 1546)
 - - -【ModelObject.entityIdentifierElement.elementQname】: xbrli:identifier
 - - -【ModelObject.elementAttributesStr】: scheme='http://disclosure.edinet-fsa.go.jp'
 - - -【ModelObject.entityIdentifierElement.textValue】: E01738-000
 - -【modelContext.entityIdentifier】: ('http://disclosure.edinet-fsa.go.jp', 'E01738-000')
 - -【modelContext.segment】: None
 - -【modelContext.scenario】: ModelObject[90622, jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl line 1551)
 - +【modelContext.scenDimValues】: {modelConcept[8920, qname: jppfs_cor:ConsolidatedOrNonConsolidatedAxis, type: xbrli:stringItemType, abstract: true, jppfs_cor_2018-03-31.xsd, line 3887]: ModelDimensionValue[90625, jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl line 1552)}
 - - -【modelConcept.qname】: [ 1 ] jppfs_cor:ConsolidatedOrNonConsolidatedAxis
 - - -【modelConcept.abstract】: [ 1 ] true
 - - -【modelConcept.typeQname】: [ 1 ] xbrli:stringItemType
 - - -【ModelDimensionValue.dimensionQname】: [ 1 ] jppfs_cor:ConsolidatedOrNonConsolidatedAxis
 - - -【ModelDimensionValue.memberQname】: [ 1 ] jppfs_cor:NonConsolidatedMember
 - - -【ModelDimensionValue.contextElement】: [ 1 ] scenario
 -【modelFact.unitID】: JPY
 +【modelFact.unit】: ModelUnit[87974, jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl line 2789)
 - -【ModelUnit.measures】: ((iso4217:JPY,), ())
 - -【ModelUnit.value】: JPY
 +【modelFact.parentElement】: ModelObject[1, jpcrp030000-asr-001_E01738-000_2019-03-31_01_2019-06-25.xbrl line 2)
 - -【ModelObject.elementQname】: xbrli:xbrl
 -【modelFact.ancestorQnames】: {xbrli:xbrl}
 -【modelFact.decimals】: -6
 -【modelFact.precision】: None
 -【modelFact.xmlLang】: None
 -【modelFact.xsiNil】: false
 -【modelFact.value】: 1070861000000
 -【modelFact.fractionValue】: ('', '')



ポイント4:

インスタンスのfootnoteを抽出する処理。
modelXbrlに含まれる全modelObjectsを順次処理していく。取得してきたmodelObjectsがfootnote情報などを含むModelLinkで、かつelementQname属性がlink:footnoteLinkの場合のみ、footnote情報を取得してくる仕組み。
リンベベース種別を保持するlinkNameを、link:labelLinklink:definitionLinkに一致するかどうかの判定に変更することで、各種リンクベース情報を取得可能。

print("************ModelLink************")
footnoteLinkCount = 1
for modelObject in modelXbrl.modelObjects:
    modelObjectStr = str(modelObject).split('[')[0]
    if modelObjectStr == 'ModelLink':
        linkName = str(modelObject.elementQname)

        if 'link:footnoteLink' == linkName:
        #・・・(省略)
            if 'fact' == name:
            #・・・(省略)

            elif 'footnote' == name:
            #・・・(省略)

出力結果(ModelLink)
[ 21 ]
 -【ModelLink.elementQname】: link:footnoteLink
 -【ModelLink.elementAttributesTuple】: [ 0 ] ('{http://www.w3.org/1999/xlink}role', 'http://disclosure.edinet-fsa.go.jp/role/jppfs/rol_StatementOfIncome')
 -【ModelLink.elementAttributesTuple】: [ 1 ] ('{http://www.w3.org/1999/xlink}type', 'extended')
 +【ModelLink.labeledResources】 defaultdict(<class 'list'>, {'footnote': [ModelResource[114368, jpcrp030000-asr-001_E04911-000_2019-03-31_01_2019-06-21.xbrl line 37884)], 'fact': [ModelLocator[114369, jpcrp030000-asr-001_E04911-000_2019-03-31_01_2019-06-21.xbrl line 37885)]})
 - -【ModelLink.fact】 footnote
 - +【ModelLink.value】 [ModelResource[114368, jpcrp030000-asr-001_E04911-000_2019-03-31_01_2019-06-21.xbrl line 37884)]
 - - -【ModelResource.elementQname】: link:footnote
 - - -【ModelResource.xlinkLabel】: footnote
 - - -【ModelResource.role】: http://disclosure.edinet-fsa.go.jp/role/jppfs/role/NotesNumber
 - - -【ModelResource.xmlLang】: ja
 - -【ModelLink.stringValue】: ※1
 - -【ModelLink.fact】 fact
 - +【ModelLink.value】 [ModelLocator[114369, jpcrp030000-asr-001_E04911-000_2019-03-31_01_2019-06-21.xbrl line 37885)]
 - - -【ModelLocator.elementQname】: link:loc
 - - -【ModelLocator.elementAttributesTuple】: [ 0 ] ('{http://www.w3.org/1999/xlink}label', 'fact')
 - - -【ModelLocator.elementAttributesTuple】: [ 1 ] ('{http://www.w3.org/1999/xlink}type', 'locator')
 - - -【ModelLocator.elementAttributesTuple】: [ 2 ] ('{http://www.w3.org/1999/xlink}href', '#fact20')



ポイント(全体補足):

以下表の参照オブジェクトを利用することで、インスタンス情報(footnote含む)を抽出した。仮にinlineXBRLがインプットになる場合は、ModelFact以外に、ModelinlineFactから情報を取得してくる必要がある。
その他、各種オブジェクトの目的や保持情報のdetailは、公式サイトのARCHITECTURE, MODEL 中段の「The model objects are, from general to more specific:」以降に記載されている。

ER図 参照オブジェクト
Model Instance Objects ModelXbrl、ModelDocument、ModelObject、ModelConcept、ModelFact、ModelContext、ModelUnit、ModelDimensionValue
Model DTS Objects ModelXbrl、ModelDocument、ModelObject、ModelResource、ModelLocator

structure_instance.png

structure_dts.png

6.まとめ

 XBRLのインスタンス情報(一部タクソノミ情報有り)を、Arelleを活用することで簡単、かつ仕様通りに解析することができた。
日本国内のXBRLデータのみを解析対象とするならば、システムで開示されているXBRLのアーキテクチャを理解し、解析ソフトウェアを自作することも確かに悪くないのだが、いざ海外のXBRLデータを取り込もうとすると、採用している仕様(TableLinkbase、InlineXBRLv1.1など)が異なっていたり、同じ仕様でもあまり使わない技術(TypedDimension,Tupleなど)を採用しているため解析できないなど、色々問題が発生し始める。
結果として、自作ソフトをカスタマイズすることになる可能性が高い。そしていつの間にかソフトを改修するのに時間が取られ、本来やりたいことに時間が割けなくなっていく。技術を理解するために開発するというのも分かるが、道が険しすぎてやはりオススメできない。
これからXBRLの世界に入るみなさんは、先人の知恵を最大限利用しよう。

7.ソースコード

# -*- coding: utf-8 -*-

from arelle import ModelManager
from arelle import Cntlr
import sys

# 【TODO】出力するテキストパスを記入
fo = open('/Users/XXX/output.txt', 'w', encoding='utf-8')
sys.stdout = fo

# EDINET instance
# 【TODO】処理したいEDINETのインスタンスファイルパスを記入
filePath = '/Users/XXXX/Desktop/jpcrp030000-asr-001_E04911-000_2019-03-31_01_2019-06-21.xbrl'

ctrl = Cntlr.Cntlr()
modelManager = ModelManager.initialize(ctrl)

print("************Cntlr************")
print(" -【Cntlr.userAppDir】 :", ctrl.userAppDir)

print('************WebCache************')
print(" -【WebCache.cacheDir】 :", ctrl.webCache.cacheDir)

print("************ModelManager************")
print(" -【ModelManager.defaultLang】 :", modelManager.defaultLang)

modelXbrl = modelManager.load(filePath)

print("************ModelXbrl************")
for urlIndex, urlDoc in enumerate(modelXbrl.urlDocs):
    print(" -【ModelXbrl.urlDocs】 :", "[", urlIndex + 1, "]", urlDoc)
print(" -【ModelXbrl.langs】 :", modelXbrl.langs)

print("************ModelDocument************")

for docIndex, urlDoc in enumerate(modelXbrl.urlDocs):
    print("[", docIndex + 1, "]", ":ModelDocument")

    docType = ""
    if (modelXbrl.urlDocs[urlDoc].type == 2):
        docType = "schema"
    elif (modelXbrl.urlDocs[urlDoc].type == 3):
        docType = "linkbase"
    elif (modelXbrl.urlDocs[urlDoc].type == 4):
        docType = "instance"
    elif (modelXbrl.urlDocs[urlDoc].type == 5):
        docType = "inlineXBRL"

    print(" -【ModelDocument.type】 :", modelXbrl.urlDocs[urlDoc].type, "[", docType, "]")
    print(" -【ModelDocument.uri】 :", modelXbrl.urlDocs[urlDoc].uri)
    print(" -【ModelDocument.targetNamespace】 :", modelXbrl.urlDocs[urlDoc].targetNamespace)
    print(" -【ModelDocument.referencedNamespaces】 :", modelXbrl.urlDocs[urlDoc].referencedNamespaces)
    print(" +【ModelDocument.xmlRootElement】 :", modelXbrl.urlDocs[urlDoc].xmlRootElement)

    # 【ModelObject Properties】
    print(" - -【ModelObject.localName】 :", modelXbrl.urlDocs[urlDoc].xmlRootElement.localName)
    print(" - -【ModelObject.attrib】 :", modelXbrl.urlDocs[urlDoc].xmlRootElement.attrib)
    print(" - -【ModelObject.defaultNamespaceURI】 :", modelXbrl.urlDocs[urlDoc].xmlRootElement.namespaceURI)

    for i, ns in enumerate(modelXbrl.urlDocs[urlDoc].xmlRootElement.nsmap):
        print(" - -【ModelObject.nsmap.prefix", "[", i, "]", ns)
        print(" - -【ModelObject.nsmap.namespaceURI", "[", i, "]", modelXbrl.urlDocs[urlDoc].xmlRootElement.nsmap[ns])

print("************ModelFact************")
for i, fact in enumerate(modelXbrl.facts):
    print("[", i + 1, "]", ":modelFact")

    # 【ModelFact Properties】
    print(" -【modelFact.id】:", fact.id) #footnote用に追加
    print(" +【modelFact.concept】:", fact.concept)

    # 【modelConcept Properties】
    print(" - -【modelConcept.qname】:", fact.concept.qname)
    print(" - -【modelConcept.abstract】:", fact.concept.abstract)
    print(" - -【modelConcept.periodType】:", fact.concept.periodType)
    print(" - -【modelConcept.typeQname】:", fact.concept.typeQname)
    print(" - -【modelConcept.niceType】:", fact.concept.niceType)
    print(" - -【modelConcept.isNumeric】:", fact.concept.isNumeric)
    print(" - -【modelConcept.isFraction】:", fact.concept.isFraction)
    print(" - -【modelConcept.isMonetary】:", fact.concept.isMonetary)
    print(" - -【modelConcept.isShares】:", fact.concept.isShares)
    print(" - -【modelConcept.isTextBlock】:", fact.concept.isTextBlock)
    print(" - -【modelConcept.type】:", fact.concept.type)

    print(" - +【modelConcept.substitutionGroup】:", fact.concept.substitutionGroup)

    # 【modelConcept Properties】
    print(" - - -【modelConcept.qname】:", fact.concept.substitutionGroup.qname)
    print(" - - -【modelConcept.abstract】:", fact.concept.substitutionGroup.abstract)
    print(" - - -【modelConcept.niceType】:", fact.concept.substitutionGroup.niceType)
    print(" - -【modelConcept.substitutionGroupQnames】:", fact.concept.substitutionGroupQnames)
    print(" - -【modelConcept.nillable】:", fact.concept.nillable)
    print(" - -【modelConcept.isItem】:", fact.concept.isItem)
    print(" - -【modelConcept.isTuple】:", fact.concept.isTuple)
    print(" - -【modelConcept.isPrimaryItem】:", fact.concept.isPrimaryItem)
    print(" - -【modelConcept.isDomainMember】:", fact.concept.isDomainMember)
    print(" - -【modelConcept.isHypercubeItem】:", fact.concept.isHypercubeItem)
    print(" - -【modelConcept.isDimensionItem】:", fact.concept.isDimensionItem)
    print(" - -【modelConcept.isTypedDimension】:", fact.concept.isTypedDimension)
    print(" - -【modelConcept.isExplicitDimension】:", fact.concept.isExplicitDimension)
    print(" - -【modelConcept.typedDomainElement】:", fact.concept.typedDomainElement)

    print(" -【modelFact.contextID】:", fact.contextID)
    print(" +【modelFact.context】:", fact.context)

    # 【modelContext Properties】
    print(" - -【modelContext.isStartEndPeriod】:", fact.context.isStartEndPeriod)
    print(" - -【modelContext.isInstantPeriod】:", fact.context.isInstantPeriod)
    print(" - -【modelContext.isForeverPeriod】:", fact.context.isForeverPeriod)
    print(" - -【modelContext.startDatetime】:", fact.context.startDatetime)
    print(" - -【modelContext.endDatetime】:", fact.context.endDatetime)
    print(" - -【modelContext.instantDatetime】:", fact.context.instantDatetime)
    print(" - +【modelContext.period】:", fact.context.period)

    # 【ModelObject Properties】
    print(" - - -【ModelObject.elementQname】:", fact.context.period.elementQname)

    print(" - +【modelContext.entity】:", fact.context.entity)

    # 【ModelObject Properties】
    print(" - - -【ModelObject.elementQname】:", fact.context.entity.elementQname)

    print(" - +【modelContext.entityIdentifierElement】:", fact.context.entityIdentifierElement)

    # 【ModelObject Properties】
    print(" - - -【ModelObject.entityIdentifierElement.elementQname】:",
          fact.context.entityIdentifierElement.elementQname)
    print(" - - -【ModelObject.elementAttributesStr】:", fact.context.entityIdentifierElement.elementAttributesStr)
    print(" - - -【ModelObject.entityIdentifierElement.textValue】:", fact.context.entityIdentifierElement.textValue)

    print(" - -【modelContext.entityIdentifier】:", fact.context.entityIdentifier)
    print(" - -【modelContext.segment】:", fact.context.segment)
    print(" - -【modelContext.scenario】:", fact.context.scenario)
    print(" - +【modelContext.scenDimValues】:", fact.context.scenDimValues)

    for dimIndex, scenDimValue in enumerate(fact.context.scenDimValues):
        print(" - - -【modelConcept.qname】:", "[", dimIndex + 1, "]", scenDimValue.qname)
        print(" - - -【modelConcept.abstract】:", "[", dimIndex + 1, "]", scenDimValue.abstract)
        print(" - - -【modelConcept.typeQname】:", "[", dimIndex + 1, "]", scenDimValue.typeQname)
        print(" - - -【ModelDimensionValue.dimensionQname】:", "[", dimIndex + 1, "]",
              fact.context.scenDimValues[scenDimValue].dimensionQname)
        print(" - - -【ModelDimensionValue.memberQname】:", "[", dimIndex + 1, "]",
              fact.context.scenDimValues[scenDimValue].memberQname)
        print(" - - -【ModelDimensionValue.contextElement】:", "[", dimIndex + 1, "]",
              fact.context.scenDimValues[scenDimValue].contextElement)

    print(" -【modelFact.unitID】:", fact.unitID)
    print(" +【modelFact.unit】:", fact.unit)

    # 【ModelUnit Properties】
    if fact.unit is not None:  # (empty if not a divide element)
        print(" - -【ModelUnit.measures】:", fact.unit.measures)
        print(" - -【ModelUnit.value】:", fact.unit.value)

    print(" +【modelFact.parentElement】:", fact.parentElement)

    # 【ModelObject Properties】
    print(" - -【ModelObject.elementQname】:", fact.parentElement.elementQname)

    print(" -【modelFact.ancestorQnames】:", fact.ancestorQnames)
    print(" -【modelFact.decimals】:", fact.decimals)
    print(" -【modelFact.precision】:", fact.precision)
    print(" -【modelFact.xmlLang】:", fact.xmlLang)
    print(" -【modelFact.xsiNil】:", fact.xsiNil)
    print(u" -【modelFact.value】:", fact.value)
    print(" -【modelFact.fractionValue】:", fact.fractionValue)

print("************ModelLink(Footnote)************")
footnoteLinkCount = 1
for modelObject in modelXbrl.modelObjects:
    modelObjectStr = str(modelObject).split('[')[0]
    if modelObjectStr == 'ModelLink':
        linkName = str(modelObject.elementQname)

        if 'link:footnoteLink' == linkName:
            print("[", footnoteLinkCount, "]")
            print(" -【ModelLink.elementQname】:", modelObject.elementQname)

            for tupleNum, list in enumerate(modelObject.elementAttributesTuple):
                print(" -【ModelLink.elementAttributesTuple】:", "[", tupleNum, "]", list)

            print(" +【ModelLink.labeledResources】", modelObject.labeledResources)

            for name in modelObject.labeledResources:
                print(" - -【ModelLink.fact】", name)
                print(" - +【ModelLink.value】", modelObject.labeledResources[name])

                if 'fact' == name:
                    for listNum, footnote in enumerate(modelObject.labeledResources[name]):

                        print(
                        " - - -【ModelLocator.elementQname】:", modelObject.labeledResources[name][listNum].elementQname)

                        for tupleNum, list in enumerate(
                                modelObject.labeledResources[name][listNum].elementAttributesTuple):
                            print(" - - -【ModelLocator.elementAttributesTuple】:", "[", tupleNum, "]", list)

                elif 'footnote' == name:
                    for listNum, footnote in enumerate(modelObject.labeledResources[name]):
                        print(" - - -【ModelResource.elementQname】:",
                              modelObject.labeledResources[name][listNum].elementQname)
                        print(" - - -【ModelResource.xlinkLabel】:",
                              modelObject.labeledResources[name][listNum].xlinkLabel)
                        print(" - - -【ModelResource.role】:", modelObject.labeledResources[name][listNum].role)
                        print(
                            " - - -【ModelResource.xmlLang】:", modelObject.labeledResources[name][listNum].xmlLang)
                        print(" - - -【ModelLink.stringValue】:", modelObject.stringValue)

            footnoteLinkCount += 1
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
31
Help us understand the problem. What are the problem?