arelle-release 2.37.71__py3-none-any.whl → 2.38.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. arelle/BetaFeatures.py +0 -21
  2. arelle/Cntlr.py +7 -1
  3. arelle/CntlrCmdLine.py +95 -19
  4. arelle/CntlrWinMain.py +4 -1
  5. arelle/DialogFind.py +1 -1
  6. arelle/ModelDtsObject.py +2 -0
  7. arelle/ModelObject.py +16 -18
  8. arelle/ModelObjectFactory.py +17 -15
  9. arelle/ModelXbrl.py +7 -1
  10. arelle/PluginManager.py +1 -5
  11. arelle/RuntimeOptions.py +1 -0
  12. arelle/UrlUtil.py +11 -0
  13. arelle/Validate.py +3 -3
  14. arelle/ValidateXbrl.py +2 -1
  15. arelle/ValidateXbrlCalcs.py +210 -186
  16. arelle/WebCache.py +2 -8
  17. arelle/XbrlConst.py +2 -0
  18. arelle/XmlUtil.py +16 -21
  19. arelle/XmlValidate.py +4 -6
  20. arelle/_version.py +2 -2
  21. arelle/config/rosettaEntitlements.plist +8 -0
  22. arelle/conformance/CSVTestcaseLoader.py +1 -1
  23. arelle/formula/XPathContext.py +3 -3
  24. arelle/logging/formatters/LogFormatter.py +3 -1
  25. arelle/packages/report/ReportPackage.py +9 -1
  26. arelle/plugin/inlineXbrlDocumentSet.py +1 -3
  27. arelle/plugin/validate/DBA/DisclosureSystems.py +19 -1
  28. arelle/plugin/validate/DBA/resources/config.xml +5 -0
  29. arelle/plugin/validate/DBA/rules/fr.py +19 -2
  30. arelle/plugin/validate/DBA/rules/tc.py +2 -0
  31. arelle/plugin/validate/DBA/rules/th.py +6 -0
  32. arelle/plugin/validate/DBA/rules/tm.py +18 -5
  33. arelle/plugin/validate/DBA/rules/tr.py +11 -5
  34. arelle/plugin/validate/EDINET/ControllerPluginData.py +2 -1
  35. arelle/plugin/validate/EDINET/NamespaceConfig.py +50 -0
  36. arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +33 -78
  37. arelle/plugin/validate/EDINET/TableOfContentsBuilder.py +153 -51
  38. arelle/plugin/validate/EDINET/rules/contexts.py +1 -1
  39. arelle/plugin/validate/EDINET/rules/edinet.py +163 -20
  40. arelle/plugin/validate/EDINET/rules/gfm.py +88 -1
  41. arelle/plugin/validate/EDINET/rules/upload.py +1 -1
  42. arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py +3 -3
  43. arelle/plugin/validate/ESEF/ESEF_Current/DTS.py +42 -14
  44. arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +14 -3
  45. arelle/plugin/validate/ESEF/__init__.py +10 -5
  46. arelle/plugin/validate/ESEF/resources/authority-validations.json +10 -5
  47. arelle/plugin/validate/NL/DisclosureSystems.py +22 -0
  48. arelle/plugin/validate/NL/PluginValidationDataExtension.py +20 -0
  49. arelle/plugin/validate/NL/ValidationPluginExtension.py +48 -3
  50. arelle/plugin/validate/NL/resources/config.xml +18 -0
  51. arelle/plugin/validate/NL/rules/br_kvk.py +9 -54
  52. arelle/plugin/validate/NL/rules/fg_nl.py +7 -38
  53. arelle/plugin/validate/NL/rules/fr_kvk.py +7 -42
  54. arelle/plugin/validate/NL/rules/fr_nl.py +25 -140
  55. arelle/plugin/validate/NL/rules/nl_kvk.py +125 -12
  56. arelle/plugin/validate/ROS/rules/ros.py +3 -1
  57. arelle/plugin/validate/UK/__init__.py +70 -14
  58. arelle/utils/EntryPointDetection.py +17 -11
  59. arelle/utils/validate/ESEFImage.py +3 -3
  60. arelle/utils/validate/Validation.py +9 -0
  61. arelle/utils/validate/ValidationPlugin.py +14 -12
  62. {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/METADATA +10 -5
  63. {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/RECORD +67 -69
  64. {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/licenses/LICENSE.md +0 -3
  65. arelle/model/CommentBase.py +0 -9
  66. arelle/model/ElementBase.py +0 -11
  67. arelle/model/PIBase.py +0 -10
  68. arelle/model/__init__.py +0 -15
  69. {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/WHEEL +0 -0
  70. {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/entry_points.txt +0 -0
  71. {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/top_level.txt +0 -0
@@ -19,13 +19,15 @@ from arelle.XmlValidateConst import VALID
19
19
  from . import lookup_namespaced_facts, errorOnForbiddenImage
20
20
  from ..PluginValidationDataExtension import PluginValidationDataExtension
21
21
  from ..ValidationPluginExtension import NAMESPACE_GSD
22
- from ..DisclosureSystems import MULTI_TARGET_DISCLOSURE_SYSTEMS, STAND_ALONE_DISCLOSURE_SYSTEMS
22
+ from ..DisclosureSystems import (ARL_MULTI_TARGET_DISCLOSURE_SYSTEMS, STAND_ALONE_DISCLOSURE_SYSTEMS,
23
+ ALL_DISCLOSURE_SYSTEMS, ARL_DISCLOSURE_SYSTEMS)
23
24
 
24
25
  _: TypeGetText
25
26
 
26
27
 
27
28
  @validation(
28
29
  hook=ValidationHook.XBRL_FINALLY,
30
+ disclosureSystems=ARL_DISCLOSURE_SYSTEMS
29
31
  )
30
32
  def rule_tr01(
31
33
  pluginData: PluginValidationDataExtension,
@@ -178,6 +180,7 @@ def rule_tr06(
178
180
 
179
181
  @validation(
180
182
  hook=ValidationHook.XBRL_FINALLY,
183
+ disclosureSystems=ARL_DISCLOSURE_SYSTEMS
181
184
  )
182
185
  def rule_tr09(
183
186
  pluginData: PluginValidationDataExtension,
@@ -197,7 +200,8 @@ def rule_tr09(
197
200
 
198
201
 
199
202
  @validation(
200
- hook=ValidationHook.XBRL_FINALLY
203
+ hook=ValidationHook.XBRL_FINALLY,
204
+ disclosureSystems=ALL_DISCLOSURE_SYSTEMS
201
205
  )
202
206
  def rule_tr12(
203
207
  pluginData: PluginValidationDataExtension,
@@ -223,6 +227,7 @@ def rule_tr12(
223
227
 
224
228
  @validation(
225
229
  hook=ValidationHook.XBRL_FINALLY,
230
+ disclosureSystems=ARL_DISCLOSURE_SYSTEMS
226
231
  )
227
232
  def rule_tr11(
228
233
  pluginData: PluginValidationDataExtension,
@@ -252,7 +257,7 @@ def rule_tr11(
252
257
 
253
258
  @validation(
254
259
  hook=ValidationHook.XBRL_FINALLY,
255
- disclosureSystems=MULTI_TARGET_DISCLOSURE_SYSTEMS,
260
+ disclosureSystems=ARL_MULTI_TARGET_DISCLOSURE_SYSTEMS,
256
261
  )
257
262
  def rule_tr15(
258
263
  pluginData: PluginValidationDataExtension,
@@ -276,7 +281,7 @@ def rule_tr15(
276
281
 
277
282
  @validation(
278
283
  hook=ValidationHook.XBRL_FINALLY,
279
- disclosureSystems=MULTI_TARGET_DISCLOSURE_SYSTEMS,
284
+ disclosureSystems=ARL_MULTI_TARGET_DISCLOSURE_SYSTEMS,
280
285
  )
281
286
  def rule_tr16(
282
287
  pluginData: PluginValidationDataExtension,
@@ -301,7 +306,7 @@ def rule_tr16(
301
306
 
302
307
  @validation(
303
308
  hook=ValidationHook.XBRL_FINALLY,
304
- disclosureSystems=MULTI_TARGET_DISCLOSURE_SYSTEMS,
309
+ disclosureSystems=ARL_MULTI_TARGET_DISCLOSURE_SYSTEMS,
305
310
  )
306
311
  def rule_tr17(
307
312
  pluginData: PluginValidationDataExtension,
@@ -342,6 +347,7 @@ def rule_tr17(
342
347
 
343
348
  @validation(
344
349
  hook=ValidationHook.XBRL_FINALLY,
350
+ disclosureSystems=ARL_DISCLOSURE_SYSTEMS
345
351
  )
346
352
  def rule_tr19(
347
353
  pluginData: PluginValidationDataExtension,
@@ -21,6 +21,7 @@ from . import Constants
21
21
  from .CoverItemRequirements import CoverItemRequirements
22
22
  from .DeiRequirements import DeiRequirements, DEI_LOCAL_NAMES
23
23
  from .FilingFormat import DocumentType, FilingFormat
24
+ from .NamespaceConfig import NamespaceConfig
24
25
  from .ReportFolderType import ReportFolderType
25
26
  from .TableOfContentsBuilder import TableOfContentsBuilder
26
27
  from .UploadContents import UploadContents, UploadPathInfo
@@ -42,13 +43,13 @@ class ControllerPluginData(PluginData):
42
43
 
43
44
  def __init__(self, name: str):
44
45
  super().__init__(name)
46
+ self.namespaces = NamespaceConfig()
45
47
  self._deiValues = {}
46
48
  self._loadedModelXbrls = []
47
49
  self._manifestInstancesById = {}
48
50
  self._tocBuilder = TableOfContentsBuilder()
49
51
  self._usedFilepaths = set()
50
52
  self._uploadContents = None
51
- self.jpcrpNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp/2024-11-01/jpcrp_cor'
52
53
 
53
54
  def __hash__(self) -> int:
54
55
  return id(self)
@@ -0,0 +1,50 @@
1
+ """
2
+ See COPYRIGHT.md for copyright information.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+
8
+ class NamespaceConfig:
9
+ def __init__(self) -> None:
10
+ self.jpcrpEsr = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp-esr/2024-11-01/jpcrp-esr_cor"
11
+ self.jpcrp = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp/2024-11-01/jpcrp_cor"
12
+ self.jpcrpSbr = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp-sbr/2024-11-01/jpcrp-sbr_cor"
13
+ self.jpctl = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpctl/2024-11-01/jpctl_cor"
14
+ self.jpdei = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpdei/2013-08-31/jpdei_cor"
15
+ self.jpigp = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpigp/2024-11-01/jpigp_cor"
16
+ self.jplvh = "http://disclosure.edinet-fsa.go.jp/taxonomy/jplvh/2024-11-01/jplvh_cor"
17
+ self.jppfs = "http://disclosure.edinet-fsa.go.jp/taxonomy/jppfs/2024-11-01/jppfs_cor"
18
+ self.jpspsEsr = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpsps-esr/2024-11-01/jpsps-esr_cor"
19
+ self.jpspsSbr = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpsps-sbr/2024-11-01/jpsps-sbr_cor"
20
+ self.jpsps = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpsps/2024-11-01/jpsps_cor"
21
+ self.jptoi = "http://disclosure.edinet-fsa.go.jp/taxonomy/jptoi/2024-11-01/jptoi_cor"
22
+ self.jptooPst = "http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-pst/2024-11-01/jptoo-pst_cor"
23
+ self.jptooToa = "http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-toa/2024-11-01/jptoo-toa_cor"
24
+ self.jptooTon = "http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-ton/2024-11-01/jptoo-ton_cor"
25
+ self.jptooTor = "http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-tor/2024-11-01/jptoo-tor_cor"
26
+ self.jptooWto = "http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-wto/2024-11-01/jptoo-wto_cor"
27
+
28
+ self._namespaceMap = {
29
+ "jpcrp-esr_cor": self.jpcrpEsr,
30
+ "jpcrp-sbr_cor": self.jpcrpSbr,
31
+ "jpcrp_cor": self.jpcrp,
32
+ "jpctl_cor": self.jpctl,
33
+ "jpdei_cor": self.jpdei,
34
+ "jpigp_cor": self.jpigp,
35
+ "jplvh_cor": self.jplvh,
36
+ "jppfs_cor": self.jppfs,
37
+ "jpsps_cor": self.jpsps,
38
+ "jpsps-esr_cor": self.jpspsEsr,
39
+ "jpsps-sbr_cor": self.jpspsSbr,
40
+ "jptoi_cor": self.jptoi,
41
+ "jptoo-pst_cor": self.jptooPst,
42
+ "jptoo-toa_cor": self.jptooToa,
43
+ "jptoo-ton_cor": self.jptooTon,
44
+ "jptoo-tor_cor": self.jptooTor,
45
+ "jptoo-wto_cor": self.jptooWto,
46
+ }
47
+
48
+ def get(self, prefix: str) -> str | None:
49
+ """get namespace URI for prefix"""
50
+ return self._namespaceMap.get(prefix)
@@ -4,6 +4,7 @@ See COPYRIGHT.md for copyright information.
4
4
  from __future__ import annotations
5
5
 
6
6
  from collections import defaultdict
7
+ from collections.abc import Callable, Hashable, Iterable
7
8
  from dataclasses import dataclass
8
9
  from decimal import Decimal
9
10
  from functools import lru_cache
@@ -11,10 +12,9 @@ from pathlib import Path
11
12
 
12
13
  from lxml.etree import DTD, XML
13
14
  from operator import attrgetter
14
- from typing import Callable, Hashable, Iterable, cast
15
+ from typing import cast
15
16
 
16
17
  import os
17
- import regex
18
18
 
19
19
  from arelle import XbrlConst
20
20
  from arelle.LinkbaseType import LinkbaseType
@@ -33,11 +33,11 @@ from arelle.typing import TypeGetText
33
33
  from arelle.utils.PluginData import PluginData
34
34
  from .Constants import xhtmlDtdExtension, PROHIBITED_HTML_TAGS, PROHIBITED_HTML_ATTRIBUTES
35
35
  from .ControllerPluginData import ControllerPluginData
36
- from .CoverItemRequirements import CoverItemRequirements
37
36
  from .DeiRequirements import DeiRequirements, DEI_LOCAL_NAMES
38
37
  from .FilingFormat import FilingFormat, FILING_FORMATS, DocumentType, Ordinance
39
38
  from .FormType import FormType
40
39
  from .ManifestInstance import ManifestInstance
40
+ from .NamespaceConfig import NamespaceConfig
41
41
  from .ReportFolderType import HTML_EXTENSIONS
42
42
  from .Statement import Statement, STATEMENTS, BalanceSheet, StatementInstance, StatementType
43
43
  from .UploadContents import UploadContents, UploadPathInfo
@@ -71,34 +71,21 @@ class UriReference:
71
71
 
72
72
  @dataclass
73
73
  class PluginValidationDataExtension(PluginData):
74
- # Namespaces
75
- jpcrpEsrNamespace: str
76
- jpcrpNamespace: str
77
- jpctlNamespace: str
78
- jpcrpSbrNamespace: str
79
- jpdeiNamespace: str
80
- jpigpNamespace: str
81
- jplvhNamespace: str
82
- jppfsNamespace: str
83
- jpspsEsrNamespace: str
84
- jpspsSbrNamespace: str
85
- jpspsNamespace: str
86
- jptoiNamespace: str
87
- jptooPstNamespace: str
88
- jptooToaNamespace: str
89
- jptooTonNamespace: str
90
- jptooTorNamespace: str
91
- jptooWtoNamespace: str
74
+ namespaces: NamespaceConfig
92
75
 
93
76
  accountingStandardsDeiQn: QName
94
77
  assetsIfrsQn: QName
95
78
  categoriesOfDirectorsAndOtherOfficersAxisQn: QName
96
79
  consolidatedOrNonConsolidatedAxisQn: QName
80
+ corporateGovernanceCompanyWithAuditAndSupervisoryCommitteeTextBlockQn: QName
81
+ corporateGovernanceCompanyWithCorporateAuditorsTextBlockQn: QName
82
+ corporateGovernanceCompanyWithNominatingAndOtherCommitteesTextBlockQn: QName
97
83
  documentTypeDeiQn: QName
98
84
  executiveOfficersMemberQn: QName
99
85
  jpcrpEsrFilingDateCoverPageQn: QName
100
86
  jpcrpFilingDateCoverPageQn: QName
101
87
  jpspsFilingDateCoverPageQn: QName
88
+ issuedSharesTotalNumberOfSharesEtcQn: QName
102
89
  nonConsolidatedMemberQn: QName
103
90
  ratioOfFemaleDirectorsAndOtherOfficersQn: QName
104
91
 
@@ -107,73 +94,39 @@ class PluginValidationDataExtension(PluginData):
107
94
  deiItems: tuple[QName, ...]
108
95
  deiRequirementsPath: Path
109
96
 
110
- _namespaceMap: dict[str, str]
111
97
  _uriReferences: list[UriReference]
112
98
 
113
99
  def __init__(self, name: str, validateXbrl: ValidateXbrl):
114
100
  super().__init__(name)
115
101
 
116
- # Namespaces
117
- self.jpcrpEsrNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp-esr/2024-11-01/jpcrp-esr_cor"
118
- self.jpcrpNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp/2024-11-01/jpcrp_cor'
119
- self.jpcrpSbrNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp-sbr/2024-11-01/jpcrp-sbr_cor"
120
- self.jpctlNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpctl/2024-11-01/jpctl_cor'
121
- self.jpdeiNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpdei/2013-08-31/jpdei_cor'
122
- self.jpigpNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpigp/2024-11-01/jpigp_cor"
123
- self.jplvhNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jplvh/2024-11-01/jplvh_cor"
124
- self.jppfsNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jppfs/2024-11-01/jppfs_cor"
125
- self.jpspsEsrNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpsps-esr/2024-11-01/jpsps-esr_cor'
126
- self.jpspsSbrNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpsps-sbr/2024-11-01/jpsps-sbr_cor'
127
- self.jpspsNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpsps/2024-11-01/jpsps_cor'
128
- self.jptoiNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jptoi/2024-11-01/jptoi_cor'
129
- self.jptooPstNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-pst/2024-11-01/jptoo-pst_cor'
130
- self.jptooToaNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-toa/2024-11-01/jptoo-toa_cor'
131
- self.jptooTonNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-ton/2024-11-01/jptoo-ton_cor'
132
- self.jptooTorNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-tor/2024-11-01/jptoo-tor_cor'
133
- self.jptooWtoNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jptoo-wto/2024-11-01/jptoo-wto_cor'
134
- self._namespaceMap = {
135
- "jpcrp-esr_cor": self.jpcrpEsrNamespace,
136
- "jpcrp-sbr_cor": self.jpcrpSbrNamespace,
137
- "jpcrp_cor": self.jpcrpNamespace,
138
- "jpctl_cor": self.jpctlNamespace,
139
- "jpdei_cor": self.jpdeiNamespace,
140
- "jpigp_cor": self.jpigpNamespace,
141
- "jplvh_cor": self.jplvhNamespace,
142
- "jppfs_cor": self.jppfsNamespace,
143
- "jpsps_cor": self.jpspsNamespace,
144
- "jpsps-esr_cor": self.jpspsEsrNamespace,
145
- "jpsps-sbr_cor": self.jpspsSbrNamespace,
146
- "jptoi_cor": self.jptoiNamespace,
147
- "jptoo-pst_cor": self.jptooPstNamespace,
148
- "jptoo-toa_cor": self.jptooToaNamespace,
149
- "jptoo-ton_cor": self.jptooTonNamespace,
150
- "jptoo-tor_cor": self.jptooPstNamespace,
151
- "jptoo-wto_cor": self.jptooWtoNamespace,
152
- }
102
+ self.namespaces = NamespaceConfig()
153
103
 
154
104
  # QNames
155
- self.accountingStandardsDeiQn = qname(self.jpdeiNamespace, 'AccountingStandardsDEI')
156
- self.assetsIfrsQn = qname(self.jpigpNamespace, 'AssetsIFRS')
157
- self.consolidatedOrNonConsolidatedAxisQn = qname(self.jppfsNamespace, 'ConsolidatedOrNonConsolidatedAxis')
158
- self.categoriesOfDirectorsAndOtherOfficersAxisQn = qname(self.jpcrpNamespace, 'CategoriesOfDirectorsAndOtherOfficersAxis')
159
- self.documentTypeDeiQn = qname(self.jpdeiNamespace, 'DocumentTypeDEI')
160
- self.executiveOfficersMemberQn = qname(self.jpcrpNamespace, 'ExecutiveOfficersMember')
161
- self.issuedSharesTotalNumberOfSharesEtcQn = qname(self.jpcrpNamespace, 'IssuedSharesTotalNumberOfSharesEtcTextBlock')
162
- self.jpcrpEsrFilingDateCoverPageQn = qname(self.jpcrpEsrNamespace, 'FilingDateCoverPage')
163
- self.jpcrpFilingDateCoverPageQn = qname(self.jpcrpNamespace, 'FilingDateCoverPage')
164
- self.jpspsFilingDateCoverPageQn = qname(self.jpspsNamespace, 'FilingDateCoverPage')
165
- self.nonConsolidatedMemberQn = qname(self.jppfsNamespace, "NonConsolidatedMember")
166
- self.ratioOfFemaleDirectorsAndOtherOfficersQn = qname(self.jpcrpNamespace, "RatioOfFemaleDirectorsAndOtherOfficers")
105
+ self.accountingStandardsDeiQn = qname(self.namespaces.jpdei, 'AccountingStandardsDEI')
106
+ self.assetsIfrsQn = qname(self.namespaces.jpigp, 'AssetsIFRS')
107
+ self.categoriesOfDirectorsAndOtherOfficersAxisQn = qname(self.namespaces.jpcrp, 'CategoriesOfDirectorsAndOtherOfficersAxis')
108
+ self.consolidatedOrNonConsolidatedAxisQn = qname(self.namespaces.jppfs, 'ConsolidatedOrNonConsolidatedAxis')
109
+ self.corporateGovernanceCompanyWithAuditAndSupervisoryCommitteeTextBlockQn = qname(self.namespaces.jpcrp, 'CorporateGovernanceCompanyWithAuditAndSupervisoryCommitteeTextBlock')
110
+ self.corporateGovernanceCompanyWithCorporateAuditorsTextBlockQn = qname(self.namespaces.jpcrp, 'CorporateGovernanceCompanyWithCorporateAuditorsTextBlock')
111
+ self.corporateGovernanceCompanyWithNominatingAndOtherCommitteesTextBlockQn = qname(self.namespaces.jpcrp, 'CorporateGovernanceCompanyWithNominatingAndOtherCommitteesTextBlock')
112
+ self.documentTypeDeiQn = qname(self.namespaces.jpdei, 'DocumentTypeDEI')
113
+ self.executiveOfficersMemberQn = qname(self.namespaces.jpcrp, 'ExecutiveOfficersMember')
114
+ self.issuedSharesTotalNumberOfSharesEtcQn = qname(self.namespaces.jpcrp, 'IssuedSharesTotalNumberOfSharesEtcTextBlock')
115
+ self.jpcrpEsrFilingDateCoverPageQn = qname(self.namespaces.jpcrpEsr, 'FilingDateCoverPage')
116
+ self.jpcrpFilingDateCoverPageQn = qname(self.namespaces.jpcrp, 'FilingDateCoverPage')
117
+ self.jpspsFilingDateCoverPageQn = qname(self.namespaces.jpsps, 'FilingDateCoverPage')
118
+ self.nonConsolidatedMemberQn = qname(self.namespaces.jppfs, "NonConsolidatedMember")
119
+ self.ratioOfFemaleDirectorsAndOtherOfficersQn = qname(self.namespaces.jpcrp, "RatioOfFemaleDirectorsAndOtherOfficers")
167
120
 
168
121
  self.coverItemRequirementsPath = Path(__file__).parent / "resources" / "cover-item-requirements.json"
169
122
  self.coverPageTitleQns = (
170
- qname(self.jpspsNamespace, "DocumentTitleAnnualSecuritiesReportCoverPage"),
171
- qname(self.jpcrpNamespace, "DocumentTitleCoverPage"),
172
- qname(self.jpcrpEsrNamespace, "DocumentTitleCoverPage"),
173
- qname(self.jpspsNamespace, "DocumentTitleCoverPage"),
123
+ qname(self.namespaces.jpsps, "DocumentTitleAnnualSecuritiesReportCoverPage"),
124
+ qname(self.namespaces.jpcrp, "DocumentTitleCoverPage"),
125
+ qname(self.namespaces.jpcrpEsr, "DocumentTitleCoverPage"),
126
+ qname(self.namespaces.jpsps, "DocumentTitleCoverPage"),
174
127
  )
175
128
  self.deiItems = tuple(
176
- qname(self.jpdeiNamespace, localName)
129
+ qname(self.namespaces.jpdei, localName)
177
130
  for localName in DEI_LOCAL_NAMES
178
131
  )
179
132
  self.deiRequirementsPath = Path(__file__).parent / "resources" / "dei-requirements.csv"
@@ -255,7 +208,9 @@ class PluginValidationDataExtension(PluginData):
255
208
  tocBuilder.addDocument(modelDocument)
256
209
 
257
210
  def qname(self, prefix: str, localName: str) -> QName:
258
- return qname(self._namespaceMap[prefix], localName)
211
+ ns = self.namespaces.get(prefix)
212
+ assert ns is not None, f"Unknown namespace prefix: {prefix}"
213
+ return qname(ns, localName)
259
214
 
260
215
  @lru_cache(1)
261
216
  def isCorporateForm(self, modelXbrl: ModelXbrl) -> bool:
@@ -265,7 +220,7 @@ class PluginValidationDataExtension(PluginData):
265
220
  return formType.isCorporateForm
266
221
 
267
222
  def isCorporateReport(self, modelXbrl: ModelXbrl) -> bool:
268
- return self.jpcrpNamespace in modelXbrl.namespaceDocs
223
+ return self.namespaces.jpcrp in modelXbrl.namespaceDocs
269
224
 
270
225
  def isExtensionUri(self, uri: str, modelXbrl: ModelXbrl) -> bool:
271
226
  if uri.startswith(modelXbrl.uriDir):
@@ -7,7 +7,9 @@ from typing import Iterable
7
7
 
8
8
  from collections import defaultdict
9
9
  from jaconv import jaconv
10
+ from lxml.etree import _Element
10
11
 
12
+ from arelle import XbrlConst
11
13
  from arelle.ModelDocument import ModelDocument
12
14
  from arelle.ModelObject import ModelObject
13
15
  from arelle.typing import TypeGetText
@@ -97,6 +99,13 @@ TOC_NUMBER_SETS = {
97
99
  SHALLOWEST_LEVEL = min(TOC_NUMBER_SETS.keys())
98
100
  DEEPEST_LEVEL = max(TOC_NUMBER_SETS.keys())
99
101
 
102
+ PROHIBITED_BETWEEN_TAGS = frozenset({
103
+ XbrlConst.qnXhtmlDel.localName,
104
+ XbrlConst.qnXhtmlImg.localName,
105
+ XbrlConst.qnXhtmlDel.clarkNotation,
106
+ XbrlConst.qnXhtmlImg.clarkNotation,
107
+ })
108
+
100
109
 
101
110
  class TableOfContentsBuilder:
102
111
  _currentDocument: ModelDocument | None
@@ -230,44 +239,151 @@ class TableOfContentsBuilder:
230
239
  # First or new document, open document.
231
240
  if self._currentDocument is None:
232
241
  self._openDocument(elt.document)
233
- text = elt.text or ""
234
- openIndex = -1
235
- closeIndex = -1
236
- if "【" in text:
237
- openIndex = text.index("【") + 1
238
- # EDINET.EC2004E: Corner brackets (【) must not overlap.
239
- if "" in text[openIndex:]:
240
- self._validations.append(Validation.error(
241
- codes='EDINET.EC2004E',
242
- msg=_("The opening bracket (【) is repeated. "
243
- "File name: '%(path)s' (line %(line)s). "
244
- "When viewed in a browser, it is not possible to display "
245
- "more than one table of contents item on one line. Please "
246
- "delete the brackets (【) in the relevant file."),
247
- path=elt.document.basename,
248
- line=elt.sourceline,
249
- modelObject=elt,
250
- ))
251
- if "】" in text:
252
- closeIndex = text.index("】") - 1
253
- if openIndex >= 0:
254
- if closeIndex > openIndex:
255
- number = text[:openIndex - 1].strip()
256
- label = text[openIndex:closeIndex + 1]
257
- self._tocSequence.append((number, label, elt))
258
- self._tocEntryCount += 1
242
+
243
+ number, label, tail, eltsInLabel, eltsBetweenNumAndLabel = self._getTextParts(elt)
244
+
245
+ textValue = ''.join(elt.textNodes())
246
+ if (
247
+ (label is None and ('' in textValue or '】' in textValue)) or
248
+ (tail is not None and ('' in tail or '】' in tail))
249
+ ):
250
+ self._validations.append(Validation.error(
251
+ codes='EDINET.EC2011E',
252
+ msg=_("\"【\" or \"】\" is used in the text. "
253
+ "File name: '%(path)s' (line %(line)s). "
254
+ "Corner brackets (【】) cannot be used in the main text "
255
+ "except for the table of contents. Please delete the "
256
+ "corner brackets (【】) in the relevant file."),
257
+ path=elt.document.basename,
258
+ line=elt.sourceline,
259
+ modelObject=elt,
260
+ ))
261
+
262
+ if label is None:
263
+ return
264
+
265
+ if len(eltsInLabel) > 0:
266
+ self._validations.append(Validation.error(
267
+ codes='EDINET.EC2008E',
268
+ msg=_("The table of contents label contains HTML tags. "
269
+ "File name: '%(path)s' (line %(line)s). "
270
+ "HTML tags are not allowed in table of contents labels. "
271
+ "Please remove the HTML tags from the relevant file."),
272
+ path=elt.document.basename,
273
+ line=elt.sourceline,
274
+ modelObject=elt,
275
+ ))
276
+
277
+ if any(
278
+ e.tag in PROHIBITED_BETWEEN_TAGS
279
+ for e in eltsBetweenNumAndLabel
280
+ ):
281
+ self._validations.append(Validation.error(
282
+ codes='EDINET.EC2009E',
283
+ msg=_("An invalid tag is used between the table of contents number "
284
+ "and the table of contents item. "
285
+ "File name: '%(path)s' (line %(line)s). "
286
+ "Please delete the tag (\"del\" or \"img\") used between the "
287
+ "table of contents number and the table of contents item of "
288
+ "the relevant file."),
289
+ path=elt.document.basename,
290
+ line=elt.sourceline,
291
+ modelObject=elt,
292
+ ))
293
+
294
+ if '【' in label[1:]:
295
+ self._validations.append(Validation.error(
296
+ codes='EDINET.EC2004E',
297
+ msg=_("The opening bracket (【) is repeated. "
298
+ "File name: '%(path)s' (line %(line)s). "
299
+ "When viewed in a browser, it is not possible to display "
300
+ "more than one table of contents item on one line. Please "
301
+ "delete the brackets (【) in the relevant file."),
302
+ path=elt.document.basename,
303
+ line=elt.sourceline,
304
+ modelObject=elt,
305
+ ))
306
+
307
+ if '】' not in label:
308
+ # EDINET.EC2007E: The table of contents entries must be enclosed in square brackets (】).
309
+ self._validations.append(Validation.error(
310
+ codes='EDINET.EC2007E',
311
+ msg=_("The table of contents entry is not closed with '】'. "
312
+ "File name: '%(path)s' (line %(line)s). "
313
+ "Add a closing bracket (】) to match the open bracket (【) "
314
+ "in the table of contents entry for the file in question."),
315
+ path=elt.document.basename,
316
+ line=elt.sourceline,
317
+ modelObject=elt,
318
+ ))
319
+
320
+ self._tocSequence.append((number, label, elt))
321
+ self._tocEntryCount += 1
322
+
323
+ def _getTextParts(
324
+ self,
325
+ elt: ModelObject
326
+ ) -> tuple[str, str | None, str | None, list[ModelObject], list[ModelObject]]:
327
+ """
328
+ Determines the TOC number, label, and tail of a given element (if set correctly)
329
+ based on the text nodes directly beneath the element.
330
+ Also captures misplaced elements in provided lists for error handling.
331
+ """
332
+ eltsInLabel = []
333
+ eltsBetweenNumAndLabel = []
334
+ textParts = [(None, elt.text)] + [
335
+ (child, child.tail)
336
+ for child in elt.iterchildren()
337
+ ]
338
+
339
+ number = ''
340
+ label = None
341
+ tail = None
342
+ while len(textParts) > 0:
343
+ textElt, text = textParts.pop(0)
344
+
345
+ # If we're iterating over an element, check if it's misplaced
346
+ if textElt is not None:
347
+ if number and label is None:
348
+ eltsBetweenNumAndLabel.append(textElt)
349
+ if label is not None and '】' not in label and tail is None:
350
+ eltsInLabel.append(textElt)
351
+
352
+ # If no text, move on
353
+ if not text:
354
+ continue
355
+
356
+ if label is None:
357
+ # We're building the number
358
+ start, sep, end = text.partition('【')
359
+ if sep:
360
+ number += start
361
+ label = sep # Start the label
362
+ # Process the remainder of this text node next
363
+ textParts.insert(0, (None, end))
364
+ else:
365
+ number += start
366
+ elif tail is None:
367
+ # We're building the label
368
+ start, sep, end = text.partition('】')
369
+ if sep:
370
+ label += start + sep
371
+ tail = '' # Start the tail
372
+ # Process the remainder of this text node next
373
+ textParts.insert(0, (None, end))
374
+ else:
375
+ label += start
259
376
  else:
260
- # EDINET.EC2007E: The table of contents entries must be enclosed in square brackets (】).
261
- self._validations.append(Validation.error(
262
- codes='EDINET.EC2007E',
263
- msg=_("The table of contents entry is not closed with '】'. "
264
- "File name: '%(path)s' (line %(line)s). "
265
- "Add a closing bracket () to match the open bracket (【) "
266
- "in the table of contents entry for the file in question."),
267
- path=elt.document.basename,
268
- line=elt.sourceline,
269
- modelObject=elt,
270
- ))
377
+ # We're building the tail
378
+ tail += text
379
+
380
+ return (
381
+ number.strip(),
382
+ label.strip() if label else label,
383
+ tail.strip() if tail else tail,
384
+ eltsInLabel,
385
+ eltsBetweenNumAndLabel,
386
+ )
271
387
 
272
388
  def _isFloating(self) -> bool:
273
389
  return self._floatingLevel is not None or self._currentLevel >= DEEPEST_LEVEL
@@ -459,7 +575,6 @@ class TableOfContentsBuilder:
459
575
  if not self._isFloating():
460
576
  # EDINET.EC2003E: The table of contents must be no longer than 384 bytes
461
577
  # (equivalent to 128 full-width characters).
462
- b = label.encode('utf-8')
463
578
  if len(label.encode('utf-8')) > 384:
464
579
  yield Validation.error(
465
580
  codes='EDINET.EC2003E',
@@ -473,19 +588,6 @@ class TableOfContentsBuilder:
473
588
  modelObject=elt,
474
589
  )
475
590
 
476
- # EDINET.EC2008E: Table of contents entries must not contain HTML tags.
477
- if len(elt) > 0:
478
- yield Validation.error(
479
- codes='EDINET.EC2008E',
480
- msg=_("The table of contents contains HTML tags. "
481
- "File name: '%(path)s' (line %(line)s). "
482
- "HTML tags are not allowed in table of contents entries. "
483
- "Please remove the HTML tags from the relevant file."),
484
- path=elt.document.basename,
485
- line=elt.sourceline,
486
- modelObject=elt,
487
- )
488
-
489
591
  # Uncomment for debugging output of TOC structure.
490
592
  # print(
491
593
  # f'{" " if self._floatingLevel is not None else "|"}\t' * (self._currentLevel - 1) +
@@ -84,7 +84,7 @@ def rule_EC8012W(
84
84
  EDINET.EC8012W: If a main financial statement element is present, a calculation linkbase file must be present.
85
85
  """
86
86
  if not any(
87
- fact.qname.namespaceURI == pluginData.jppfsNamespace
87
+ fact.qname.namespaceURI == pluginData.namespaces.jppfs
88
88
  for fact in val.modelXbrl.facts
89
89
  ):
90
90
  return