{"id":14559,"date":"2025-04-02T12:04:31","date_gmt":"2025-04-02T03:04:31","guid":{"rendered":"https:\/\/www.sambuichi.jp\/?p=14559"},"modified":"2025-04-02T13:52:08","modified_gmt":"2025-04-02T04:52:08","slug":"xbrl-gl-palette-taxonomy-parser","status":"publish","type":"post","link":"https:\/\/www.sambuichi.jp\/?p=14559&lang=en","title":{"rendered":"XBRL GL Palette Taxonomy Parser"},"content":{"rendered":"<p>Views: 61<\/p><div id=\"header\">\n<h1>XBRL GL Palette Taxonomy Parser<\/h1>\n<div class=\"details\">\n<span id=\"author\" class=\"author\">Author: ChatGPT with editor SAMBUICHI, Nobuyuki<\/span><br \/>\n<span id=\"revdate\">2025-04-02<\/span>\n<\/div>\n<\/div>\n<div id=\"content\">\n<div id=\"preamble\">\n<div class=\"sectionbody\">\n<div class=\"quoteblock abstract\">\n<blockquote><p>\nThis article introduces a Python-based parser to extract a logical hierarchical model (LHM) structure from the XBRL GL taxonomy. The parser also retrieves multilingual labels and documentation from the label linkbase. The output is a structured CSV file useful for semantic analysis, implementation, and documentation.\n<\/p><\/blockquote>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_motivation\">1. Motivation<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The XBRL Global Ledger (XBRL GL) Palette taxonomy defines an XML-based standard for representing accounting and audit data. However, its hierarchical structure\u2014especially when modularised\u2014can be difficult to navigate, particularly when multilingual labels are defined using labelArc.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>This script provides a bridge between raw schema definitions and a friendly CSV format enriched with English and localised labels (e.g., Japanese).<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_what_this_script_does\">2. What This Script Does<\/h2>\n<div class=\"sectionbody\">\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Loads all <code>gl-<strong><strong>*.xsd<\/code> and <code>gl-<\/strong><\/strong>*-content.xsd<\/code> schemas<\/p>\n<\/li>\n<li>\n<p>Detects <code>complexType<\/code> definitions with <code>anyType<\/code> base as <strong>tuples<\/strong><\/p>\n<\/li>\n<li>\n<p>Extracts all element names, types, and cardinality<\/p>\n<\/li>\n<li>\n<p>Extracts labels from <code>label.xml<\/code> and <code>label-ja.xml<\/code> via <code>labelArc<\/code><\/p>\n<\/li>\n<li>\n<p>Supports fallback resolution of label identifiers<\/p>\n<\/li>\n<li>\n<p>Outputs a fully annotated CSV representing the logical structure defined by complexType and complexContent\/xs:sequence declarations in the schema<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_requirements\">3. Requirements<\/h2>\n<div class=\"sectionbody\">\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Python 3.7 or later<\/p>\n<\/li>\n<li>\n<p><code>lxml<\/code> library:<\/p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-shell\" data-lang=\"shell\">pip install lxml<\/code><\/pre>\n<\/div>\n<\/div>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_usage_instructions\">4. Usage Instructions<\/h2>\n<div class=\"sectionbody\">\n<div class=\"sect2\">\n<h3 id=\"_command_line_execution\">4.1. Command-Line Execution<\/h3>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-shell\" data-lang=\"shell\">python xbrl_gl_label_parser.py --base-dir XBRL-GL-PWD-2016-12-01<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_optional_parameters\">4.2. Optional Parameters<\/h3>\n<table class=\"tableblock frame-all grid-all stretch\">\n<colgroup>\n<col style=\"width: 25%;\">\n<col style=\"width: 75%;\">\n<\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">Argument<\/th>\n<th class=\"tableblock halign-left valign-top\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>--base-dir<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><strong>(Required)<\/strong> Path to the root directory of your XBRL GL taxonomy<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>--palette<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Subdirectory name of the palette folder (default: <code>case-c-b-m-u-e-t-s<\/code>)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>--lang<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Language code for labels (default: <code>ja<\/code>). Accepts values like <code>en<\/code>, <code>ja<\/code>, etc.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>--debug<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Enable detailed debug logging<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>--trace<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Enable top-level trace output<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>--output<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Output CSV filename (default: XBRL_GL_Parsed_LHM_Structure.csv)<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_example_in_launch_json_for_vscode\">4.3. Example (in <code>launch.json<\/code> for VSCode)<\/h3>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-json\" data-lang=\"json\">\"args\": [\r\n  \"--base-dir\", \"XBRL-GL-PWD-2016-12-01\",\r\n  \"--palette\", \"case-c-b\",\r\n  \"--lang\", \"ja\",\r\n  \"--debug\",\r\n  \"--trace\",\r\n  \"--output\", \"XBRL_GL_case-c-b_Structure.csv\"\r\n]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_input_directory_structure\">5. Input Directory Structure<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Your XBRL GL taxonomy should be structured like this:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-tree\" data-lang=\"tree\">XBRL-GL-PWD-2016-12-01\/\r\n\u251c\u2500\u2500 gl\/\r\n\u2502   \u251c\u2500\u2500 cor\/\r\n\u2502   \u2502   \u251c\u2500\u2500 gl-cor-2016-12-01.xsd\r\n\u2502   \u2502   \u2514\u2500\u2500 lang\/\r\n\u2502   \u2502       \u251c\u2500\u2500 gl-cor-2016-12-01-label.xml\r\n\u2502   \u2502       \u2514\u2500\u2500 gl-cor-2016-12-01-label-ja.xml\r\n\u2502   \u251c\u2500\u2500 bus\/\r\n\u2502   \u251c\u2500\u2500 muc\/\r\n\u2502   \u2514\u2500\u2500 ...\r\n\u251c\u2500\u2500 gl\/plt\/case-c-b\/\r\n\u2502   \u251c\u2500\u2500 gl-cor-content-2016-12-01.xsd\r\n\u2502   \u2514\u2500\u2500 ...<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_output\">6. Output<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The script generates a CSV file:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code>Level,Element,Type,Path,isTuple,minOccurs,maxOccurs,BaseType,Label,Documentation,LocalLabel,LocalDocumentation\r\n1,accountingEntries,gl-cor:accountingEntriesComplexType,\/gl-cor:accountingEntries,True,1,unbounded,,Accounting Entries,Root for XBRL GL. No entry made here.,\u3010\u4f1a\u8a08\u4ed5\u8a33\u3011,XBRL GL\u306e\u30eb\u30fc\u30c8\u8981\u7d20\u3002 \u3053\u306e\u8981\u7d20\u306b\u306f\u30c7\u30fc\u30bf\u306f\u767b\u9332\u3055\u308c\u306a\u3044\u3002\r\n2,gl-cor:documentInfo,gl-cor:documentInfoComplexType,\/gl-cor:accountingEntries\/gl-cor:documentInfo,True,1,1,,Document Information,Parent for descriptive information about the accountingEntries section in which it is contained.,\u3010\u6587\u66f8\u60c5\u5831\u3011,\u3053\u306e\u4f1a\u8a08\u4ed5\u8a33\u306b\u95a2\u3059\u308b\u60c5\u5831\u306e\u89aa\u30bf\u30b0\u3002\r\n3,gl-cor:entriesType,gl-gen:entriesTypeItemType,\/gl-cor:accountingEntries\/gl-cor:documentInfo\/gl-cor:entriesType,False,1,1,xbrli:tokenItemType,Document Type,\"account: information to fill in a chart of accounts file.  \r\nbalance: the results of accumulation of a complete and validated list of entries for an account (or a list of account) in a specific period - sometimes called general ledger  \r\nentries: a list of individual accounting entries, which might be posted\/validated or nonposted\/validated   \r\njournal: a self-balancing (Dr = Cr) list of entries for a specific period including beginning balance for that period.  \r\nledger: a complete list of entries for a specific account (or list of accounts) for a specific period; note - debits do not have to equal credits.   \r\nassets: a listing of open receivables, payables, inventory, fixed assets or other information that can be extracted from but are not necessarily included as part of a journal entry.  \r\ntrialBalance: the self-balancing (Dr = Cr) result of accumulation of a complete and validated list of entries for the entity in a complete list of accounts in a specific period. <\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Google Drive<br \/>\n<a href=\"https:\/\/drive.google.com\/file\/d\/1DgwxLU9P7NXDcz2MbVLJ3jIAa6Cz5Q4u\/view?usp=sharing\">XBRL_GL_Parsed_LHM_Structure.csv<\/a><\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_csv_columns\">6.1. CSV Columns<\/h3>\n<table class=\"tableblock frame-all grid-all stretch\">\n<colgroup>\n<col style=\"width: 25%;\">\n<col style=\"width: 75%;\">\n<\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">Column<\/th>\n<th class=\"tableblock halign-left valign-top\">Meaning<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>Level<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Depth level in the hierarchy<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>Element<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">QName (e.g. <code>gl-cor:uniqueID<\/code>)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>Type<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Schema type (e.g. <code>gl-cor:uniqueIDItemType<\/code>)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>Path<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Hierarchy path<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>isTuple<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">True if the type is a tuple<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>minOccurs<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Minimum cardinality<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>maxOccurs<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Maximum cardinality<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>BaseType<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Underlying XBRL base type (e.g. <code>xbrli:stringItemType<\/code>)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>Label<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">English label from <code>label.xml<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>Documentation<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">English description<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>LocalLabel<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Localised label (e.g. Japanese)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>LocalDocumentation<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Localised description<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_notes\">6.2. Notes<\/h3>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Tuples are determined by checking if <code>complexType<\/code> is based on <code>anyType<\/code>.<\/p>\n<\/li>\n<li>\n<p>Localised labels (e.g. <code>ja<\/code>) can be extracted by using <code>--lang ja<\/code>.<\/p>\n<\/li>\n<li>\n<p>The script is modular and extensible to support other taxonomies.<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_related_links\">7. Related Links<\/h2>\n<div class=\"sectionbody\">\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a href=\"https:\/\/www.xbrl.org\/the-standard\/what\/global-ledger\/\" class=\"bare\">https:\/\/www.xbrl.org\/the-standard\/what\/global-ledger\/<\/a> \u2014 XBRL Global Ledger: Transactional Reporting<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/specifications.xbrl.org\/spec-group-index-xbrl-gl.html\" class=\"bare\">https:\/\/specifications.xbrl.org\/spec-group-index-xbrl-gl.html<\/a> \u2014 XBRL Specification<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.xbrl.org\/int\/gl\/2015-03-25\/GLTFTA-REC-2015-03-25.html\" class=\"bare\">https:\/\/www.xbrl.org\/int\/gl\/2015-03-25\/GLTFTA-REC-2015-03-25.html<\/a> \u2014 XBRL GL Taxonomy Framework Technical Architecture 2015<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_questions_or_feedback\">8. Questions or Feedback?<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>If you have suggestions, encounter issues, or need support adapting the script to other taxonomies, feel free to comment on this page. Contributions and improvements are always welcome.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>You can also fork the script or submit enhancements by referencing the source file:<br \/>\nSOURCE<br \/>\nGoogle Drive <a href=\"https:\/\/drive.google.com\/file\/d\/1rC4xIVzt1zOTT4q6rNmjggmUHcmHX9ug\/view?usp=sharing\">xbrl_gl_palette_parser.py<\/a><\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\" style=\"overflow-x: auto; white-space: pre; height: 700px;\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">#!\/usr\/bin\/env python3\r\n# coding: utf-8\r\n\"\"\"\r\nxbrl_gl_palette_parser.py\r\nParses XBRL Global Ledger (XBRL GL) taxonomy and extracts labeled hierarchical element structures into CSV format.\r\n\r\nDesigned by SAMBUICHI, Nobuyuki (Sambuichi Professional Engineers Office)\r\nWritten by SAMBUICHI, Nobuyuki (Sambuichi Professional Engineers Office)\r\n\r\nCreation Date: 2025-04-02\r\n\r\nMIT License\r\n\r\n(c) 2025 SAMBUICHI, Nobuyuki (Sambuichi Professional Engineers Office)\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and\/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n\r\nUsage:\r\n    python xbrl_gl_label_parser.py --base-dir &lt;taxonomy-root-directory&gt; [--palette &lt;palette-subdir&gt;] [--lang &lt;language-code&gt;] [--debug] [--trace] [--output &lt;filename&gt;]\r\n\r\nArguments:\r\n    --base-dir     Required. Path to the root of the XBRL GL taxonomy (e.g., XBRL-GL-PWD-2016-12-01).\r\n    --palette      Optional. Subdirectory name of the palette folder (default: case-c-b-m-u-e-t-s).\r\n    --lang         Optional. Language code for multilingual labels. Default is 'ja'.\r\n    --debug        Optional. Enables detailed debug output.\r\n    --trace        Optional. Enables trace messages.\r\n    --output       Optional. Filename for the output CSV (default: XBRL_GL_Parsed_LHM_Structure.csv).\r\n\r\nExample:\r\n    python xbrl_gl_label_parser.py --base-dir XBRL-GL-PWD-2016-12-01 --palette case-c-b --lang ja --debug --output my_labels.csv\r\n\"\"\"\r\n\r\nimport lxml.etree as ET\r\nimport os\r\nimport re\r\nimport csv\r\nimport argparse\r\nfrom collections import defaultdict\r\n\r\nTRACE = True\r\nDEBUG = True\r\n\r\ndef trace_print(text):\r\n    if TRACE or DEBUG:\r\n        print(text)\r\n\r\ndef debug_print(text):\r\n    if DEBUG:\r\n        print(text)\r\n\r\n# Helper to clean label IDs\r\ndef clean_label_id(label_id):\r\n    label_id = re.sub(r\"^label_\", \"\", label_id)\r\n    label_id = re.sub(r\"(_lbl|_\\d+(_\\d+)?)$\", \"\", label_id)\r\n    return label_id\r\n\r\n# Argument parser for base directory\r\nparser = argparse.ArgumentParser(description=\"Parse XBRL-GL schemas and extract labeled hierarchy.\")\r\nparser.add_argument(\"--palette\", type=str, default=\"case-c-b-m-u-e-t-s\", help=\"Palette subdirectory under gl\/plt\/ (e.g. case-c-b or case-c-b-m-u-e-t-s)\")\r\nparser.add_argument(\"--base-dir\", type=str, required=True, help=\"Base directory path to XBRL GLtaxonomy, e.g. XBRL-GL-PWD-2016-12-01\")\r\nparser.add_argument(\"--debug\", action=\"store_true\", help=\"Enable debug output\")\r\nparser.add_argument(\"--trace\", action=\"store_true\", help=\"Enable trace output\")\r\nparser.add_argument(\"--lang\", type=str, default=\"ja\", help=\"Language code for local labels (e.g. 'ja', 'en')\")\r\nparser.add_argument(\"--output\", type=str, default=\"XBRL_GL_Parsed_LHM_Structure.csv\", help=\"Output CSV filename\")\r\n\r\nargs = parser.parse_args()\r\nbase_dir = args.base_dir\r\npalette = args.palette\r\nDEBUG = args.debug\r\nTRACE = args.trace\r\nLANG = args.lang\r\noutput_filename = args.output\r\n\r\nxsd_path = os.path.join(base_dir, f\"gl\/plt\/{palette}\/gl-cor-content-2016-12-01.xsd\")\r\nnamespaces = {\r\n    'xs': \"http:\/\/www.w3.org\/2001\/XMLSchema\",\r\n    'xbrli': \"http:\/\/www.xbrl.org\/2003\/instance\"\r\n}\r\nmodules = ['gen', 'cor', 'bus', 'muc', 'usk', 'ehm', 'taf', 'srcd']\r\n\r\n# Load base schemas and build type maps\r\nelement_type_map = {}\r\ntype_base_map = {}\r\ntype_base_lookup = {}\r\ncomplex_type_lookup = {}\r\nfor mod in modules:\r\n    path = os.path.join(base_dir, f\"gl\/{mod}\/gl-{mod}-2016-12-01.xsd\")\r\n    if os.path.exists(path):\r\n        tree = ET.parse(path)\r\n        root = tree.getroot()\r\n        for el in root.xpath(\"\/\/xs:element\", namespaces=namespaces):\r\n            name, type_ = el.get(\"name\"), el.get(\"type\")\r\n            if name and type_:\r\n                # debug_print(f\"gl-{mod}:{name}\")\r\n                element_type_map[f\"gl-{mod}:{name}\"] = type_\r\n        for tdef in root.xpath(\"\/\/xs:simpleType | \/\/xs:complexType\", namespaces=namespaces):\r\n            name = tdef.get(\"name\")\r\n            if name:\r\n                # debug_print(name)\r\n                complex_type_lookup[name] = tdef\r\n                restriction = tdef.find(\".\/\/xs:restriction\", namespaces)\r\n                if restriction is not None:\r\n                    base = restriction.get(\"base\")\r\n                    if base:\r\n                        type_base_map[name] = base\r\n                        type_base_lookup[name] = base\r\n                extension = tdef.find(\".\/\/xs:extension\", namespaces)\r\n                if extension is not None:\r\n                    base = extension.get(\"base\")\r\n                    if base:\r\n                        type_base_map[name] = base\r\n                        type_base_lookup[name] = base\r\n\r\n# Load content schemas\r\ncontent_roots = {}\r\nfor mod in modules:\r\n    path = os.path.join(base_dir, f\"gl\/plt\/{palette}\/gl-{mod}-content-2016-12-01.xsd\")\r\n    if os.path.exists(path):\r\n        content_roots[mod] = ET.parse(path).getroot()\r\n        tree = ET.parse(path)\r\n        root = tree.getroot()\r\n        for el in root.xpath(\"\/\/xs:element\", namespaces=namespaces):\r\n            name, type_ = el.get(\"name\"), el.get(\"type\")\r\n            if name and type_:\r\n                # debug_print(f\"gl-{mod}:{name}\")\r\n                element_type_map[f\"gl-{mod}:{name}\"] = type_\r\n        for tdef in root.xpath(\"\/\/xs:simpleType | \/\/xs:complexType\", namespaces=namespaces):\r\n            name = tdef.get(\"name\")\r\n            if name:\r\n                # debug_print(name)\r\n                complex_type_lookup[name] = tdef\r\n                restriction = tdef.find(\".\/\/xs:restriction\", namespaces)\r\n                if restriction is not None:\r\n                    base = restriction.get(\"base\")\r\n                    if base:\r\n                        type_base_map[name] = base\r\n                        type_base_lookup[name] = base\r\n                extension = tdef.find(\".\/\/xs:extension\", namespaces)\r\n                if extension is not None:\r\n                    base = extension.get(\"base\")\r\n                    if base:\r\n                        type_base_map[name] = base\r\n                        type_base_lookup[name] = base\r\n\r\n# Load content schemas\r\ncontent_roots = {}\r\nfor mod in modules:\r\n    path = os.path.join(base_dir, f\"gl\/plt\/{palette}\/gl-{mod}-content-2016-12-01.xsd\")\r\n    if os.path.exists(path):\r\n        content_roots[mod] = ET.parse(path).getroot()\r\n\r\n# Load label linkbases (EN and JA)\r\ndef load_labels(mod, lang):\r\n    label_map = defaultdict(dict)\r\n    suffix = \"label.xml\" if lang == \"en\" else f\"label-{lang}.xml\"\r\n    path = os.path.join(base_dir, f\"gl\/{mod}\/lang\/gl-{mod}-2016-12-01-{suffix}\")\r\n    if not os.path.exists(path):\r\n        return label_map\r\n    tree = ET.parse(path)\r\n    root = tree.getroot()\r\n    ns = {'link': 'http:\/\/www.xbrl.org\/2003\/linkbase', 'xlink': 'http:\/\/www.w3.org\/1999\/xlink'}\r\n\r\n    locator_map = {}\r\n    label_resources = {}\r\n\r\n    # Map locator label -&gt; href target\r\n    for loc in root.xpath(\".\/\/link:loc\", namespaces=ns):\r\n        label_id = loc.get(\"{http:\/\/www.w3.org\/1999\/xlink}label\")\r\n        href = loc.get(\"{http:\/\/www.w3.org\/1999\/xlink}href\")\r\n        _, anchor = href.split(\"#\")\r\n        if label_id and href and '#' in href:\r\n            locator_map[label_id] = anchor\r\n\r\n    # Collect label resources\r\n    for label in root.xpath(\".\/\/link:label\", namespaces=ns):\r\n        label_id = label.get(\"{http:\/\/www.w3.org\/1999\/xlink}label\")\r\n        role = label.get(\"{http:\/\/www.w3.org\/1999\/xlink}role\")\r\n        label_text = label.text.strip() if label.text else \"\"\r\n        if label_id not in label_resources:\r\n            label_resources[label_id] = {}\r\n        if role.endswith(\"label\"):\r\n            label_resources[label_id][\"label\"] = label_text\r\n        elif role.endswith(\"documentation\"):\r\n            label_resources[label_id][\"documentation\"] = label_text\r\n\r\n\r\n    # Resolve labelArcs and map labels to href anchors\r\n    for arc in root.xpath(\".\/\/link:labelArc\", namespaces=ns):\r\n        from_label = arc.get(\"{http:\/\/www.w3.org\/1999\/xlink}from\")\r\n        to_label = arc.get(\"{http:\/\/www.w3.org\/1999\/xlink}to\")\r\n        href = locator_map.get(from_label)\r\n        label = label_resources.get(to_label)\r\n        if href and label is not None:\r\n            role = label.get(\"{http:\/\/www.w3.org\/1999\/xlink}role\")\r\n            if lang == \"en\":\r\n                if \"label\" in label:\r\n                    label_map[href][\"label\"] = label[\"label\"]\r\n                if \"documentation\" in label:\r\n                    label_map[href][\"documentation\"] = label[\"documentation\"]\r\n            elif lang != \"en\":\r\n                if \"label\" in label:\r\n                    label_map[href][f\"label_{lang}\"] = label[\"label\"]\r\n                if \"documentation\" in label:\r\n                    label_map[href][f\"documentation_{lang}\"] = label[\"documentation\"]\r\n\r\n    return label_map\r\n\r\nlabel_texts = defaultdict(dict)\r\nfor mod in modules:\r\n    labels = [load_labels(mod, \"en\")]\r\n    if LANG != \"en\":\r\n        labels.append(load_labels(mod, LANG))\r\n    for label_map in labels:\r\n        for k, v in label_map.items():\r\n            label_texts[k].update(v)\r\n\r\n# Helpers\r\ndef is_tuple_type(complex_type_element):\r\n    if complex_type_element is None:\r\n        return False\r\n    if complex_type_element.find(\"xs:simpleContent\", namespaces) is not None:\r\n        return False\r\n    complex_content = complex_type_element.find(\"xs:complexContent\", namespaces)\r\n    if complex_content is not None:\r\n        for tag in [\"xs:restriction\", \"xs:extension\"]:\r\n            inner = complex_content.find(tag, namespaces)\r\n            if inner is not None:\r\n                base = inner.get(\"base\")\r\n                return base == \"anyType\"\r\n    return False\r\n\r\ndef resolve_base_type(type_str):\r\n    type_name = type_str.split(\":\")[-1]\r\n    return type_base_lookup.get(type_name, \"\")\r\n\r\n# Traversal\r\nrecords = []\r\ndef process_sequence(seq, _type, module, path, base, namespaces):\r\n    debug_print(f\" - Processing xs:sequence in path: \/{path}\")\r\n    for el in seq.findall(\"xs:element\", namespaces=namespaces):\r\n        ref = el.get(\"ref\")\r\n        name = el.get(\"name\")\r\n        el_name = ref or name\r\n        el_type = element_type_map.get(el_name, \"\")\r\n        type_name = el_type.split(\":\")[-1]\r\n        complex_type = complex_type_lookup.get(type_name)\r\n        is_tuple = False\r\n        if complex_type is not None:\r\n            is_tuple = is_tuple_type(complex_type)\r\n\r\n        path_str = f\"gl-{module}:{path}\" if \"gl-\" not in path else path\r\n        new_path = f\"{path_str}\/{el_name}\"\r\n        min_occurs = el.get(\"minOccurs\", \"1\")\r\n        max_occurs = el.get(\"maxOccurs\", \"1\")\r\n        base_type = resolve_base_type(el_type) if not is_tuple and el_type else \"\"\r\n        level = 1 + new_path.count(\"\/\")\r\n\r\n        raw_key = el_name.replace(\":\", \"_\")\r\n        label_info = label_texts.get(raw_key, {})\r\n\r\n        record = {\r\n            \"Level\": level,\r\n            \"Element\": el_name,\r\n            \"Type\": el_type,\r\n            \"Path\": f\"\/{new_path}\",\r\n            \"isTuple\": is_tuple,\r\n            \"minOccurs\": min_occurs,\r\n            \"maxOccurs\": max_occurs,\r\n            \"BaseType\": base_type,\r\n            \"Label\": label_info.get(\"label\", \"\"),\r\n            \"Documentation\": label_info.get(\"documentation\", \"\"),\r\n            \"LocalLabel\": label_info.get(\"label_ja\", \"\"),\r\n            \"LocalDocumentation\": label_info.get(\"documentation_ja\", \"\")\r\n        }\r\n        records.append(record)\r\n        if not el_type:\r\n            continue\r\n        type_name = el_type.split(\":\")[-1]\r\n        if is_tuple:\r\n            mod = el_type.split(\":\")[0][3:]\r\n            for _path in [\r\n                os.path.join(base_dir, f\"gl\/{mod}\/gl-{mod}-2016-12-01.xsd\"),\r\n                os.path.join(base_dir, f\"gl\/plt\/{palette}\/gl-{mod}-content-2016-12-01.xsd\")\r\n            ]:\r\n                if os.path.exists(_path):\r\n                    tree = ET.parse(_path)\r\n                    nested = tree.xpath(f\".\/\/xs:complexType[@name='{type_name}']\", namespaces=namespaces)\r\n                    if nested:\r\n                        walk_complex_type(type_name, nested[0], \"tuple\", mod, new_path, namespaces)\r\n                        break\r\n\r\ndef walk_complex_type(name, element, _type, module, path, namespaces):\r\n    if \":\" not in path:\r\n        trace_print(f\"Walking {_type} type '{name}' at path: \/gl-{module}:{path}\")\r\n    else:\r\n        trace_print(f\"Walking {_type}: '{name}' at path: \/{path}\")\r\n    sequence = element.find(\"xs:sequence\", namespaces)\r\n    if sequence is not None:\r\n        process_sequence(sequence, _type, module, path, name, namespaces)\r\n        return\r\n    complex_content = element.find(\"xs:complexContent\", namespaces)\r\n    if complex_content is not None:\r\n        for tag in [\"xs:restriction\", \"xs:extension\"]:\r\n            inner = complex_content.find(tag, namespaces)\r\n            if inner is not None:\r\n                base = inner.get(\"base\")\r\n                seq = inner.find(\"xs:sequence\", namespaces)\r\n                if seq is not None:\r\n                    process_sequence(seq, _type, module, path, base, namespaces)\r\n                return\r\n\r\n# Start with root complexType\r\nroot = content_roots[\"cor\"]\r\ncomplex_type_list = root.xpath(\".\/\/xs:complexType[@name='accountingEntriesComplexType']\", namespaces=namespaces)\r\nif complex_type_list:\r\n    href = \"gl-cor_accountingEntries\"\r\n    record = {\r\n        \"Level\": 1,\r\n        \"Element\": \"accountingEntries\",\r\n        \"Type\": \"gl-cor:accountingEntriesComplexType\",\r\n        \"Path\": \"\/gl-cor:accountingEntries\",\r\n        \"isTuple\": True,\r\n        \"minOccurs\": \"1\",\r\n        \"maxOccurs\": \"unbounded\",\r\n        \"BaseType\": \"\",\r\n        \"Label\": label_texts[href].get(\"label\", \"\"),\r\n        \"Documentation\": label_texts[href].get(\"documentation\", \"\"),\r\n        \"LocalLabel\": label_texts[href].get(\"label_ja\", \"\"),\r\n        \"LocalDocumentation\": label_texts[href].get(\"documentation_ja\", \"\")\r\n    }\r\n    records.append(record)\r\n    \r\n    walk_complex_type(\"accountingEntriesComplexType\", complex_type_list[0], \"tuple\", \"cor\", \"accountingEntries\", namespaces)\r\nelse:\r\n    print(\"\u274c Not found: accountingEntriesComplexType\")\r\n\r\n# Output to CSV\r\noutput_dir = \"XBRL-GL-2025\"\r\nos.makedirs(output_dir, exist_ok=True)\r\noutput_file = os.path.join(output_dir, output_filename)\r\n\r\nwith open(output_file, mode='w', newline='', encoding='utf-8-sig') as f:\r\n    if records:\r\n        writer = csv.DictWriter(f, fieldnames=records[0].keys())\r\n        writer.writeheader()\r\n        writer.writerows(records)\r\n    else:\r\n        print(\"\u26a0\ufe0f No records to write.\")\r\n\r\nprint(f\"\\n\u2705 Saved parsed structure to: {output_file}\")<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div id=\"footer\">\n<div id=\"footer-text\">\nLast updated 2025-04-02 13:44:01 +0900\n<\/div>\n<\/div>\n<div id=\"toc\" class=\"toc2\">\n<div id=\"toctitle\">Table of Contents<\/div>\n<ul class=\"sectlevel1\">\n<li><a href=\"#_motivation\">1. Motivation<\/a><\/li>\n<li><a href=\"#_what_this_script_does\">2. What This Script Does<\/a><\/li>\n<li><a href=\"#_requirements\">3. Requirements<\/a><\/li>\n<li><a href=\"#_usage_instructions\">4. Usage Instructions<\/a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#_command_line_execution\">4.1. Command-Line Execution<\/a><\/li>\n<li><a href=\"#_optional_parameters\">4.2. Optional Parameters<\/a><\/li>\n<li><a href=\"#_example_in_launch_json_for_vscode\">4.3. Example (in <code>launch.json<\/code> for VSCode)<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#_input_directory_structure\">5. Input Directory Structure<\/a><\/li>\n<li><a href=\"#_output\">6. Output<\/a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#_csv_columns\">6.1. CSV Columns<\/a><\/li>\n<li><a href=\"#_notes\">6.2. Notes<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#_related_links\">7. Related Links<\/a><\/li>\n<li><a href=\"#_questions_or_feedback\">8. Questions or Feedback?<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Views: 61 XBRL GL Palette Taxonomy Parser Author: ChatGPT with editor SAMBUICHI, Nobuyuki 2025-04-02 This arti [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":14541,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[17,66],"tags":[],"_links":{"self":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/14559"}],"collection":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=14559"}],"version-history":[{"count":14,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/14559\/revisions"}],"predecessor-version":[{"id":14587,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/14559\/revisions\/14587"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/media\/14541"}],"wp:attachment":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=14559"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=14559"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=14559"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}