• Solutions
    • FERC XBRL Reporting
    • FDTA Financial Reporting
    • SEC Compliance
    • Windows Clipboard Management
    • Legato Scripting
  • Products
    • GoFiler Suite
    • XBRLworks
    • SEC Exhibit Explorer
    • SEC Extractor
    • Clipboard Scout
    • Legato
  • Education
    • Training
    • SEC and EDGAR Compliance
    • Legato Developers
  • Blog
  • Support
  • Skip to blog entries
  • Skip to archive page
  • Skip to right sidebar

Friday, February 09. 2018

LDC #71: Validating With The XBRL Object

XBRL can be a challenging topic to tackle. There are a lot of rules to learn for it, and with 14,000+ elements in the US:GAAP taxonomy, it doesn’t look like it’s going to get simpler any time soon. Fortunately, using GoFiler and Legato, we can add some functionality to make things a little easier.


Legato supports XBRL through an XBRL object. You can retrieve a handle to the XBRL object by using the XBRLGetObject function. The handle is a required parameter for most functions dealing with XBRL. In the current version of Legato, we have the ability to read various parts of any XBRL open in the XBRL View. We can do things like get elements, get labels, get presentations, and so on. Future versions of Legato will have the ability to modify these attributes, but for now the XBRL object can only read them. This is still pretty useful. We can do things like add extra validations and checks to make sure we’re doing things the way we want. I wrote up a small example script of how to use these functions. This little program adds an extra check to the validate button to check to see if the number of extended elements is too high, but there are many more things you can do with a script like this.


The example script:



#define                 HIGH            30
#define                 MID             15
#define                 HIGH_MSG        "Using a high percentage of extended elements is not recommended. Use more taxonomy elements."
#define                 MID_MSG         "Custom element usage is about average, if possible replace some custom definitions for taxonomy elements."

void setup();
void run(int f_id, string mode, handle window);


void main(){
    
    int                 ix;
    int                 size;
    string              windows[][];
    handle              window;
    
    if (GetScriptParent() == "LegatoIDE"){
      windows = EnumerateEditWindows();
      size = ArrayGetAxisDepth(windows);
      for (ix = 0 ; ix < size; ix++){
        if (windows[ix]["FileTypeToken"] == "FT_XFR"){
          run (0,"postprocess",MakeHandle(windows[ix]["ClientHandle"]));
          }
        }
      }
    setup();
    }
    
void setup(){
    
    MenuSetHook("XBRL_VALIDATE", GetScriptFilename(), "run");
    MenuSetHook("EDGAR_VALIDATE", GetScriptFilename(), "run");
    
    }
    
void run(int f_id, string mode, handle window){
    
    handle              XBRL;
    string              presentations[];
    string              elements[];
    dword               wType;
    int                 fields_pos;
    int                 customs;
    int                 total_elements;
    int                 ix, rx;
    int                 percent;
    int                 size;
    boolean             hooked;
    
    if (mode != "postprocess"){
      return;
      }
    if (IsWindowHandleValid(window) == false){
      window = GetActiveEditWindow();
      wType = GetEditWindowType(window) & EDX_TYPE_ID_MASK;
      if (wType != EDX_TYPE_XBRL_VIEW){
        return;
        }
      hooked = true;
      }
    XBRL = XBRLGetObject(window);
    presentations = XBRLGetPresentations(XBRL);
    fields_pos = FindInList(presentations,"XBRL Financial Fields");
    if (fields_pos < 0){
      return;
      }
    elements = XBRLGetPresentationElements(XBRL,fields_pos);
    size = ArrayGetAxisDepth(elements);
    customs = 0;
    for (ix = 0; ix < size; ix++){
      if (elements[ix] !=""){
        total_elements++;
        if (FindInString(elements[ix],"custom:")==0){
          customs++;
          }
        }
      }
    percent = (customs*100)/total_elements;
    if (hooked == false){
      AddMessage("Checking Custom Elements in %s",GetEditWindowFilename(window));
      AddMessage("Found %d total line items",total_elements);
      AddMessage("Found %d custom line items",customs);
      AddMessage("%d%% custom line items",percent);
      }
    else{
      if (percent > MID){
        if (percent >= HIGH){
          MessageBox('x',"%d%% custom elements used as line items. %s",percent,HIGH_MSG);
          }
        else{
          MessageBox('i',"%d%% custom elements used as line items. %s",percent,MID_MSG);
          }
        }
      }
    }


This script is set up so it can run from either the Legato IDE or from XBRL view. If it’s run from the IDE, the main function is going to be run otherwise setup will run. So, the first thing that function needs to do is double-check to make sure it’s being run from the IDE by using the GetScriptParent function. Once we know that it’s running from an IDE, we can iterate over all windows, and if the window is of file type FT_XFR, we know it’s an XBRL file and we can use our run function on it. The run function in this case is set up to take a window handle as an input parameter, so all we need to do is pass the handle of our XBRL window to the function.



void main(){
    
    int                 ix;
    int                 size;
    string              windows[][];
    handle              window;
    
    if (GetScriptParent() == "LegatoIDE"){
      windows = EnumerateEditWindows();
      size = ArrayGetAxisDepth(windows);
      for (ix = 0 ; ix < size; ix++){
        if (windows[ix]["FileTypeToken"] == "FT_XFR"){
          run (0,"postprocess",MakeHandle(windows[ix]["ClientHandle"]));
          }
        }
      }
    setup();
    }


The setup function is really simple. We just want to hook our run function to the XBRL validate and the regular EDGAR validate buttons. The run function itself then needs to double-check to make sure it actually has an XBRL view open before it continues.



void setup(){
    
    MenuSetHook("XBRL_VALIDATE", GetScriptFilename(), "run");
    MenuSetHook("EDGAR_VALIDATE", GetScriptFilename(), "run");
    
    }


The run function is the main function in this script. The first thing it does is check to make sure we’re running in postprocess mode. We want this to run after the normal validation. Then we can check to see if we were passed a valid window handle. If so, we’re running in IDE mode. If not, then we can get the active edit window, ensure it’s an XBRL view, and set the “hooked” variable to true to show we’re running in hooked mode instead of IDE mode. Then we can use the XBRLGetObject function to grab a handle to the XBRL object. Using this handle, we can get all sorts of data out of our XBRL file, but in this case we’re going to have the XBRLGetPresentations function get a list of all XBRL presentations. We can then use the FindInList function to find the position of the XBRL Fields presentation, which has all of the used elements listed on it in GoFiler. If there isn’t one, we can just return here. Otherwise, we can use the XBRLGetPresentationElements function to retrieve a list of all the elements used in the entire report,and use the ArrayGetAxisDepth function to get the size of that list.


    
void run(int f_id, string mode, handle window){
    
<... declarations omitted ... >

    if (mode != "postprocess"){
      return;
      }
    if (IsWindowHandleValid(window) == false){
      window = GetActiveEditWindow();
      wType = GetEditWindowType(window) & EDX_TYPE_ID_MASK;
      if (wType != EDX_TYPE_XBRL_VIEW){
        return;
        }
      hooked = true;
      }
    XBRL = XBRLGetObject(window);
    presentations = XBRLGetPresentations(XBRL);
    fields_pos = FindInList(presentations,"XBRL Financial Fields");
    if (fields_pos < 0){
      return;
      }
    elements = XBRLGetPresentationElements(XBRL,fields_pos);
    size = ArrayGetAxisDepth(elements);


Now that we have the list of elements and the size, we can iterate over the list. For each element, we add it to the total number of elements. Also, if the element name contains “custom:” at the start, then it must be a custom element, so we can add one to the total number of custom elements. The percentage of custom elements is going to be number of custom elements multiplied by 100 and then divided by the total number of elements. I multiply by 100 before dividing so I can use integer math to do the calculation instead of a floating point calculation. If we’re running in “hooked” mode, we can then just add some messages to the log. If not, we want to evaluate if the percentage of custom elements is too high, so we compare it to our defined middle and high threshold points and print out appropriate error messages in either case.



    customs = 0;
    for (ix = 0; ix < size; ix++){
      if (elements[ix] !=""){
        total_elements++;
        if (FindInString(elements[ix],"custom:")==0){
          customs++;
          }
        }
      }
    percent = (customs*100)/total_elements;
    if (hooked == false){
      AddMessage("Checking Custom Elements in %s",GetEditWindowFilename(window));
      AddMessage("Found %d total line items",total_elements);
      AddMessage("Found %d custom line items",customs);
      AddMessage("%d%% custom line items",percent);
      }
    else{
      if (percent > MID){
        if (percent >= HIGH){
          MessageBox('x',"%d%% custom elements used as line items. %s",percent,HIGH_MSG);
          }
        else{
          MessageBox('i',"%d%% custom elements used as line items. %s",percent,MID_MSG);
          }
        }
      }
    }


Like most of our examples, this is only meant to be an overview of something you can do with the XBRL object. It can get fact values, context values, labels, pretty much any data you could want out of an XBRL report. We’re using it here to add an extra layer of validation, but it could just as easily be adjusted to mine existing reports for data. If you mined the SEC for XBRL files, for example, you could write a script to iterate through them and pull out key facts across them all. Any XBRL file that can be opened in GoFiler can work with the XBRL object, and therefore Legato can help you automate the retrieval of information from them. Full documentation of what the XBRL object can do is available in the Legato Documentation located here.


 


Steven Horowitz has been working for Novaworks for over five years as a technical expert with a focus on EDGAR HTML and XBRL. Since the creation of the Legato language in 2015, Steven has been developing scripts to improve the GoFiler user experience. He is currently working toward a Bachelor of Sciences in Software Engineering at RIT and MCC.

Additional Resources

Novaworks’ Legato Resources

Legato Script Developers LinkedIn Group

Primer: An Introduction to Legato 



Posted by
Steven Horowitz
in Development at 17:49
Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)
No comments
Add Comment
Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

 
   
 

Quicksearch

Categories

  • XML Accounting
  • XML AICPA News
  • XML FASB News
  • XML GASB News
  • XML IASB News
  • XML Development
  • XML Events
  • XML FERC
  • XML eForms News
  • XML FERC Filing Help
  • XML Filing Technology
  • XML Information Technology
  • XML Investor Education
  • XML MSRB
  • XML EMMA News
  • XML FDTA
  • XML MSRB Filing Help
  • XML Novaworks News
  • XML GoFiler Online Updates
  • XML GoFiler Updates
  • XML XBRLworks Updates
  • XML SEC
  • XML Corporation Finance
  • XML DERA
  • XML EDGAR News
  • XML Investment Management
  • XML SEC Filing Help
  • XML XBRL
  • XML Data Quality Committee
  • XML GRIP Taxonomy
  • XML IFRS Taxonomy
  • XML US GAAP Taxonomy

Calendar

Back May '25 Forward
Mo Tu We Th Fr Sa Su
Sunday, May 18. 2025
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Feeds

  • XML
Sign Up Now
Get SEC news articles and blog posts delivered monthly to your inbox!
Based on the s9y Bulletproof template framework

Compliance

  • FERC
  • EDGAR
  • EMMA

Software

  • GoFiler Suite
  • SEC Exhibit Explorer
  • SEC Extractor
  • XBRLworks
  • Legato Scripting

Company

  • About Novaworks
  • News
  • Site Map
  • Support

Follow Us:

  • LinkedIn
  • YouTube
  • RSS
  • Newsletter
  • © 2024 Novaworks, LLC
  • Privacy
  • Terms of Use
  • Trademarks and Patents
  • Contact Us