Namespaces and explicitMember namespace prefix

Hi,

I am currently evaluating your library within our project at my company for a potential purchase.

I have a few questions, as the provided examples do not fully address my requirements. Specifically, I am working on creating an XBRL file in the context of CSRD and the European taxonomy developed by eFrag.

  1. How are all XML namespaces declared? I need clarification because I am unable to declare them manually.
  2. I am encountering an issue with explicit members of dimensions within a scenario. The code redefines a namespace with a random prefix, and I am unsure how to ensure it uses the correct namespace (which is already declared for the fact).

Thank you in advance for your assistance.

NB : below an example of the xbrl generated, if you need some piece of code please tell me.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<xbrl xmlns="http://www.xbrl.org/2003/instance" xmlns:xbrli="http://www.xbrl.org/2003/instance" xmlns:link="http://www.xbrl.org/2003/linkbase" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:esrs_entry="https://xbrl.efrag.org/taxonomy/esrs/2023-12-22/entry" xmlns:dtr-types="http://www.xbrl.org/dtr/type/2022-03-31" xmlns:xbrldt="http://xbrl.org/2005/xbrldt" xmlns:glgqdllj="https://xbrl.efrag.org/taxonomy/esrs/2023-12-22" xmlns:esrs="https://xbrl.efrag.org/taxonomy/esrs/2023-12-22/entry" xmlns:xbrldi="http://xbrl.org/2006/xbrldi">
  <link:schemaRef xlink:type="simple" xlink:href="https://xbrl.efrag.org/taxonomy/esrs/2023-12-22/esrs_all.xsd" />
  <context id="c_0">
    <entity />
    <period>
      <startDate>2024-01-01</startDate>
      <endDate>2024-12-31</endDate>
    </period>
  </context>
  <context id="c_1">
    <entity />
    <period>
      <startDate>2024-01-01</startDate>
      <endDate>2024-12-31</endDate>
    </period>
    <scenario>
      <xbrldi:explicitMember dimension="glgqdllj:GenderAxis">glgqdllj:FemaleMember</xbrldi:explicitMember>
    </scenario>
  </context>
  <context id="c_2">
    <entity />
    <period>
      <startDate>2024-01-01</startDate>
      <endDate>2024-12-31</endDate>
    </period>
    <scenario>
      <xbrldi:explicitMember dimension="glgqdllj:GenderAxis">glgqdllj:MaleMember</xbrldi:explicitMember>
    </scenario>
  </context>

@Deboveq

Could you please provide more details about the specific issues you are facing with declaring XML namespaces and the explicit members of dimensions? Additionally, if you have any code snippets that illustrate the problem, please share them.

@Professionalize.Discourse

Thank you for your answer, here is the Builder I use (every parameter are POCO for encapsulation):

internal class XBRLCreationBuilder : IXBRLCreationBuilder
{
    private readonly Dictionary<string, Context> Contexts = [];
    private readonly Dictionary<string, Unit> Units = [];
    public readonly List<ValidationErrorForXBRL> ValidationsErrors = [];

    private readonly XbrlDocument Document;
    private readonly SchemaRef Schema;
    private readonly XbrlInstance XBRLInstance;

    internal XBRLCreationBuilder()
    {
        Document = new();
        (XBRLInstance, Schema) = SetupDocument();
    }

    public void AddContext(ContextForXBRL contextForXBRL)
    {
        if(!Contexts.ContainsKey(contextForXBRL.ToString())) {
            ContextPeriod period = contextForXBRL.Period.EndDate.HasValue ? new(contextForXBRL.Period.StartDate.Value, contextForXBRL.Period.EndDate.Value) : new(contextForXBRL.Period.StartDate.Value);
            ContextEntity entity = new(contextForXBRL.Entity.Scheme, contextForXBRL.Entity.Identifier);
            Context context = new (period, entity);

            if(contextForXBRL.IsArrayContext) {
                context.Scenario = new ContextSenario();
                contextForXBRL.Scenario.TypedDimensions.ForEach((KeyValuePair<string, string> pair) => {
                    Concept typedConcept = GetConceptByXbrlCode(pair.Key);
                    Concept explicitConcept = GetConceptByXbrlCode(pair.Value);

                    context.Scenario.DimensionMemberList.Add(new DimensionMember(typedConcept, explicitConcept));
                });
                contextForXBRL.Scenario.ExplicitDimensions.ForEach((KeyValuePair<string, string> pair) => {
                    Concept typedConcept = GetConceptByXbrlCode(pair.Key);
                    Concept explicitConcept = GetConceptByXbrlCode(pair.Value);

                    context.Scenario.DimensionMemberList.Add(new DimensionMember(typedConcept, explicitConcept));
                });
            }
            
            context.Id = $"c_{Contexts.Count}";
            Contexts.Add(contextForXBRL.ToString(), context);
            XBRLInstance.Contexts.Add(context);
        }
    }

    public void AddFact(IndicatorForXBRL indicatorForXBRL, IndicatorValueForXBRL indicatorValueForXBRL)
    {
        AddContext(indicatorValueForXBRL.Context);
        // TODO check if good because in the xbrl norm, normally the unit is mandatory
        if(indicatorValueForXBRL.Unit != null)
        {
            AddUnit(indicatorValueForXBRL.Unit);
        }
        
        Concept concept = GetConceptByXbrlCode(indicatorForXBRL.XbrlCode);

        if(concept != null)
        {
            Item fact = new(concept)
            {
                ContextRef = Contexts[indicatorValueForXBRL.Context.ToString()],
                Value = indicatorValueForXBRL.Value,
                Name = new QualifiedName(concept.Name, XBRLNamespace.ESRS.LocalName, XBRLNamespace.ESRS.Namespace)
            };

            // TODO verify if the unit is mandatory
            if(indicatorValueForXBRL.Unit != null && Units.ContainsKey(indicatorValueForXBRL.Unit.ToString()))
            {
                fact.UnitRef = Units[indicatorValueForXBRL.Unit.ToString()];
            }

            if (indicatorValueForXBRL.Decimals.HasValue)
            {
                fact.Decimals = indicatorValueForXBRL.Decimals.Value;
            }

            fact.Id = $"f_{XBRLInstance.Facts.Count}";
            XBRLInstance.Facts.Add(fact);
        }
    }

    public void AddUnit(UnitForXBRL unitForXBRL)
    {
        if(!Units.ContainsKey(unitForXBRL.ToString()))
        {
            
            UnitType unitType = unitForXBRL.Numerator != null && unitForXBRL.Denominator != null ? UnitType.Divide : UnitType.Measure;
            Unit unit = new (unitType);

            if(unitType == UnitType.Divide) {
                unit.UnitDenominatorQualifiedNames.Add(new QualifiedName(unitForXBRL.Denominator.NormalizedName, unitForXBRL.Denominator.XBRLNamespace.GetLastPathSegment(), unitForXBRL.Denominator.XBRLNamespace));
                unit.UnitNumeratorQualifiedNames.Add(new QualifiedName(unitForXBRL.Numerator.NormalizedName, unitForXBRL.Numerator.XBRLNamespace.GetLastPathSegment(), unitForXBRL.Numerator.XBRLNamespace));
            } else {
                unit.MeasureQualifiedNames.Add(new QualifiedName(unitForXBRL.Numerator.NormalizedName, unitForXBRL.Numerator.XBRLNamespace.GetLastPathSegment(), unitForXBRL.Numerator.XBRLNamespace));
            }

            unit.Id = $"u_{Units.Count}";
            Units.Add(unitForXBRL.ToString(), unit);
            XBRLInstance.Units.Add(unit);
        }
    }

    public void BuildXBRL(string filePathWithExtension)
    {
        Build(filePathWithExtension, SaveFormat.XBRL);
    }

    public void BuildIXBRL(string filePathWithExtension)
    {
        Build(filePathWithExtension, SaveFormat.IXBRL);
    }

    public void Validate()
    {
        XBRLInstance.Validate();
        ValidationsErrors.AddRange(XBRLInstance.ValidationErrors.Select(GenerateClassicError));

    }

    private (XbrlInstance, SchemaRef) SetupDocument()
    {
        XbrlInstanceCollection xbrlInstances = Document.XbrlInstances;
        XbrlInstance instance = xbrlInstances[xbrlInstances.Add()];

        SchemaRefCollection schemaRefs = instance.SchemaRefs;
        schemaRefs.Add(XBRLNamespace.ESRS_XSD.Namespace, XBRLNamespace.ESRS_XSD.LocalName, XBRLNamespace.ESRS.Namespace);

        return (instance, schemaRefs[0]);
    }

    private Concept GetConceptByXbrlCode(string xbrlCode)
    {
        Concept fixedAssetsConcept = Schema.GetConceptByName(xbrlCode);
         
        return fixedAssetsConcept;
    }

    private void Build(string filePathWithExtension, SaveFormat format)
    {
        Directory.CreateDirectory(Path.GetDirectoryName(filePathWithExtension));

        if(!File.Exists(filePathWithExtension))
        {
            File.Create(filePathWithExtension).Close();
        }

        Document.Save(filePathWithExtension, new SaveOptions() { SaveFormat = format, SaveLinkbasesToDesticationFolder = false, SaveSchemasToDesticationFolder = false });
    }
}

So every time i add an ArrayContext (aka dimension), it seems that the code use a random generated prefix namespace.

Also, i observed that the shemaRef i add generate an entry into the xmlns as xmlns:esrs=“https://xbrl.efrag.org/taxonomy/esrs/2023-12-22/entry” xmlns:xbrldi=“http://xbrl.org/2006/xbrldi”>
which is wrong but looking into the https://xbrl.efrag.org/taxonomy/esrs/2023-12-22/esrs_all.xsd file we see that the esrs namespace is linked into targetNamespace from the xsd file…

@Deboveq,

Thanks for the code snippet and details.

We require thorough evaluation and investigation of your requirements/issue regarding namespaces and explicitMember namespace prefix. We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes (either proposed code snippet or fix) according to the terms mentioned in Free Support Policies.

Issue ID(s): FINANCENET-390

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

1 Like