コード例 #1
0
        /// <summary>
        /// A definition network attaches one (or at least one?) hypercube to a concept.
        /// </summary>
        /// <remarks>
        /// The role of some definition linkbases have a suffix (a, b, ...) added to the role of the presentation network.
        /// We have to disregard this suffix to reliably find the attached hypercubes.
        ///
        /// For example, for the presentation network with the role http://xbrl.ifrs.org/role/ifrs/ias_19_2017-03-09_role-834480
        /// there exist these definition network roles, each defining a single hypercube:
        /// http://xbrl.ifrs.org/role/ifrs/ias_19_2017-03-09_role-834480
        /// http://xbrl.ifrs.org/role/ifrs/ias_19_2017-03-09_role-834480a
        /// http://xbrl.ifrs.org/role/ifrs/ias_19_2017-03-09_role-834480b
        /// http://xbrl.ifrs.org/role/ifrs/ias_19_2017-03-09_role-834480c
        /// http://xbrl.ifrs.org/role/ifrs/ias_19_2017-03-09_role-834480d
        /// (All bundled inside the def_ias_19_2017-03-09_role-834480.xml linkbase)
        ///
        /// Clearly, the authors of the IFRS taxonomy wanted to have a single hypercube per definition link.
        /// Question: is that a requirement from XBRL Dimensions?
        /// </remarks>
        /// <remarks>
        /// A hypercube arc (all or notAll) connects to a *concept* inside a specific presentation network, which is not actually precise.
        /// Instead, it should attach to a *locator node*.
        /// The same issue appears with extensions of existing presentation, definition or calculation networks.
        /// </remarks>
        private Hypercube GetAttachedHypercube(LocatorNode node)
        {
            var item = node.Item;

            // Oddly, the role of some definition linkbase have a suffix (a, b, ...) added to the role of the presentation network.
            // We have to disregard this suffix to reliably find the attached hypercubes.
            var hypercubeArc = item.Nodes
                               .SelectMany(n => n.FromArcs.OfType <DefinitionArc>())
                               .SingleOrDefault(a => a.Link.Role.AbsoluteUri.StartsWith(node.Link.Role.AbsoluteUri) && a.Role == ArcRoles.PositiveHypercube);

            if (hypercubeArc == null)
            {
                return(null);
            }

            var hypercube = new Hypercube(hypercubeArc.ToLocator.Item);

            var dimensionNodes = hypercubeArc.ToLocator.FromArcs.OfType <DefinitionArc>().Select(a => a.ToLocator);

            foreach (var dimensionNode in dimensionNodes)
            {
                var axis = BuildHypercubeAxis(dimensionNode);
                hypercube.Axes.Add(axis);
            }

            return(hypercube);
        }
コード例 #2
0
        private ConceptMember TraversePresentationNetwork(LocatorNode node, Uri preferredLabelRole, ISet <XName> hypercubeDimensionNames)
        {
            var concept = node.Item;

            var aspect = new ConceptAspect(concept.Name);
            var member = new ConceptMember(aspect)
            {
                Item = concept,
                PreferredLabelRole = preferredLabelRole,
                Label = concept.FindLabel(preferredLabelRole),
                HypercubeDimensionNames = hypercubeDimensionNames
            };

            var outgoingArcs = node.GetOrderedOutgoingHierarchicalArcs <PresentationArc>();

            var attachedHypercube = GetAttachedHypercube(node);

            if (attachedHypercube != null)
            {
                if (outgoingArcs.Count != 1)
                {
                    throw new InvalidOperationException($"The hypercube {attachedHypercube.HypercubeItem.Name} has {outgoingArcs.Count} line items children, but exactly one is expected.");
                }

                var outgoingArc = outgoingArcs.Single();

                // We are replicating and adding the line items tree for each axis, including the respective dimension name to each concept member.
                foreach (var hypercubeAxis in attachedHypercube.Axes)
                {
                    var childHypercubeDimensionNames = new HashSet <XName>(hypercubeDimensionNames)
                    {
                        hypercubeAxis.Dimension.Name
                    };
                    var child = TraversePresentationNetwork(outgoingArc.ToLocator, outgoingArc.PreferredLabelRole, childHypercubeDimensionNames);
                    child.HypercubeAxis = hypercubeAxis;
                    member.AddChild(child);
                }
            }
            else
            {
                foreach (var outgoingArc in outgoingArcs)
                {
                    var child = TraversePresentationNetwork(outgoingArc.ToLocator, outgoingArc.PreferredLabelRole, hypercubeDimensionNames);
                    member.AddChild(child);
                }
            }

            return(member);
        }
コード例 #3
0
        private Axis BuildHypercubeAxis(LocatorNode dimensionNode)
        {
            var rootNodes = dimensionNode.FromArcs.OfType <DefinitionArc>()
                            .Where(a => a.Role == ArcRoles.DimensionToDomain)
                            .Select(a => a.ToLocator)
                            .ToList();

            // Just like for presentation networks, the IFRS taxonomy only has single roots for hypercube dimensions.
            if (rootNodes.Count > 1)
            {
                throw new InvalidOperationException($"The hypercube dimension {dimensionNode.Item.Name} has multiple root nodes.");
            }

            var dimension   = new Dimension(dimensionNode.Item.Name);
            var rootMembers = rootNodes.Select(n => TraverseHypercubeDimension(n, dimension)).ToList();

            return(new Axis(dimension, dimension.Name, rootMembers));
        }
コード例 #4
0
        private ExplicitMember TraverseHypercubeDimension(LocatorNode node, Dimension dimension)
        {
            var memberItem = node.Item;
            var aspect     = new ExplicitMemberAspect(dimension, memberItem.Name);
            var member     = new ExplicitMember(aspect)
            {
                Item  = memberItem,
                Label = memberItem.FindLabel(LabelRoles.Standard)
            };

            var outgoingArcs = node.GetOrderedOutgoingHierarchicalArcs <DefinitionArc>();

            foreach (var outgoingArc in outgoingArcs)
            {
                var child = TraverseHypercubeDimension(outgoingArc.ToLocator, dimension);
                member.AddChild(child);
            }

            return(member);
        }
コード例 #5
0
        private LocatorNode FindParentNode(LocatorNode locatorNode, XName parentName)
        {
            if (locatorNode.Item.Name == parentName)
            {
                return(locatorNode);
            }

            var outgoingArcs = locatorNode.GetOrderedOutgoingHierarchicalArcs <DefinitionArc>();

            foreach (var outgoingArc in outgoingArcs)
            {
                var childResult = FindParentNode(outgoingArc.ToLocator, parentName);
                if (childResult != null)
                {
                    return(childResult);
                }
            }

            return(null);
        }
コード例 #6
0
        private Linkbase CreateDefinitionLinkbase(Taxonomy taxonomy, DiscoverableTaxonomySet dts)
        {
            var linkbase = new Linkbase(GetLinkbaseFileName(taxonomy, "def"));

            var memberItems = ExtensionItems.OfType <ExtensionMember>().ToList();

            var groupedByHypercube = memberItems.SelectMany(i => i.Locations.Select(l =>
                                                                                    new { l.HypercubeName, Location = l, Item = i }))
                                     .GroupBy(d => d.HypercubeName)
                                     .ToList();

            foreach (var groupByHypercube in groupedByHypercube)
            {
                var hypercubeNode = dts.GetAllLinks()
                                    .Where(l => l.ElementName == LinkbaseXNames.Definition)
                                    .SelectMany(l => l.NodesMap.Values)
                                    .OfType <LocatorNode>()
                                    .SingleOrDefault(ln => ln.Item.Name == groupByHypercube.Key);
                if (hypercubeNode == null)
                {
                    throw new InvalidOperationException($"Could not find a hypercube (aka table) {groupByHypercube.Key} in the DTS.");
                }

                var definitionLink = new DefinitionLink(LinkbaseXNames.Definition, hypercubeNode.Link.Role);
                linkbase.AddLink(definitionLink, dts);

                var locCount = 0;
                foreach (var locationAndItem in groupByHypercube)
                {
                    var dimensionLocationNode = hypercubeNode.FromArcs
                                                .OfType <DefinitionArc>()
                                                .Select(da => da.ToLocator)
                                                .SingleOrDefault(ln => ln.Item.Name == locationAndItem.Location.DimensionName);

                    if (dimensionLocationNode == null)
                    {
                        throw new InvalidOperationException($"Could not find a dimension (aka axis) {locationAndItem.Location.DimensionName} in the hypercube (aka table) {groupByHypercube.Key}.");
                    }

                    var parentNodeInBaseTaxonomy = FindParentNode(dimensionLocationNode, locationAndItem.Location.ParentName);
                    if (parentNodeInBaseTaxonomy == null)
                    {
                        throw new InvalidOperationException($"There is no member {locationAndItem.Location.ParentName} in the dimension {groupByHypercube.Key}.");
                    }

                    var siblingArcs = parentNodeInBaseTaxonomy.GetOrderedOutgoingHierarchicalArcs <DefinitionArc>();

                    double newOrder;
                    try
                    {
                        newOrder = DetermineOrder(locationAndItem.Location.PrecedingSiblingName, siblingArcs);
                    }
                    catch (InvalidOperationException ex)
                    {
                        throw new InvalidOperationException($"The sibling {locationAndItem.Location.PrecedingSiblingName} was not found as a child of {locationAndItem.Location.ParentName} in the dimension {groupByHypercube.Key}.", ex);
                    }

                    var parentLocLabel = $"loc_{locCount}";
                    locCount += 1;
                    var parentNode = new LocatorNode(parentLocLabel, parentNodeInBaseTaxonomy.Item);
                    definitionLink.AddNode(parentNode);

                    var locLabel = $"loc_{locCount}";
                    locCount += 1;
                    var locNode = CreateLocatorNode(locLabel, locationAndItem.Item, dts);
                    definitionLink.AddNode(locNode);

                    var arc = new DefinitionArc(parentNode, locNode, newOrder);
                    definitionLink.AddArc(arc);
                }
            }

            return(linkbase);
        }
コード例 #7
0
        private Linkbase CreatePresentationLinkbase(Taxonomy taxonomy, DiscoverableTaxonomySet dts)
        {
            var conceptItems = ExtensionItems.OfType <ExtensionConcept>().ToList(); // Does that include abstracts?

            var linkbase = new Linkbase(GetLinkbaseFileName(taxonomy, "pre"));

            var groupedByNetworkRole = conceptItems.SelectMany(i => i.Locations.Select(l =>
                                                                                       new { l.NetworkRole, Location = l, Item = i }))
                                       .GroupBy(d => d.NetworkRole)
                                       .ToList();

            foreach (var groupByNetworkRole in groupedByNetworkRole)
            {
                var presentationLink = new PresentationLink(LinkbaseXNames.Presentation, groupByNetworkRole.Key);
                linkbase.AddLink(presentationLink, dts);

                var locCount = 0;
                foreach (var locationAndItem in groupByNetworkRole)
                {
                    var parentItem = dts.FindItem(locationAndItem.Location.ParentName);
                    if (parentItem == null)
                    {
                        throw new InvalidOperationException($"There is no concept {locationAndItem.Location.ParentName} in the DTS.");
                    }

                    var parentLocatorNodes = parentItem.Nodes
                                             .Where(n => n.Link.Role == groupByNetworkRole.Key).ToList();
                    if (!parentLocatorNodes.Any())
                    {
                        throw new InvalidOperationException($"The concept {locationAndItem.Location.ParentName} is not in the presentation network {groupByNetworkRole.Key}.");
                    }

                    var siblingArcs = parentLocatorNodes.First().GetOrderedOutgoingHierarchicalArcs <PresentationArc>();

                    double newOrder;
                    try
                    {
                        newOrder = DetermineOrder(locationAndItem.Location.PrecedingSiblingName, siblingArcs);
                    }
                    catch (InvalidOperationException ex)
                    {
                        throw new InvalidOperationException($"The sibling {locationAndItem.Location.PrecedingSiblingName} was not found as a child of {locationAndItem.Location.ParentName} in the presentation network {groupByNetworkRole.Key}.", ex);
                    }

                    var parentLocLabel = $"loc_{locCount}";
                    locCount += 1;
                    var parentNode = new LocatorNode(parentLocLabel, parentItem);
                    presentationLink.AddNode(parentNode);

                    var childLocLabel = $"loc_{locCount}";
                    locCount += 1;
                    var childNode = CreateLocatorNode(childLocLabel, locationAndItem.Item, dts);
                    presentationLink.AddNode(childNode);

                    var arc = new PresentationArc(parentNode, childNode, newOrder, locationAndItem.Location.PreferredLabelRole);
                    presentationLink.AddArc(arc);
                }
            }

            return(linkbase);
        }