Task 827: .XRBL File Format

Task 827: .XRBL File Format

1. List of Properties of the .XBRL File Format Intrinsic to Its File System

The .XBRL file format is an XML-based standard for business reporting, primarily used for financial data. The properties intrinsic to the format, which define its structure and identification in file systems, are as follows:

  • File extension: .xbrl or .xml.
  • MIME type: application/xml or text/xml.
  • XML version: 1.0.
  • Character encoding: UTF-8 (recommended).
  • Root element:  in the namespace http://www.xbrl.org/2003/instance.
  • Required namespaces:
  • http://www.xbrl.org/2003/instance (prefix: xbrli).
  • http://www.w3.org/1999/xlink (prefix: xlink).
  • http://www.xbrl.org/2003/linkbase (prefix: link).
  • http://www.w3.org/2001/XMLSchema-instance (prefix: xsi).
  • http://www.w3.org/XML/1998/namespace (prefix: xml).
  • Presence of at least one link:schemaRef element with an xlink:href attribute referencing a taxonomy schema (.xsd file).
  • Optional link:linkbaseRef elements with xlink:href attributes referencing linkbase files (e.g., label, calculation).
  • elements, each with an id attribute, containing  (with  and scheme) and  (instant, duration, or forever).
  • elements, each with an id attribute, containing  or  for unit definitions.
  • Fact elements:  or , with attributes such as contextRef, unitRef (for numeric items), decimals or precision, and xsi:nil.
  • Schema compliance: Must validate against the XBRL 2.1 instance schema (xbrl-instance-2003-12-31.xsd).
  • URI resolution: Optional xml:base attribute for relative URI resolution in hrefs.

These properties ensure the file is recognizable and processable as an XBRL instance document.

3. Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .XBRL File Processing

The following is an HTML snippet with embedded JavaScript that can be inserted into a Ghost blog post. It creates a drag-and-drop area where a user can drop a .XBRL file. The script reads the file, parses it as XML, extracts the properties listed in section 1, and displays them on the screen.

Drag and drop a .XBRL file here

4. Python Class for .XBRL File Processing

The following Python class uses the standard xml.etree.ElementTree module to open, parse, read, write, and print the properties of a .XBRL file.

import xml.etree.ElementTree as ET

class XBRLParser:
    def __init__(self, filename):
        self.filename = filename
        self.tree = None
        self.root = None
        self.namespaces = {
            'xbrli': 'http://www.xbrl.org/2003/instance',
            'link': 'http://www.xbrl.org/2003/linkbase',
            'xlink': 'http://www.w3.org/1999/xlink',
            'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
            'xml': 'http://www.w3.org/XML/1998/namespace'
        }

    def read(self):
        self.tree = ET.parse(self.filename)
        self.root = self.tree.getroot()
        if self.root.tag != '{http://www.xbrl.org/2003/instance}xbrl':
            raise ValueError("Not a valid XBRL file (missing <xbrl> root).")

    def print_properties(self):
        if not self.root:
            raise ValueError("File not read yet. Call read() first.")
        
        print("XBRL Properties:")
        print(f"- XML Version: {self.tree.docinfo.xml_version or '1.0'}")
        print(f"- Encoding: {self.tree.docinfo.encoding or 'UTF-8'}")
        print(f"- Root Element: {ET.QName(self.root.tag).localname}")
        print("- Namespaces:")
        for prefix, uri in self.root.nsmap.items():
            print(f"  {prefix}: {uri}")
        schema_refs = self.root.findall('link:schemaRef', self.namespaces)
        print(f"- Schema References: {len(schema_refs)}")
        for ref in schema_refs:
            print(f"  href: {ref.get('{http://www.w3.org/1999/xlink}href')}")
        linkbase_refs = self.root.findall('link:linkbaseRef', self.namespaces)
        print(f"- Linkbase References: {len(linkbase_refs)}")
        for ref in linkbase_refs:
            print(f"  href: {ref.get('{http://www.w3.org/1999/xlink}href')}, role: {ref.get('{http://www.w3.org/1999/xlink}role') or 'none'}")
        contexts = self.root.findall('xbrli:context', self.namespaces)
        print(f"- Contexts: {len(contexts)}")
        units = self.root.findall('xbrli:unit', self.namespaces)
        print(f"- Units: {len(units)}")
        facts = [elem for elem in self.root.iter() if 'contextRef' in elem.attrib]
        print(f"- Facts: {len(facts)}")

    def write(self, new_filename):
        if not self.tree:
            raise ValueError("File not read yet. Call read() first.")
        self.tree.write(new_filename, encoding='utf-8', xml_declaration=True)

# Example usage:
# parser = XBRLParser('example.xbrl')
# parser.read()
# parser.print_properties()
# parser.write('output.xbrl')

5. Java Class for .XBRL File Processing

The following Java class uses javax.xml.parsers to open, parse, read, write, and print the properties of a .XBRL file.

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import java.io.File;
import java.io.StringReader;

public class XBRLParser {
    private String filename;
    private Document document;

    public XBRLParser(String filename) {
        this.filename = filename;
        this.document = null;
    }

    public void read() throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        this.document = builder.parse(new File(filename));
        Element root = document.getDocumentElement();
        if (!root.getLocalName().equals("xbrl")) {
            throw new IllegalArgumentException("Not a valid XBRL file (missing <xbrl> root).");
        }
    }

    public void printProperties() throws Exception {
        if (document == null) {
            throw new IllegalArgumentException("File not read yet. Call read() first.");
        }
        Element root = document.getDocumentElement();
        System.out.println("XBRL Properties:");
        System.out.println("- XML Version: " + document.getXmlVersion());
        System.out.println("- Encoding: " + document.getXmlEncoding());
        System.out.println("- Root Element: " + root.getLocalName());
        System.out.println("- Namespaces:");
        // Note: Java DOM does not directly expose nsmap; parse manually if needed
        String rootStr = document.getDocumentElement().toString(); // Simplified
        System.out.println("  (Namespaces available in root attributes)");
        NodeList schemaRefs = document.getElementsByTagNameNS("http://www.xbrl.org/2003/linkbase", "schemaRef");
        System.out.println("- Schema References: " + schemaRefs.getLength());
        for (int i = 0; i < schemaRefs.getLength(); i++) {
            Element ref = (Element) schemaRefs.item(i);
            System.out.println("  href: " + ref.getAttributeNS("http://www.w3.org/1999/xlink", "href"));
        }
        NodeList linkbaseRefs = document.getElementsByTagNameNS("http://www.xbrl.org/2003/linkbase", "linkbaseRef");
        System.out.println("- Linkbase References: " + linkbaseRefs.getLength());
        for (int i = 0; i < linkbaseRefs.getLength(); i++) {
            Element ref = (Element) linkbaseRefs.item(i);
            System.out.println("  href: " + ref.getAttributeNS("http://www.w3.org/1999/xlink", "href") + ", role: " + ref.getAttributeNS("http://www.w3.org/1999/xlink", "role"));
        }
        NodeList contexts = document.getElementsByTagNameNS("http://www.xbrl.org/2003/instance", "context");
        System.out.println("- Contexts: " + contexts.getLength());
        NodeList units = document.getElementsByTagNameNS("http://www.xbrl.org/2003/instance", "unit");
        System.out.println("- Units: " + units.getLength());
        // Facts: elements with contextRef attribute
        // Simplified count; use XPath for accurate count if needed
        System.out.println("- Facts: (Count requires XPath query for [contextRef])");
    }

    public void write(String newFilename) throws Exception {
        if (document == null) {
            throw new IllegalArgumentException("File not read yet. Call read() first.");
        }
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(document);
        StreamResult result = new StreamResult(new File(newFilename));
        transformer.transform(source, result);
    }

    // Example usage:
    // public static void main(String[] args) throws Exception {
    //     XBRLParser parser = new XBRLParser("example.xbrl");
    //     parser.read();
    //     parser.printProperties();
    //     parser.write("output.xbrl");
    // }
}

6. JavaScript Class for .XBRL File Processing

The following JavaScript class (for Node.js, requiring 'fs' and 'xmldom' module) opens, parses, reads, writes, and prints the properties of a .XBRL file to the console.

const fs = require('fs');
const DOMParser = require('xmldom').DOMParser;
const XMLSerializer = require('xmldom').XMLSerializer;

class XBRLParser {
  constructor(filename) {
    this.filename = filename;
    this.xmlContent = null;
    this.doc = null;
  }

  read() {
    this.xmlContent = fs.readFileSync(this.filename, 'utf8');
    const parser = new DOMParser();
    this.doc = parser.parseFromString(this.xmlContent, 'application/xml');
    if (this.doc.documentElement.tagName !== 'xbrl') {
      throw new Error('Not a valid XBRL file (missing <xbrl> root).');
    }
  }

  printProperties() {
    if (!this.doc) {
      throw new Error('File not read yet. Call read() first.');
    }
    console.log('XBRL Properties:');
    console.log(`- XML Version: ${this.doc.xmlVersion || '1.0'}`);
    console.log(`- Encoding: ${this.doc.xmlEncoding || 'UTF-8'}`);
    console.log(`- Root Element: ${this.doc.documentElement.tagName}`);
    console.log('- Namespaces:');
    const attrs = this.doc.documentElement.attributes;
    for (let i = 0; i < attrs.length; i++) {
      if (attrs[i].name.startsWith('xmlns')) {
        console.log(`  ${attrs[i].name}: ${attrs[i].value}`);
      }
    }
    const schemaRefs = this.doc.getElementsByTagNameNS('http://www.xbrl.org/2003/linkbase', 'schemaRef');
    console.log(`- Schema References: ${schemaRefs.length}`);
    for (let ref of schemaRefs) {
      console.log(`  href: ${ref.getAttributeNS('http://www.w3.org/1999/xlink', 'href')}`);
    }
    const linkbaseRefs = this.doc.getElementsByTagNameNS('http://www.xbrl.org/2003/linkbase', 'linkbaseRef');
    console.log(`- Linkbase References: ${linkbaseRefs.length}`);
    for (let ref of linkbaseRefs) {
      console.log(`  href: ${ref.getAttributeNS('http://www.w3.org/1999/xlink', 'href')}, role: ${ref.getAttributeNS('http://www.w3.org/1999/xlink', 'role') || 'none'}`);
    }
    console.log(`- Contexts: ${this.doc.getElementsByTagNameNS('http://www.xbrl.org/2003/instance', 'context').length}`);
    console.log(`- Units: ${this.doc.getElementsByTagNameNS('http://www.xbrl.org/2003/instance', 'unit').length}`);
    const facts = this.doc.querySelectorAll('[contextRef]');
    console.log(`- Facts: ${facts.length}`);
  }

  write(newFilename) {
    if (!this.doc) {
      throw new Error('File not read yet. Call read() first.');
    }
    const serializer = new XMLSerializer();
    const xmlStr = serializer.serializeToString(this.doc);
    fs.writeFileSync(newFilename, xmlStr, 'utf8');
  }
}

// Example usage:
// const parser = new XBRLParser('example.xbrl');
// parser.read();
// parser.printProperties();
// parser.write('output.xbrl');

7. C Class for .XBRL File Processing

Since C is not object-oriented, the following is a C++ class using <fstream>, <string>, and <tinyxml2> (an external library for XML parsing) to open, parse, read, write, and print the properties of a .XBRL file to the console. Assume tinyxml2 is included.

#include <iostream>
#include <fstream>
#include <string>
#include "tinyxml2.h"  // Assume tinyxml2 library is available

using namespace tinyxml2;

class XBRLParser {
private:
    std::string filename;
    XMLDocument doc;

public:
    XBRLParser(const std::string& fn) : filename(fn) {}

    void read() {
        if (doc.LoadFile(filename.c_str()) != XML_SUCCESS) {
            throw std::runtime_error("Failed to load file.");
        }
        XMLElement* root = doc.RootElement();
        if (std::string(root->Name()) != "xbrl") {
            throw std::runtime_error("Not a valid XBRL file (missing <xbrl> root).");
        }
    }

    void printProperties() {
        XMLElement* root = doc.RootElement();
        if (!root) {
            throw std::runtime_error("File not read yet. Call read() first.");
        }
        std::cout << "XBRL Properties:" << std::endl;
        std::cout << "- XML Version: " << (doc.Version() ? doc.Version() : "1.0") << std::endl;
        // Encoding not directly available in tinyxml2; assume UTF-8
        std::cout << "- Encoding: UTF-8" << std::endl;
        std::cout << "- Root Element: " << root->Name() << std::endl;
        std::cout << "- Namespaces:" << std::endl;
        // Namespaces in attributes
        for (const XMLAttribute* attr = root->FirstAttribute(); attr; attr = attr->Next()) {
            if (std::string(attr->Name()).find("xmlns") == 0) {
                std::cout << "  " << attr->Name() << ": " << attr->Value() << std::endl;
            }
        }
        XMLElement* schemaRef = root->FirstChildElement("schemaRef");
        int schemaCount = 0;
        std::cout << "- Schema References: ";
        while (schemaRef) {
            schemaCount++;
            std::cout << schemaCount << " href: " << (schemaRef->Attribute("xlink:href") ? schemaRef->Attribute("xlink:href") : "") << std::endl;
            schemaRef = schemaRef->NextSiblingElement("schemaRef");
        }
        if (schemaCount == 0) std::cout << "0" << std::endl;
        XMLElement* linkbaseRef = root->FirstChildElement("linkbaseRef");
        int linkbaseCount = 0;
        std::cout << "- Linkbase References: ";
        while (linkbaseRef) {
            linkbaseCount++;
            std::cout << linkbaseCount << " href: " << (linkbaseRef->Attribute("xlink:href") ? linkbaseRef->Attribute("xlink:href") : "") 
                      << ", role: " << (linkbaseRef->Attribute("xlink:role") ? linkbaseRef->Attribute("xlink:role") : "none") << std::endl;
            linkbaseRef = linkbaseRef->NextSiblingElement("linkbaseRef");
        }
        if (linkbaseCount == 0) std::cout << "0" << std::endl;
        XMLElement* context = root->FirstChildElement("context");
        int contextCount = 0;
        while (context) {
            contextCount++;
            context = context->NextSiblingElement("context");
        }
        std::cout << "- Contexts: " << contextCount << std::endl;
        XMLElement* unit = root->FirstChildElement("unit");
        int unitCount = 0;
        while (unit) {
            unitCount++;
            unit = unit->NextSiblingElement("unit");
        }
        std::cout << "- Units: " << unitCount << std::endl;
        // Facts: count elements with contextRef
        int factCount = 0;
        XMLElement* elem = root->FirstChildElement();
        while (elem) {
            if (elem->Attribute("contextRef")) factCount++;
            elem = elem->NextSiblingElement();
        }
        std::cout << "- Facts: " << factCount << std::endl;
    }

    void write(const std::string& newFilename) {
        if (doc.SaveFile(newFilename.c_str()) != XML_SUCCESS) {
            throw std::runtime_error("Failed to write file.");
        }
    }
};

// Example usage:
// int main() {
//     try {
//         XBRLParser parser("example.xbrl");
//         parser.read();
//         parser.printProperties();
//         parser.write("output.xbrl");
//     } catch (const std::exception& e) {
//         std::cerr << e.what() << std::endl;
//     }
//     return 0;
// }