예제 #1
0
        /// <summary>
        /// Locates all items in the given collection of facts that match the current element.
        /// </summary>
        /// <param name="ItemElement">
        /// The element describing the items to be found.
        /// </param>
        /// <param name="FactList">
        /// The collection of items that should be searched.
        /// </param>
        /// <returns>
        /// A collection of items that match the current element. If no items match,
        /// a non-null List will still be returned, but the list will be empty.
        /// </returns>
        /// <remarks>
        /// This method should most likely be moved into a class which wraps <see cref="Item"/>
        /// collections with a value-added wrapper class.
        /// </remarks>
        private List <Item> LocateItems(Element ItemElement, FactCollection FactList)
        {
            var ItemList = new List <Item>();

            if (ItemElement != null)
            {
                foreach (Fact CurrentFact in FactList)
                {
                    if ((CurrentFact is Item) == true)
                    {
                        var CurrentItem = CurrentFact as Item;
                        if (CurrentItem.SchemaElement.Equals(ItemElement) == true)
                        {
                            ItemList.Add(CurrentItem);
                        }
                    }
                    else if ((CurrentFact is Tuple) == true)
                    {
                        var currentTuple = CurrentFact as Tuple;
                        var tupleList    = LocateItems(ItemElement, currentTuple.Facts);
                        ItemList.AddRange(tupleList);
                    }
                }
            }
            return(ItemList);
        }
예제 #2
0
        public static void ParseFacts(XDocument report, Instance instance)
        {
            var factElements = FindFacts(report);
            var facts        = new FactCollection(instance);

            foreach (var factElement in factElements)
            {
                var name     = factElement.Attribute("name").Value;
                var prefix   = name.Split(':').First();
                var ns       = report.Root.GetNamespaceOfPrefix(prefix).ToString();
                var unitRef  = factElement.Attribute("unitRef")?.Value;
                var decimals = factElement.Attribute("decimals")?.Value;
                var value    = factElement.Value;
                var scale    = factElement.Attribute("scale")?.Value;

                if (!string.IsNullOrWhiteSpace(scale))
                {
                    var power      = int.Parse(scale);
                    var v          = decimal.Parse(value.Replace(" ", ""));
                    var multiplier = (decimal)Math.Pow(10, power);
                    v    *= multiplier;
                    value = v.ToString();
                }

                var contextRef = factElement.Attribute("contextRef").Value;
                var fact       = new Fact(name, ns, unitRef, decimals, contextRef, value);
                facts.Add(fact);
            }
            foreach (var fact in facts)
            {
                instance.Facts.Add(fact);
            }
        }
예제 #3
0
 /// <summary>
 /// Validate the essence alias between a given fact and all other facts with the given fact name.
 /// </summary>
 /// <remarks>
 /// <para>
 /// An essence alias is a relationship between a "from" item and a "to" item. The "from" item and
 /// the "to" item must be identical. This method is given the "from" item and must search for the
 /// corresponding "to" item.
 /// </para>
 /// <para>
 /// The scoping of the search for the corresponding "to" item is important. In the simple case, an
 /// XBRL fragment has only items, and the search for the corresponding "to" item can be conducted
 /// in the list all of all items in the fragment.
 /// </para>
 /// <para>
 /// However, if the "from" item is found in a tuple, then the list of items from which the "to" item
 /// is to be found must be restricted to the other items in the tuple and not simply the set of all
 /// items in the fragment.
 /// </para>
 /// </remarks>
 /// <param name="FromItem">
 /// The item that represents the "from" end of the essence alias relationship.
 /// </param>
 /// <param name="FactList">
 /// The list of facts that should be searched to find the item that represents the "to" end of the essence alias relationship.
 /// </param>
 /// <param name="ToItemName">
 /// The name of the item that represents the "to" end of the essence alias relationship.
 /// </param>
 private void ValidateEssenceAliasedFacts(Item FromItem, FactCollection FactList, string ToItemName)
 {
     foreach (Fact CurrentFact in FactList)
     {
         var CurrentItem = CurrentFact as Item;
         if (CurrentItem != null)
         {
             if (CurrentFact.Name.Equals(ToItemName) == true)
             {
                 ValidateEssenceAliasedFacts(FromItem, CurrentItem);
             }
         }
     }
 }
예제 #4
0
 /// <summary>
 /// Validate context references for all facts in the given fact collection.
 /// </summary>
 /// <param name="FactList">
 /// A collection of facts whose contexts should be validated.
 /// </param>
 private void ValidateContextRefs(FactCollection FactList)
 {
     foreach (Fact CurrentFact in FactList)
     {
         if (CurrentFact is Item)
         {
             ValidateContextRef(CurrentFact as Item);
         }
         else if (CurrentFact is Tuple)
         {
             var CurrentTuple = CurrentFact as Tuple;
             ValidateContextRefs(CurrentTuple.Facts);
         }
     }
 }
예제 #5
0
 /// <summary>
 /// Locates an item in a list of facts.
 /// </summary>
 /// <param name="ItemElement">
 /// A schema element defining the item to be found.
 /// </param>
 /// <param name="FactList">
 /// The collection of items that should be searched.
 /// </param>
 /// <returns>
 /// A reference to the first item that matches the given element, or null if no matching item is found.
 /// </returns>
 /// <remarks>
 /// This method should most likely be moved into a class which wraps <see cref="Item"/>
 /// collections with a value-added wrapper class.
 /// </remarks>
 private Item LocateItem(Element ItemElement, FactCollection FactList)
 {
     if (ItemElement == null)
     {
         return(null);
     }
     foreach (Fact CurrentFact in FactList)
     {
         var CurrentItem = CurrentFact as Item;
         if (CurrentItem != null)
         {
             if (CurrentItem.SchemaElement.Equals(ItemElement) == true)
             {
                 return(CurrentItem);
             }
         }
     }
     return(null);
 }
예제 #6
0
        /// <summary>
        /// Validates a given summation concept.
        /// </summary>
        /// <param name="CurrentCalculationLink">
        /// The calculation link that defines the given summation concept.
        /// </param>
        /// <param name="CurrentSummationConcept">
        /// The summation concept to be validated.
        /// </param>
        /// <param name="FactList">
        /// The collection of items that should be searched when looking for summation or contributing items.
        /// </param>
        private void ValidateSummationConcept(CalculationLink CurrentCalculationLink, SummationConcept CurrentSummationConcept, FactCollection FactList)
        {
            Element SummationConceptElement = LocateElement(CurrentSummationConcept.SummationConceptLocator);
            Item    SummationConceptItem    = LocateItem(SummationConceptElement, FactList);

            // If the summation concept item doesn't exist, then there is no calculation
            // to perform.

            if (SummationConceptItem == null)
            {
                return;
            }

            // If the summation concept item has a "nil" value, then there is no calculation
            // to perform.

            if (SummationConceptItem.NilSpecified == true)
            {
                return;
            }

            double SummationConceptRoundedValue         = SummationConceptItem.RoundedValue;
            double ContributingConceptRoundedValueTotal = 0;
            var    ContributingConceptItemsFound        = false;
            var    AtLeastOneItemWithZeroPrecision      = false;

            foreach (Locator CurrentLocator in CurrentSummationConcept.ContributingConceptLocators)
            {
                // Some decisions need to be made before the code can actually add the value of the
                // contributing concept to the total that the code is keeping.

                var IncludeContributingConceptItemInCalculation = true;

                // Find the calculation arc for the given calculation link.

                CalculationArc ContributingConceptCalculationArc = CurrentCalculationLink.GetCalculationArc(CurrentLocator);
                if (ContributingConceptCalculationArc == null)
                {
                    IncludeContributingConceptItemInCalculation = false;
                }

                // Find the elemement for the given locator.

                Element ContributingConceptElement = LocateElement(CurrentLocator);
                if (ContributingConceptElement == null)
                {
                    IncludeContributingConceptItemInCalculation = false;
                }

                // Find all items for the given element. If there is more than one, and at least
                // one of them is not p-equals with at least one of the other ones, then
                // the entire calculation validation is forfeit, according to test 397.12 in
                // the XBRL-CONF-CR3-2007-03-05 conformance suite.

                var AllMatchingItems = LocateItems(ContributingConceptElement, FactList);
                if (AllItemsNotPEquals(AllMatchingItems) == false)
                {
                    return;
                }

                // Find the item for the given element.

                if (AllMatchingItems.Count == 0)
                {
                    IncludeContributingConceptItemInCalculation = false;
                }
                else
                {
                    foreach (var ContributingConceptItem in AllMatchingItems)
                    {
                        if (IncludeContributingConceptItemInCalculation == true)
                        {
                            IncludeContributingConceptItemInCalculation = ContributingConceptItemEligibleForUseInCalculation(ContributingConceptItem, SummationConceptItem);
                        }
                        if (IncludeContributingConceptItemInCalculation == true)
                        {
                            ContributingConceptItemsFound = true;
                            if ((ContributingConceptItem.PrecisionSpecified == true) && (ContributingConceptItem.Precision == 0) && (ContributingConceptItem.InfinitePrecision == false))
                            {
                                AtLeastOneItemWithZeroPrecision = true;
                            }
                            double ContributingConceptRoundedValue = ContributingConceptItem.RoundedValue;
                            if (ContributingConceptCalculationArc.Weight != (decimal)(1.0))
                            {
                                ContributingConceptRoundedValue = ContributingConceptRoundedValue * (double)(ContributingConceptCalculationArc.Weight);
                            }
                            ContributingConceptRoundedValueTotal += ContributingConceptRoundedValue;
                        }
                    }
                }
            }
            if (ContributingConceptItemsFound == true)
            {
                if (AtLeastOneItemWithZeroPrecision == true)
                {
                    var    MessageBuilder = new StringBuilder();
                    string StringFormat   = AssemblyResources.GetName("SummationConceptUsesContributingItemWithPrecisionZero");
                    MessageBuilder.AppendFormat(StringFormat, SummationConceptItem.Name);
                    ValidatedFragment.AddValidationError(new SummationConceptValidationError(CurrentSummationConcept, MessageBuilder.ToString()));
                    return;
                }
                ContributingConceptRoundedValueTotal = SummationConceptItem.Round(ContributingConceptRoundedValueTotal);
                if (SummationConceptRoundedValue != ContributingConceptRoundedValueTotal)
                {
                    var    MessageBuilder = new StringBuilder();
                    string StringFormat   = AssemblyResources.GetName("SummationConceptError");
                    MessageBuilder.AppendFormat(StringFormat, SummationConceptItem.Name, SummationConceptRoundedValue, ContributingConceptRoundedValueTotal);
                    ValidatedFragment.AddValidationError(new SummationConceptValidationError(CurrentSummationConcept, MessageBuilder.ToString()));
                    return;
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Validate the essence alias between two facts referenced in a definition arc using
        /// the set of all facts in the fragment.
        /// </summary>
        /// <param name="EssenceAliasDefinitionArc">
        /// The definition arc defining the essence alias.
        /// </param>
        /// <param name="FactList">
        /// A collection of <see cref="Fact"/> objects defined in the fragment.
        /// </param>
        private void ValidateEssenceAliasedFacts(DefinitionArc EssenceAliasDefinitionArc, FactCollection FactList)
        {
            Locator CurrentFromLocator = EssenceAliasDefinitionArc.FromLocator;

            if (CurrentFromLocator == null)
            {
                throw new NullReferenceException("FromLocator is NULL in ValidateEssenceAliasedFacts()");
            }
            Locator CurrentToLocator = EssenceAliasDefinitionArc.ToLocator;

            foreach (Fact CurrentFact in FactList)
            {
                if (CurrentFact is Item)
                {
                    var CurrentItem = CurrentFact as Item;
                    if (CurrentItem.Name.Equals(CurrentFromLocator.HrefResourceId) == true)
                    {
                        ValidateEssenceAliasedFacts(CurrentItem, FactList, CurrentToLocator.HrefResourceId);
                    }
                }
                else if (CurrentFact is Tuple)
                {
                    var CurrentTuple = CurrentFact as Tuple;
                    ValidateEssenceAliasedFacts(EssenceAliasDefinitionArc, CurrentTuple.Facts);
                }
            }
        }