Source code for nse_xbrl_parser.taxonomy.schema

"""
nse_xbrl_parser.taxonomy.schema

XSD Taxonomy Schema Parser (elements, types, substitution groups, period types).
"""
from __future__ import annotations

from typing import Any, Dict, List, Optional
from lxml import etree
from pydantic import BaseModel, Field

from ..utils.xml_utils import clean_xml_bytes, get_namespace, parse_xml_tree, strip_namespace

XSD_NS = "http://www.w3.org/2001/XMLSchema"
XBRLI_NS = "http://www.xbrl.org/2003/instance"


[docs] class SchemaElement(BaseModel): """Represents a concept element declared in an XBRL taxonomy schema (.xsd).""" name: str id: Optional[str] = None type: Optional[str] = None substitution_group: Optional[str] = None period_type: Optional[str] = None balance: Optional[str] = None is_abstract: bool = False is_nillable: bool = True target_namespace: Optional[str] = None @property def is_monetary(self) -> bool: return self.type is not None and "monetaryItemType" in self.type @property def is_shares(self) -> bool: return self.type is not None and "sharesItemType" in self.type
[docs] class TaxonomySchema(BaseModel): """Container for parsed taxonomy schemas.""" target_namespace: str = "" elements: Dict[str, SchemaElement] = Field(default_factory=dict)
[docs] @classmethod def from_xsd_content(cls, content: bytes | str) -> TaxonomySchema: """Parse an XSD file into a TaxonomySchema model.""" root = parse_xml_tree(content) tns = root.attrib.get("targetNamespace", "") elements: Dict[str, SchemaElement] = {} for elem in root.xpath("//xsd:element", namespaces={"xsd": XSD_NS}): name = elem.attrib.get("name") if not name: continue elem_id = elem.attrib.get("id") elem_type = elem.attrib.get("type") subst = elem.attrib.get("substitutionGroup") period = elem.attrib.get(f"{{{XBRLI_NS}}}periodType") or elem.attrib.get("periodType") balance = elem.attrib.get(f"{{{XBRLI_NS}}}balance") or elem.attrib.get("balance") is_abstract = elem.attrib.get("abstract", "false").lower() == "true" is_nillable = elem.attrib.get("nillable", "true").lower() == "true" schema_elem = SchemaElement( name=name, id=elem_id, type=elem_type, substitution_group=subst, period_type=period, balance=balance, is_abstract=is_abstract, is_nillable=is_nillable, target_namespace=tns, ) elements[name] = schema_elem return cls(target_namespace=tns, elements=elements)