No Semantics to Context References

This email came into the Gepsio inbox recently:

I’ve been playing around with the library. My first exercise for myself is trying to reconstruct the financial statements. I thought I’d group Facts by time periods. The ContextRefNames were not what I expected. There were overlaps in names like FD2015XXX, D2015XXX, I2015XXX. Do you know the difference between the prefixes? I’m using Whole Foods https://www.sec.gov/Archives/edgar/data/865436/000086543615000177/0000865436-15-000177-index.htm

Is there a particular convention that the contextrefnames follow? I had a look at Walmart and they use a similar, but different convention.

Unfortunately, the answer is “no”.

Context IDs and references have no meaning. They are syntax, not semantics. Context reference names are arbitrary and have meaning only to link items within the individual document instances.

Section 4.7.1 of the XBRL 2.1 specification discusses the “id” attribute of a <context> element:

Every  <context>  element MUST include the  @id attribute. The content of the  @id attribute MUST conform to the [XML] rules for attributes with the ID type (http://www.w3.org/TR/REC-xml#NT-TokenizedType). The  @id attribute identifies the context (see  Section 4.7) so that it may be referenced by item elements.

The specification does not impose any semantics on the contents of the ID attribute.

Gepsio for Universal Windows Underway

The following email came in to the Gepsio inbox today:

Hi,

I am very interested in trying out Gepsio on the windows 10 universal app platform.

I saw that a universal windows project has been added to the repo without some vital xml parts.

Will there be a new patch soon with the remaining parts?

As a matter of fact, yes! That work is underway now.

The email is referencing this changeset, which contains the following somewhat-cryptic description:

Universal Windows project added. XML implementation for Universal Windows is not implemented, and there are no unit tests for Universal Windows, so Gepsio for Universal Windows cannot be used at this time. The .NET builds are, as always, fully supported.

That changeset included a new project in the Gepsio solution – a project which would target a Gepsio assembly tuned for the Windows 10 Universal Windows Platform (or UWP, for short). The vision is to allow Gepsio to be used by developers wishing to build XBRL-enabled applications on Windows 10 UWP.

Thanks to the interface-based separation between Gepsio’s XML service layer and its XBRL semantic layer, described here, the work needed to allow Gepsio to support Windows 10 UWP is not a “do over”. The work involved is, basically, to build new XML interface implementations that use Windows 10 UWP instead of .NET. This work is underway now. In fact, Gepsio already has enough UWP code to open up an XML document and search for <xbrl> nodes in Windows 10. This is exciting, as it means that Gepsio can be used for code that runs on any Windows 10 UWP platform, from the phone, to the tablet, to the desktop, to the Xbox One.

The Windows 10 UWP code is not ready, and, although the project skeleton has been checked in, the XML layer for Windows 10 UWP is not ready. That code is in progress. When it’s ready, there will be a blog post announcing the new code. The code is not a straightforward port from the .NET XML code, for the following reasons:

  • The .NET code uses the XML classes in the System.Xml namespace. The Windows 10 UWP code is using XML classes in the Windows.Data.Xml.Dom namespace.
  • The Windows 10 UWP makes use of asynchronous methods; for example, XmlDocument.Load() has become await XmlDocument.LoadFromFileAsync(). Ensuring that Gepsio supports this asynchronous model, while still maintaining the existing needs of the Gepsio XBRL semantic layer, will need some additional work.
  • Unlike .NET’s System.Xml namespace, the Windows 10 UWP’s Windows.Data.Xml.Dom namespace does not have any built in support for XML Schema. XBRL relies on XML Schema documents for its taxonomies. Gepsio’s XML Schema support will have to be written from the ground up since there is no support for XML Schema in UWP.

Gepsio will retain its .NET builds as well. Gepsio will continue to support .NET 3.5, .NET 4, .NET 4.5, .NET 4.5.1, .NET 4.5.2, and .NET 4.6. If you’re not ready to move to Windows 10 UWP just yet, do not worry – all of the .NET builds will continue to be supported and ship for the foreseeable future.

Assemblies for Multiple Platforms Available with Next Release

The Gepsio code base has just undergone a significant restructuring with changeset 77191. As a benefit of the restructuring, the project will, for the first time, be able to provide assemblies for the following platforms:

  • .NET 3.5
  • .NET 4
  • .NET 4.5
  • .NET 4.5.1
  • .NET 4.5.2
  • .NET 4.6

This restructuring also puts Gepsio in the position to provide support for .NET platforms, including the Universal Windows Platform (UWP) available with Windows 10. This is an exciting time for the project, as, up to this point, Gepsio has provided assemblies only for the aging .NET 3.5 platform.

The restructuring relies heavily on the Shared Projects concept available in Visual Studio 2015 to provide support for sharing common code across each of the platform builds. As such, Visual Studio 2015 is now required to open the solution’s source code.

For those users interested only in compiled binaries, no change is needed. Both the project site on Codeplex and Gepsio’s NuGet package will be updated with all of the platform binaries produced by the build process.

Change Log for Aug 2015 CTP

Design

  • The XLINK specification is now implemented in a specific class, and XBRL linkbase nodes now leverage Gepsio’s implementation of XLINK. The following classes have been refactored to leverage Gepsio’s internal support for the XLINK specification added in this version:
    • Label
    • LabelLink
  • Improved performance of loading an XBRL fragment’s fact collection by setting the capacity of the collection to the maximum number of nodes beneath the XBRL root node before any facts are created and added to the collection, and then trimming the excess after all facts are created and added to the collection. This strategy prevents .NET from having to re-allocate the fact collection each time it needs to expand, which costs time during the fact collection creation process.
  • The list of facts exposed by an XbrlFragment, formerly of type List<Fact>, is now an object of a class called FactCollection. The FactCollection class allows the fact list to be augmented with some internal dictionaries that can be used to find a fact more quickly than simply iterating through a list and checking each fact.
  • Gepsio’s XML service layer has been implemented behind an interface since the Nov 2014 CTP. These interfaces, which have been internal in previous CTPs, is now public. See this blog post for more information for the motivation and rationale behind this change.

New Classes

  • FactCollection: Replaces the simple List<Fact> with additional public methods to quickly find a fact or list of facts by name or ID. The FactCollection class supports public methods such as GetFactById() and GetFactByName() which allows callers to find facts in the collection quickly and efficiently, thanks to internal disctionaries managed by the FactCollection class.
  • PresentableFactTree: A tree of facts arranged in accordance with the information in a presentation linkbase. See this blog post and this blog post for more information.
  • PresentableFactTreeNode: A node in a tree of facts arranged in accordance with the information in a presentation linkbase. See this blog post and this blog post for more information.

New Properties Available on Previously Existing Classes

Element

  • bool IsAbstract: True if the element is an abstract element; false otherwise.

Fact

  • string Id: The ID of the fact.

Label

  • string Label: The value of the label’s “label” attribute.

New Methods Available on Previously Existing Classes

XbrlFragment

  • GetPresentableFactTree()

LabelLink

  • GetLocator(string href)
  • GetLabelArc(string fromAttributeValue)
  • GetLabel(string labelAttributeValue)

Previously Existing Properties Removed from Previously Existing Classes

Item

  • string ID: The ID value is now populated in the base Fact class, making IDs available to both items and tuples.

Label

  • string ID: The ID value is now populated in the base XlinkNode class and its “Label” property.

Conformance

  • None

Conformance Tests in XBRL-CONF-CR5-2012-01-24 Passed by Gepsio

Identifier Scope [Section 4.3 The Item Element]

  • 301-01-IdScopeValid.xml [301.01 Valid example of id attribute.]
  • 301-03-IdScopePeriodDiff.xml [301.03 Mismatch of periodType attribute and referenced context’s period type.]
  • 301-04-IdScopeContextRefToUnit.xml [301.04 contextRef has IDREF to unit element.]
  • 301-05-IdScopeUnitRefToContext.xml [301.05 unitRef has IDREF to context element.]
  • 301-06-FootnoteScopeValid.xml [301.06 Valid example of footnote link href attribute.]
  • 301-08-FootnoteToContext.xml [301.08 href attribute is referencing to context element.]
  • 301-09-FootnoteToUnit.xml [301.09 href attribute is referencing to unit element.]
  • 301-10-FootnoteFromOutOfScope.xml [301.10 The instance contains two footnote links. The second one contains an arc with a from value that does not have a corresponding loc in the same extended link.]
  • 301-11-FootnoteToOutOfScope.xml [301.11 The instance contains two footnote links. The second one contains an arc with a to value that does not have a corresponding footnote resource in the same extended link.]
  • 301-12-FootnoteLocOutOfScope.xml [301.12 The instance contains a footnote link. In the footnote link there is a loc element that has an href that points to a fact in another instance document.]
  • 301-13-FootnoteLocInScope.xml [301.13 The instance contains a footnote link. In the footnote link there is a loc element that has an href that points to a fact in the instance document using the instance document file name with a fragment identifier.]
  • 301-14-FootnoteFromResource.xml [301.14 The instance contains a footnote link. The arc in the footnote link has a from value that matches a footnote resource. This is not valid for the fact-footnote arc role on the arc. The from must point to a loc which in turns points to a fact in the same instance document.]
  • 301-15-FootnoteToLoc.xml [301.15 The instance contains a footnote link. The arc in the footnote link has a from value that matches a footnote resource. This is not valid for the fact-footnote arc role on the arc. The from must point to a loc which in turns points to a fact in the same instance document.]
  • 301-16-FootnoteWithoutLang.xml [301.16 The xml:lang attribute is missing on the footnote resource.]
  • 301-17-FootnoteCustomArcRole.xml [301.17 The footnote custom arc role can relate two footnotes to each other instead of just fact to footnote. (Only the standard footnote arc role is restricted to being from item or tuple locators.) Maybe this might be used to indicate how some footnote is “footnoting” another footnote.]

Context Segments and Scenarios [Section 4.4 The Context Element]

  • 302-01-SegmentValid.xml [302.01 Valid segment in a context]
  • 302-02-SegmentNamespaceInvalid.xml [302.02 Invalid segment in a context; contains an element defined in xbrli namespace]
  • 302-03-ScenarioValid.xml [302.03 Valid scenario in a context]
  • 302-04-ScenarioNamespaceInvalid.xml [302.04 Invalid scenario in a context; contains an element defined in xbrli namespace]
  • 302-05-SegmentSubstitutionInvalid.xml [302.05 Invalid segment in a context; contains an element in substitution group of xbrli:item]
  • 302-06-ScenarioSubstitutionInvalid.xml [302.06 Invalid scenario in a context; contains an element in substitution group of xbrli:item]
  • 302-07-SegmentEmptyContent.xml [302.07 Segment in a context contains an element with empty content]
  • 302-08-ScenarioEmptyContent.xml [302.08 Scenario in a context contains an element with empty content]
  • 302-09-PeriodDateTimeValid.xml [302.09 Valid duration context with start date earlier than end date]
  • 302-10-PeriodDateTimeInvalid.xml [302.10 Invalid duration context with start date later than end date]
  • 302-11-DecimalAttributeOnSegmentInconsistent.xbrl [302.11 Two contexts are S-Equal even though a decimal-valued attribute in their segment elements have different lexical representations. The contexts are S-equal, so a calculation inconsistency MUST be signaled.]
  • 302-12-DecimalAttributeOnScenarioInconsistent.xbrl [302.12 Two contexts are S-Equal even though a decimal-valued attribute in their scenario elements have different lexical representations. The contexts are S-equal, so a calculation inconsistency MUST be signaled.]

Period Type Consistency [Section 4.3 The Item Element]

  • 303-01-PeriodInstantValid.xml [303.01 instant context and item defined with PeriodType=”instant”]
  • 303-02-PeriodDurationValid.xml [303.02 duration context and item defined with PeriodType=”duration”]
  • 303-03-PeriodInstantInvalid.xml [303.03 duration context and item defined with PeriodType=”instant”]
  • 303-04-PeriodDurationInvalid.xml [303.04 instant context and item defined with PeriodType=”duration”]
  • 303-05-ForeverElementewithInstancePeriodTypeReportedasForever.xbrl [ForeverConcept with Instant Period Type is not allowed]

Unit of Measure Consistency [Section 4.4 The Context Element]

  • 304-01-monetaryItemTypeUnitsRestrictions.xml [304.01 An element with a monetary item type has an ISO currency code for its units (using the standard ISO namespace prefix).]
  • 304-02-monetaryItemTypeUnitsRestrictions.xml [304.02 An element with a monetary item type has an ISO currency code for its units (using a non-standard ISO namespace prefix).]
  • 304-03-monetaryItemTypeUnitsRestrictions.xml [304.03 An element with a type derived by restriction from the monetary item type has an ISO currency code for its units.]
  • 304-04-monetaryItemTypeUnitsRestrictions.xml [304.04 An element with a type derived by restriction from monetary item type has an ISO currency code for its units (using a non-standard ISO namespace prefix).]
  • 304-05-monetaryItemTypeUnitsRestrictions.xml [304.05 An element with a non-monetary item type has an ISO currency code for its units (using the standard ISO namespace prefix).]
  • 304-06-monetaryItemTypeUnitsRestrictions.xml [304.06 An element with a monetary item type does not have an ISO currency code for its units – the namespace is wrong.]
  • 304-07-monetaryItemTypeUnitsRestrictions.xml [304.07 An element with a monetaryItemType does not have an ISO currency code for its units – the local name is wrong.]
  • 304-08-monetaryItemTypeUnitsRestrictions.xml [304.08 An element with a type derived by restriction from monetaryItemType does not have an ISO currency code for its units – the namespace is wrong.]
  • 304-09-monetaryItemTypeUnitsRestrictions.xml [304.09 An element with a type derived by restriction from monetaryItemType does not have an ISO currency code for its units – the local name is wrong.]
  • 304-10-pureItemTypeUnitsRestrictions.xml [304.10 An item with a pureItemType data type MUST have a unit element and the local part of the measure MUST be “pure” with a namespace prefix that resolves to a namespace of “http://www.xbrl.org/2003/instance&#8221;.]
  • 304-11-pureItemTypeUnitsRestrictions.xml [A measure element with a namespace prefix that resolves to the “http://www.xbrl.org/2003/instance&#8221; namespace MUST have a local part of either “pure” or “shares”. The value ‘impure’ is not a valid measure in the XBRL instance namespace.]
  • 304-12-pureItemTypeUnitsRestrictions.xml [Unlike for monetaryItemType and sharesItemType, there is no constraint (in 4.8.2 or elsewhere) requiring an item with a pureItemType data type to have a particular kind of unit.]
  • 304-12a-pureItemTypeUnitsRestrictions.xml [Same as V-12, but the pure measure has no prefix and the default namespace is undefined.]
  • 304-13-sharesItemTypeUnitsRestrictions.xml [304.13 For facts that are of the sharesItemType, units MUST have A single measure element. The local part of the measure MUST be “shares” and the namespace prefix that MUST resolve to http://www.xbrl.org/2003/instance%5D
  • 304-14-sharesItemTypeUnitsRestrictions.xml [304.14 For facts that are DERIVED BY RESTRICTION from the sharesItemType, units MUST have A single measure element. The local part of the measure MUST be “shares” and the namespace prefix that MUST resolve to http://www.xbrl.org/2003/instance%5D
  • 304-15-pureItemTypeUnitsRestrictions.xml [304.15 For facts that are of shares item type, units MUST have A single measure element. The local part of the measure MUST be “shares” and the namespace prefix that MUST resolve to http://www.xbrl.org/2003/instance. In this case the unit has two measure elements, both of which are pure.]
  • 304-15a-sharesItemTypeUnitsRestrictions.xml [Same as V-15 but in this case the unit has has shares but no prefix and the default namespace is undefined.]
  • 304-16-unitsInSimplestForm.xml [304.16 The units must not have numerator and denominator measures that cancel.]
  • 304-17-sameOrderMeasuresValid.xml [304.17 The units equality test which two units have same order measures.]
  • 304-18-sameOrderDivisionMeasuresValid.xml [304.18 The units equality test which two units have same order divisions.]
  • 304-19-differentOrderMeasuresValid.xml [304.19 The units equality test which two units have different order measures.]
  • 304-20-differentOrderDivisionMeasuresValid.xml [304.20 The units equality test which two units have division elements which their order of child measures are different.]
  • 304-21-measuresInvalid.xml [304.21 it tries to essence-alias equality of two elements with different units : where one is pure-feet and the second is pure-pounds. so the alias essence check is invalid and it should throw an error in xbrl validation]
  • 304-22-divisionMeasuresInvalid.xml [304.22 The test tried to essense-alias equality check of two elements with different units : where one is unit between “pure-inch / pound-feet” and other “pure-feet / pound-inch”. The tests is invalid as it should throw an error during xbrl validation.]
  • 304-23-Calculation-item-does-not-match-unit.xml [Variation of 304-15 where the type of the fact value does not match that of the type of the reported element. Shares type versus Monetary unit]
  • 304-24-valid-ISO-unit-of-measue.xml [Valid ISO unit of measurement example]
  • 304-25-measure-reported-with-prefix-undefined-instance.xbrl [Measure reported with prefix undefined is considered XBRL invalid]
  • 304-26-monetaryItemTypeUnitsRestrictions.xml [Monetary item reported with unit having a denominator.]

Decimal and Precision Mutual Exclusion and prohibition on nil items [Section 4.4 Items]

  • 305-01-DecimalOnlySpecified.xml [305.01 item has only Decimals specified]
  • 305-02-PrecisionOnlySpecified.xml [305.02 item has only Precision specified]
  • 305-03-NoDecimalOrPrecisionSpecified.xml [305.03 item has neither Decimals nor Precision specified]
  • 305-04-BothDecimalAndPrecisionSpecified.xml [305.04 item has both Decimals and Precision specified]
  • 305-05-DecimalSpecifiedOnNilItem.xml [305.05 nil item has Decimals specified]
  • 305-06-PrecisionSpecifiedOnNilItem.xml [305.06 nil item has Precision specified]
  • 305_07_invalid_instance.xbrl [305.07 a genuine inconsistency due to roll up of child values]
  • 305-08-UnitsSpecifiedOnNilItem.xml [305.08 nil items have no decimals or precision, with unitref, but the type specifies fixed values for decimals and precision.]

Required Arc in Definition Linkbase [Section 5.5.6.4.1.5]

  • 306-01-RequiredInstanceValid.xml [306.01 The instance contains two elements in the same context. The presence of one element forces the presence of the other.]
  • 306-02-RequiredInstanceTupleValid.xml [306.02 The instance contains an item and a tuple. The presence of the tuple forces the presence of the item.]
  • 306-03-RequiredInstanceInvalid.xml [306.03 The instance contains an item and a tuple. The presence of the tuple forces the presence of the item.]

Schema References [Section 5 Taxonomies]

  • 307-01-SchemaRefExample.xml [307.01 A schemaRef element MUST hold the URI of a schema. In this case it does.]
  • 307-02-SchemaRefCounterExample.xml [307.01 A schemaRef element MUST hold the URI of a schema. In this case it does not because the second reference to a schema actually points to an XML document that is a label linkbase. ]
  • 307-03-SchemaRefXMLBase.xml [307.03 schemaRef elements MUST hold the URI of Schemas. In this case the requirement is not satisfied because the schema reference has to be resolved using the XML base attribute that ensures the schemaRef URI resolves to the XML document in the base directory. This document, however, is a label linkbase, not a schema. If the XML base attribute value is not used then the schema in the same directory as the instance is discovered and no issues are noticed.]

Duplicate instance roleRef and duplicate arcroleRefs [3.5.2.4.5 and 3.5.2.5.5 duplicate instance roleRef and arcroleRef elements.]

  • 308-01-instance.xml [Instance contains two role references to the same URI, INVALID]
  • 308-02-instance.xml [Instance contains two arcrole references to the same URI, INVALID]

LAX validation tests [Test that LAX validation is performed]

  • 314-lax-validation-01.xml [Segment has an element for which there is no definition, so it is allowed; item has an attribute with no definition, so it is allowed. The definitions are imported to the discovered taxonomy.]
  • 314-lax-validation-02.xml [Segment has an element for which there is no definition, so it is allowed; item has an attribute with no definition, so it is allowed. The definitions are found by schemaLocation from the instance document.]
  • 314-lax-validation-03.xml [Same as v-01 but segment has an element defined as integer with string contents]

Working with the PresentableFactTree

A previous post introduced the presentable fact tree: a tree of facts from an XBRL instance arranged in parent-child relationships according to the information in a presentation linkbase. This blog post will describe the tree structure returned by a call to XbrlFragment.GetPresentableFactTree().

Presentable Fact Tree

The XbrlFragment.GetPresentableFactTree() method returns an object of a class called PresentableFactTree. The PresentableFactTree class has one property:

List<PresentableFactTreeNode> TopLevelNodes

This property is a list of top-level presentable tree nodes, each of which is represented by a class called PresentableFactTreeNode. Unlike traditional trees in computer science, which have a single “root” node at the top, presentation linkbases do not necessarily define a single “root” top level node. Gepsio, therefore, must prepare for the scenario in which the presentation linkbase has multiple “top-level” nodes and defines a list of top level nodes in a presentable fact tree.

Presentable Fact Tree Nodes

All of the information in a tree is captured in a set of tree node objects of class PresentableFactTreeNode. The PresentableFactTreeNode class has several properties:

  • PresentableFactTreeNode ParentNode
  • Fact NodeFact
  • string NodeLabel
  • List<PresentableFactTreeNode> ChildNode

Let’s look at each one in detail.

ParentNode

The ParentNode property is simply a reference to the current node’s parent in the tree. This value may be null if the current node is a top level node which has no parent.

NodeFact

The NodeFact property is a reference to the XBRL fact represented by this node.

Remember that the Fact class is a base class, and the fact is actually an object of either the Item class (for single-value facts) or Tuple (for multi-value facts). Check the derived class and proceed accordingly, because the base Fact class has no value information at that level.

It is important to understand that the NodeFact property may be null. Some XBRL taxonomies define abstract elements, which have no values. These abstract elements nevertheless appear in presentation linkbases as a soft of “placeholder” for a row in a presentation without a value of its own. Consider the following presentation linkbase fragment:

  <link:presentationLink xlink:type="extended" xlink:role="http://www.aigcorporate.com/role/DisclosureEquity">
    <link:loc xlink:type="locator" xlink:href="http://xbrl.fasb.org/us-gaap/2012/elts/us-gaap-2012-01-31.xsd#us-gaap_StockholdersEquityNoteAbstract" xlink:label="StockholdersEquityNoteAbstract" xlink:title="StockholdersEquityNoteAbstract" />
    <link:loc xlink:type="locator" xlink:href="http://xbrl.fasb.org/us-gaap/2012/elts/us-gaap-2012-01-31.xsd#us-gaap_StockholdersEquityNoteDisclosureTextBlock" xlink:label="StockholdersEquityNoteDisclosureTextBlock" xlink:title="StockholdersEquityNoteDisclosureTextBlock" />
    <link:presentationArc xlink:type="arc" xlink:arcrole="http://www.xbrl.org/2003/arcrole/parent-child" xlink:from="StockholdersEquityNoteAbstract" xlink:to="StockholdersEquityNoteDisclosureTextBlock" xlink:title="presentation: StockholdersEquityNoteAbstract to StockholdersEquityNoteDisclosureTextBlock" use="optional" order="10.0" preferredLabel="http://www.xbrl.org/2003/role/terseLabel" />
  </link:presentationLink>

This fragment is a real world example which references an element called “us-gaap_StockholdersEquityNoteAbstract”. This element is defined in the associated taxonomy as an abstract element, and there is no actual value in the XBRL instance with this element. In this case, the element’s label should be displayed when a fact is null. This brings us to …

NodeLabel

The NodeLabel property contains the label for the tree node. Gepsio automatically pulls this information from the label linkbase, if it exists. If a label cannot be found, then this value is the empty string. This property is always available, regardless of whether or not the NodeFact is populated.

ChildNode

The ChildNode property is a list of child presentable fact tree nodes relative to the current node.

Sample Code

Here is a bit of sample code that walks a presentable fact tree and outputs the facts found in the tree:

public void WalkPresentableTree()
{
    var xbrlDoc = new XbrlDocument();
    xbrlDoc.Load("MyXbrlInstance.xml");
    var firstFragment = xbrlDoc.XbrlFragments[0];
    var tree = firstFragment.GetPresentableFactTree();
    foreach (var currentNode in tree.TopLevelNodes)
        WalkPresentableTreeNode(currentNode, 0);
}

private void WalkPresentableTreeNode(PresentableFactTreeNode node, int depth)
{

    // Indent as necessary, according to depth, so that parent child relationships
    // are shown.
    for (var indent = 0; indent < depth; indent++)
        Debug.Write("    ");

    // If the tree node has a fact, then display it.
    if (node.NodeFact != null)
    {

        // Display item details, if this fact is actually an item.
        // Tuples are not supported in this code sample.
        if (node.NodeFact is Item)
        {
            var nodeItem = node.NodeFact as Item;
            Debug.Write(nodeItem.Name);
            Debug.Write(" ");
            Debug.Write(nodeItem.Value);
        }
    }
    else
    {

        // If there is no fact for this node, then display the label.
        Debug.Write(node.NodeLabel);
    }
    Debug.WriteLine("");

    // Recursively call into this same method for each of the node's
    // child nodes, increasing the depth by one so that the indenting
    // reflects the child nodes.
    foreach (var childNode in node.ChildNodes)
        WalkPresentableTreeNode(childNode, depth + 1);
}

An initial, un-optimized implementation of the presentable fact tree support has been checked in to Codeplex and will be available in binary form when the next CTP is released (tentatively scheduled for Sat 01 Aug 2015).

Introducing the Presentable Fact Tree

At a very high level, XBRL instances are sets of key/value pairs: the key is the fact and the value is the fact’s value:

Fact Value
EntityRegistrantName AMERICAN INTERNATIONAL GROUP INC
EntityCentralIndexKey 0000005272
DocumentType 10-Q
DocumentPeriodEndDate 2013-06-30

There is no inherent structure to the list of facts in an XBRL instance: the instance is simply a large table of facts and values. Gepsio exposes the Facts property from an XbrlFragment object to allow callers to get at this list of facts and their values.

However, from an accounting perspective, these facts do have relationships to each other, and some of the facts are higher level aggregated values representing some lower level facts. When these facts are displayed in forms such as Consolidated Balance Sheets, this relationship between facts is plainly visible. Take a look here at Google’s 10-Q statement from Jun 30 2012. Scroll down to the Financial Statements and see, for example, that Current assets includes

  • Cash and cash equivalents
  • Marketable securities
  • Total cash, cash equivalents, and marketable securities
  • Accounts receivable
  • Inventories
  • Receivable under reverse repurchase agreements
  • Deferred income taxes, net
  • Prepaid revenue share, expenses and other assets

XBRL supports a linkbase called the presentation linkbase, which describes the relationships between facts so that, with some code, the list of facts can be turned into a more presentable table with parent/child fact relationships shown as the facts would be shown on a financial statement. Gepsio has supported the reading of the presentation linkbase in previous CTPs, but never offered away to turn the raw list of facts into a representation of a parent/child relationship model which mirrors the data in the presentation linkbase.

Very shortly, a first cut at a new XbrlFragment method called GetPresentableFactTree() will be added to the Gepsio code. This method will return a tree-like structure that arranges an XBRL instance’s list of facts into a set of parent/child relationships based on the information in a presentation linkbase, all in one line of code (the linear Facts collection in an XbrlFragment will not be modified by this call and will still be available at all times). The code would look something like this:

var xbrlDoc = new XbrlDocument();
xbrlDoc.Load("aig-20130630.xml");
var firstFragment = xbrlDoc.XbrlFragments[0];
var tree = firstFragment.GetPresentableFactTree();

A future blog post will describe the structure returned by GetPresentableFactTree() and how developers can use it to build up fact-based displays which reflect the  information in a parent/child relationship.

Where Did The Segment Property Go?

The following email came into the Gepsio email inbox not long ago:

I upgraded to your latest release btw but it looks like the Segment object was removed. How do I access Dimensions and Segments now?
Thanks

The user had been using the Sep 2013 CTP [version 2.1.0.7] and had been using it to write code like this:

// this item has a dimension (grouped) 
if (item.ContextRef.Segment != null)
{
    foreach (System.Xml.XmlNode node in item.ContextRef.Segment)
    {
        //Insert_Dimension(FactItemID, node.Attributes["dimension"].Value, node.InnerText);
        ddi.NewRow(FactItemID, node.Attributes["dimension"].Value, node.InnerText);
    }
}

The short answer is that – oops! – the Segment property was moved from public visibility to internal visibility in the Nov 2014 CTP [2.1.0.8], and that change was retained in the May 2015 CTP [2.1.0.9]. It will be moved back to public visibility in the next CTP, but an explanation for the change is in order.

The Segment Property in the Sep 2013 CTP

In the Sep 2013 CTP, the public Segment property was a property of the Context class. It was of type System.Xml.XmlNode and was documented as follows:

The segment node defined for this context. If this context was not marked up with a segment node, then this property will return null.

This property was made available in support of section 4.7.3.2 of the XBRL 2.1 specification, which describes an optional <segment> child element of a <context> element:

The  <segment>  element is an optional container for additional mark-up that the preparer of an XBRL Instance SHOULD use to identify the business segment more completely in cases where the Entity identifier is insufficient. In general, the content of a  <segment>  will be specific to the purpose of the XBRL instance. Elements contained by the  <segment>  element MUST NOT be defined in the http://www.xbrl.org/2003/instance namespace. Also, they MUST NOT be in the substitution group for elements defined in the http://www.xbrl.org/2003/instance namespace. The  <segment>  element MUST NOT be empty.

The XBRL 2.1 specification does not associate any semantics with the <segment> element; therefore, Gepsio could not define an object model around this element, since it is documented as an optional container containing zero or more elements whose semantics were presumably documented elsewhere. Therefore, Gepsio could only expose the element, if it existed, as a generic XmlNode.

Introducing the Interface-Based XML Layer

On 18 July 2014, a changeset was checked in which changed Gepsio’s relationship to the .NET 3.5 XML DOM classes. This change was first published in a build in the Nov 2014 CTP and continued on in the May 2015 CTP. This change removed Gepsio’s direct dependency on the .NET 3.5 XML DOM classes and, instead, moved the support behind a set of internally-defined interfaces. The change introduced interfaces to handle all of the XML work, as well as classes that implemented the interface using the .NET 3.5 XML DOM classes. So, with this design, instead of Gepsio calling something like XmlDocument.Load() to load an XBRL document instance, it called an interface method called IDocument.Load(). The IDocument.Load() interface implementation called XmlDocument.Load() in its implementation.

The rationale behind moving Gepsio’s XML layer behind an interface was to make it easier to support other XML implementations in the future. The future of Gepsio, and its possible reach beyond purely .NET and possibly into other areas, whether it be as a Portable Class Library, as a library that would support Xamarin, or as a library that would support the Universal Windows Platform, means that Gepsio may need to be modified at its lowest level XML layer. For example, The Portable Class Library does not support the .NET 3.5 XML DOM classes. Instead, it supports only the LINQ-to-XML classes. Once XML is loaded, Gepsio is pretty portable, but the XML layer could potentially be a porting problem down the road should the XML runtime need to change.

Moving all of Gepsio’s low level XML needs behind an interface, and implementing the interface in a set of classes that Gepsio would actually be using, makes it easier to change the XML layer later on, should the need arise, without disturbing the rest of the Gepsio code base. Moving, for example, from the .NET 3.5 XML DOM classes to LINQ-to-XML would be a (theoretically) simple matter of implementing the internal XML interfaces in classes that used LINQ-to-XML. Gepsio’s higher levels of code – the XBRL semantics – would not need to change.

Interfaces and the Segment Property

The issue with the interface implementation with regards to the Segment property is that things like System.Xml.XmlNode, which were originally exposed as the type of the Segment property, are now behind an interface. With the XML interface design, Gepsio no longer sees a System.Xml.XmlNode object directly. Instead, it sees an internally-defined INode interface, and System.Xml.XmlNode is hidden behind the implementation of INode. With the interface design change, the Segment property in question would need to have its type changed from System.Xml.XmlNode to INode. The problem there is that INode is defined internally by Gepsio, and external callers, such as the code shown above, have no knowledge of INode. Failing that understanding, the Segment property could not be exposed, so the property was moved to be private in the Nov 2014 CTP.

The Road Forward

Since folks are, in fact, using the Segment property for Dimensions work (and, failing Gepsio’s first-party support for Dimensions, which needs to get on the project roadmap), then the Segment property will once again need to go public. Work will, therefore, progress in getting the XML interfaces documented so that people can use an internally-defined INode implementation to do work with segment nodes. This work is underway now.