def addChild(parent, childName1, childName2=None, attributes=None, text=None, afterSibling=None, beforeSibling=None): from arelle.FunctionXs import xsString modelDocument = parent.modelDocument if isinstance(childName1, QName): addQnameValue(modelDocument, childName1) child = modelDocument.parser.makeelement(childName1.clarkNotation) else: # called with namespaceURI, localName existingPrefix = xmlnsprefix(parent, childName1) prefix, sep, localName = childName2.partition(":") if localName: if existingPrefix is None: setXmlns(modelDocument, prefix, childName1) else: localName = prefix child = modelDocument.parser.makeelement("{{{0}}}{1}".format(childName1, localName)) child.init(modelDocument) if afterSibling is not None and afterSibling.getparent() == parent: # sibling is a hint, parent prevails afterSibling.addnext(child) elif beforeSibling is not None and beforeSibling.getparent() == parent: # sibling is a hint, parent prevails beforeSibling.addprevious(child) else: parent.append(child) if attributes: for name, value in (attributes if len(attributes) > 0 and isinstance(attributes[0],tuple) else (attributes,)): if isinstance(name,QName): if name.namespaceURI: addQnameValue(modelDocument, name) child.set(name.clarkNotation, str(value)) else: child.set(name, xsString(None, None, value) ) if text: child.text = xsString(None, None, text) return child
def produceOutputFact(xpCtx, formula, result): priorErrorCount = len(xpCtx.modelXbrl.errors) isTuple = isinstance(formula,ModelTuple) # assemble context conceptQname = aspectValue(xpCtx, formula, Aspect.CONCEPT, "xbrlfe:missingConceptRule") if isinstance(conceptQname, VariableBindingError): xpCtx.modelXbrl.error(conceptQname.err, _("Formula %(xlinkLabel)s concept: %(concept)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, concept=conceptQname.msg) modelConcept = None else: modelConcept = xpCtx.modelXbrl.qnameConcepts[conceptQname] if modelConcept is None or (not modelConcept.isTuple if isTuple else not modelConcept.isItem): xpCtx.modelXbrl.error("xbrlfe:missingConceptRule", _("Formula %(xlinkLabel)s concept %(concept)s is not a %(element)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, concept=conceptQname, element=formula.localName) outputLocation = aspectValue(xpCtx, formula, Aspect.LOCATION_RULE, None) if not isTuple: # entity entityIdentScheme = aspectValue(xpCtx, formula, Aspect.SCHEME, "xbrlfe:missingEntityIdentifierRule") if isinstance(entityIdentScheme, VariableBindingError): xpCtx.modelXbrl.error(str(entityIdentScheme), _("Formula %(xlinkLabel)s entity identifier scheme: %(scheme)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, scheme=entityIdentScheme.msg) entityIdentValue = None else: entityIdentValue = aspectValue(xpCtx, formula, Aspect.VALUE, "xbrlfe:missingEntityIdentifierRule") if isinstance(entityIdentValue, VariableBindingError): xpCtx.modelXbrl.error(str(entityIdentScheme), _("Formula %(xlinkLabel)s entity identifier value: %(entityIdentifier)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, entityIdentifier=entityIdentValue.msg) # period periodType = aspectValue(xpCtx, formula, Aspect.PERIOD_TYPE, "xbrlfe:missingPeriodRule") periodStart = None periodEndInstant = None if isinstance(periodType, VariableBindingError): xpCtx.modelXbrl.error(str(periodType), _("Formula %(xlinkLabel)s period type: %(periodType)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, periodType=periodType.msg) elif periodType == "instant": periodEndInstant = aspectValue(xpCtx, formula, Aspect.INSTANT, "xbrlfe:missingPeriodRule") if isinstance(periodEndInstant, VariableBindingError): xpCtx.modelXbrl.error(str(periodEndInstant), _("Formula %(xlinkLabel)s period end: %(period)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, period=periodEndInstant.msg) elif periodType == "duration": periodStart = aspectValue(xpCtx, formula, Aspect.START, "xbrlfe:missingPeriodRule") if isinstance(periodStart, VariableBindingError): xpCtx.modelXbrl.error(str(periodStart), _("Formula %(xlinkLabel)s period start: %(period)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, period=periodStart.msg) periodEndInstant = aspectValue(xpCtx, formula, Aspect.END, "xbrlfe:missingPeriodRule") if isinstance(periodEndInstant, VariableBindingError): xpCtx.modelXbrl.error(str(periodEndInstant), _("Formula %(xlinkLabel)s period end: %(period)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, period=periodEndInstant.msg) # unit if modelConcept is not None and modelConcept.isNumeric: unitSource = aspectValue(xpCtx, formula, Aspect.UNIT_MEASURES, None) multDivBy = aspectValue(xpCtx, formula, Aspect.MULTIPLY_BY, "xbrlfe:missingUnitRule") if isinstance(multDivBy, VariableBindingError): xpCtx.modelXbrl.error(str(multDivBy) if isinstance(multDivBy, VariableBindingError) else "xbrlfe:missingUnitRule", _("Formula %(xlinkLabel)s unit: %(unit)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, unit=multDivBy.msg) multiplyBy = (); divideBy = () # prevent errors later if bad else: divMultBy = aspectValue(xpCtx, formula, Aspect.DIVIDE_BY, "xbrlfe:missingUnitRule") if isinstance(divMultBy, VariableBindingError): xpCtx.modelXbrl.error(str(multDivBy) if isinstance(divMultBy, VariableBindingError) else "xbrlfe:missingUnitRule", _("Formula %(xlinkLabel)s unit: %(unit)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, unit=divMultBy.msg) multiplyBy = (); divideBy = () # prevent errors later if bad else: multiplyBy = unitSource[0] + multDivBy[0] + divMultBy[1] divideBy = unitSource[1] + multDivBy[1] + divMultBy[0] # remove cancelling mult/div units lookForCommonUnits = True while lookForCommonUnits: lookForCommonUnits = False for commonUnit in multiplyBy: if commonUnit in divideBy: multiplyBy.remove(commonUnit) divideBy.remove(commonUnit) lookForCommonUnits = True break if len(multiplyBy) == 0: # if no units add pure multiplyBy.append(XbrlConst.qnXbrliPure) # dimensions segOCCs = [] scenOCCs = [] if formula.aspectModel == "dimensional": dimAspects = {} dimQnames = aspectValue(xpCtx, formula, Aspect.DIMENSIONS, None) if dimQnames: for dimQname in dimQnames: dimConcept = xpCtx.modelXbrl.qnameConcepts[dimQname] dimErr = "xbrlfe:missing{0}DimensionRule".format("typed" if dimConcept is not None and dimConcept.isTypedDimension else "explicit") dimValue = aspectValue(xpCtx, formula, dimQname, dimErr) if isinstance(dimValue, VariableBindingError): xpCtx.modelXbrl.error(dimErr, _("Formula %(xlinkLabel)s dimension %(dimension)s: %(value)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, dimension=dimQname, value=dimValue.msg) elif dimConcept.isTypedDimension: if isinstance(dimValue, list): # result of flatten, always a list if len(dimValue) != 1 or not isinstance(dimValue[0], ModelObject): xpCtx.modelXbrl.error("xbrlfe:wrongXpathResultForTypedDimensionRule", _("Formula %(xlinkLabel)s dimension %(dimension)s value is not a node: %(value)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, dimension=dimQname, value=dimValue) continue dimValue = dimValue[0] dimAspects[dimQname] = dimValue elif dimValue is not None and xpCtx.modelXbrl.qnameDimensionDefaults.get(dimQname) != dimValue: dimAspects[dimQname] = dimValue segOCCs = aspectValue(xpCtx, formula, Aspect.NON_XDT_SEGMENT, None) scenOCCs = aspectValue(xpCtx, formula, Aspect.NON_XDT_SCENARIO, None) for occElt in xpCtx.flattenSequence((segOCCs, scenOCCs)): if isinstance(occElt, ModelObject) and occElt.namespaceURI == XbrlConst.xbrldi: xpCtx.modelXbrl.error("xbrlfe:badSubsequentOCCValue", _("Formula %(xlinkLabel)s OCC element %(occ)s covers a dimensional aspect"), modelObject=(formula,occElt), xlinkLabel=formula.xlinkLabel, occ=occElt.elementQname) else: dimAspects = None # non-dimensional segOCCs = aspectValue(xpCtx, formula, Aspect.COMPLETE_SEGMENT, None) scenOCCs = aspectValue(xpCtx, formula, Aspect.COMPLETE_SCENARIO, None) if priorErrorCount < len(xpCtx.modelXbrl.errors): return None # had errors, don't produce output fact # does context exist in out instance document outputInstanceQname = formula.outputInstanceQname outputXbrlInstance = xpCtx.inScopeVars[outputInstanceQname] xbrlElt = outputXbrlInstance.modelDocument.xmlRootElement # in source instance document newFact = None if isTuple: newFact = outputXbrlInstance.createFact(conceptQname, parent=outputLocation, afterSibling=xpCtx.outputLastFact.get(outputInstanceQname)) else: # add context prevCntx = outputXbrlInstance.matchContext( entityIdentScheme, entityIdentValue, periodType, periodStart, periodEndInstant, dimAspects, segOCCs, scenOCCs) if prevCntx is not None: cntxId = prevCntx.id newCntxElt = prevCntx else: newCntxElt = outputXbrlInstance.createContext(entityIdentScheme, entityIdentValue, periodType, periodStart, periodEndInstant, conceptQname, dimAspects, segOCCs, scenOCCs, afterSibling=xpCtx.outputLastContext.get(outputInstanceQname), beforeSibling=xpCtx.outputFirstFact.get(outputInstanceQname)) cntxId = newCntxElt.id xpCtx.outputLastContext[outputInstanceQname] = newCntxElt # does unit exist # add unit if modelConcept.isNumeric: prevUnit = outputXbrlInstance.matchUnit(multiplyBy, divideBy) if prevUnit is not None: unitId = prevUnit.id newUnitElt = prevUnit else: newUnitElt = outputXbrlInstance.createUnit(multiplyBy, divideBy, afterSibling=xpCtx.outputLastUnit.get(outputInstanceQname), beforeSibling=xpCtx.outputFirstFact.get(outputInstanceQname)) unitId = newUnitElt.id xpCtx.outputLastUnit[outputInstanceQname] = newUnitElt # add fact attrs = [("contextRef", cntxId)] precision = None decimals = None if modelConcept.isNumeric: attrs.append(("unitRef", unitId)) value = formula.evaluate(xpCtx) valueSeqLen = len(value) if valueSeqLen > 1: xpCtx.modelXbrl.error("xbrlfe:nonSingletonOutputValue", _("Formula %(xlinkLabel)s value is a sequence of length %(valueSequenceLength)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, valueSequenceLength=valueSeqLen) else: if valueSeqLen == 0: #xsi:nil if no value attrs.append((XbrlConst.qnXsiNil, "true")) v = None else: # add precision/decimals for non-fraction numerics if modelConcept.isNumeric and not modelConcept.isFraction: if formula.hasDecimals: decimals = formula.evaluateRule(xpCtx, Aspect.DECIMALS) attrs.append(("decimals", decimals)) else: if formula.hasPrecision: precision = formula.evaluateRule(xpCtx, Aspect.PRECISION) else: precision = 0 attrs.append(("precision", precision)) x = value[0] if isinstance(x,float): from math import (log10, isnan, isinf, fabs) if (isnan(x) or (precision and (isinf(precision) or precision == 0)) or (decimals and isinf(decimals))): v = xsString(xpCtx, None, x) elif decimals is not None: v = "%.*f" % ( int(decimals), x) elif precision is not None and precision != 0: a = fabs(x) log = log10(a) if a != 0 else 0 v = "%.*f" % ( int(precision) - int(log) - (1 if a >= 1 else 0), x) else: # no implicit precision yet v = xsString(xpCtx, None, x) elif isinstance(x,QName): v = XmlUtil.addQnameValue(xbrlElt, x) elif isinstance(x,datetime.datetime): v = XmlUtil.dateunionValue(x) else: v = xsString(xpCtx, None, x) newFact = outputXbrlInstance.createFact(conceptQname, attributes=attrs, text=v, parent=outputLocation, afterSibling=xpCtx.outputLastFact.get(outputInstanceQname)) if newFact is not None: xpCtx.outputLastFact[outputInstanceQname] = newFact if outputInstanceQname not in xpCtx.outputFirstFact: xpCtx.outputFirstFact[outputInstanceQname] = newFact return newFact
def produceOutputFact(xpCtx, formula, result): priorErrorCount = len(xpCtx.modelXbrl.errors) # assemble context conceptQname = aspectValue(xpCtx, formula, Aspect.CONCEPT, "xbrlfe:missingConceptRule") if isinstance(conceptQname, VariableBindingError): xpCtx.modelXbrl.error(conceptQname.err, _("Formula %(xlinkLabel)s concept: %(concept)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, concept=conceptQname.msg) modelConcept = None else: modelConcept = xpCtx.modelXbrl.qnameConcepts[conceptQname] if modelConcept is None or not modelConcept.isItem: xpCtx.modelXbrl.error("xbrlfe:missingConceptRule", _("Formula %(xlinkLabel)s concept %(concept)s is not an item"), modelObject=formula, xlinkLabel=formula.xlinkLabel, concept=conceptQname) # entity entityIdentScheme = aspectValue(xpCtx, formula, Aspect.SCHEME, "xbrlfe:missingEntityIdentifierRule") if isinstance(entityIdentScheme, VariableBindingError): xpCtx.modelXbrl.error(str(entityIdentScheme), _("Formula %(xlinkLabel)s entity identifier scheme: %(scheme)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, scheme=entityIdentScheme.msg) entityIdentValue = None else: entityIdentValue = aspectValue(xpCtx, formula, Aspect.VALUE, "xbrlfe:missingEntityIdentifierRule") if isinstance(entityIdentValue, VariableBindingError): xpCtx.modelXbrl.error(str(entityIdentScheme), _("Formula %(xlinkLabel)s entity identifier value: %(entityIdentifier)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, entityIdentifier=entityIdentValue.msg) # period periodType = aspectValue(xpCtx, formula, Aspect.PERIOD_TYPE, "xbrlfe:missingPeriodRule") periodStart = None periodEndInstant = None if isinstance(periodType, VariableBindingError): xpCtx.modelXbrl.error(str(periodType), _("Formula %(xlinkLabel)s period type: %(periodType)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, periodType=periodType.msg) elif periodType == "instant": periodEndInstant = aspectValue(xpCtx, formula, Aspect.INSTANT, "xbrlfe:missingPeriodRule") if isinstance(periodEndInstant, VariableBindingError): xpCtx.modelXbrl.error(str(periodEndInstant), _("Formula %(xlinkLabel)s period end: %(period)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, period=periodEndInstant.msg) elif periodType == "duration": periodStart = aspectValue(xpCtx, formula, Aspect.START, "xbrlfe:missingPeriodRule") if isinstance(periodStart, VariableBindingError): xpCtx.modelXbrl.error(str(periodStart), _("Formula %(xlinkLabel)s period start: %(period)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, period=periodStart.msg) periodEndInstant = aspectValue(xpCtx, formula, Aspect.END, "xbrlfe:missingPeriodRule") if isinstance(periodEndInstant, VariableBindingError): xpCtx.modelXbrl.error(str(periodEndInstant), _("Formula %(xlinkLabel)s period end: %(period)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, period=periodEndInstant.msg) # unit if modelConcept is not None and modelConcept.isNumeric: unitSource = aspectValue(xpCtx, formula, Aspect.UNIT_MEASURES, None) multDivBy = aspectValue(xpCtx, formula, Aspect.MULTIPLY_BY, "xbrlfe:missingUnitRule") if isinstance(multDivBy, VariableBindingError): xpCtx.modelXbrl.error(str(multDivBy) if isinstance(multDivBy, VariableBindingError) else "xbrlfe:missingUnitRule", _("Formula %(xlinkLabel)s unit: %(unit)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, unit=multDivBy.msg) multiplyBy = (); divideBy = () # prevent errors later if bad else: divMultBy = aspectValue(xpCtx, formula, Aspect.DIVIDE_BY, "xbrlfe:missingUnitRule") if isinstance(divMultBy, VariableBindingError): xpCtx.modelXbrl.error(str(multDivBy) if isinstance(divMultBy, VariableBindingError) else "xbrlfe:missingUnitRule", _("Formula %(xlinkLabel)s unit: %(unit)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, unit=divMultBy.msg) multiplyBy = (); divideBy = () # prevent errors later if bad else: multiplyBy = unitSource[0] + multDivBy[0] + divMultBy[1] divideBy = unitSource[1] + multDivBy[1] + divMultBy[0] # remove cancelling mult/div units lookForCommonUnits = True while lookForCommonUnits: lookForCommonUnits = False for commonUnit in multiplyBy: if commonUnit in divideBy: multiplyBy.remove(commonUnit) divideBy.remove(commonUnit) lookForCommonUnits = True break if len(multiplyBy) == 0: # if no units add pure multiplyBy.append(XbrlConst.qnXbrliPure) # dimensions segOCCs = [] scenOCCs = [] if formula.aspectModel == "dimensional": dimAspects = {} dimQnames = aspectValue(xpCtx, formula, Aspect.DIMENSIONS, None) if dimQnames: for dimQname in dimQnames: dimConcept = xpCtx.modelXbrl.qnameConcepts[dimQname] dimErr = "xbrlfe:missing{0}DimensionRule".format("typed" if dimConcept is not None and dimConcept.isTypedDimension else "explicit") dimValue = aspectValue(xpCtx, formula, dimQname, dimErr) if isinstance(dimValue, VariableBindingError): xpCtx.modelXbrl.error(dimErr, _("Formula %(xlinkLabel)s dimension %(dimension)s: %(value)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, dimension=dimQname, value=dimValue.msg) elif dimValue is not None and xpCtx.modelXbrl.qnameDimensionDefaults.get(dimQname) != dimValue: dimAspects[dimQname] = dimValue segOCCs = aspectValue(xpCtx, formula, Aspect.NON_XDT_SEGMENT, None) scenOCCs = aspectValue(xpCtx, formula, Aspect.NON_XDT_SCENARIO, None) else: dimAspects = None # non-dimensional segOCCs = aspectValue(xpCtx, formula, Aspect.COMPLETE_SEGMENT, None) scenOCCs = aspectValue(xpCtx, formula, Aspect.COMPLETE_SCENARIO, None) if priorErrorCount < len(xpCtx.modelXbrl.errors): return None # had errors, don't produce output fact # does context exist in out instance document outputInstanceQname = formula.outputInstanceQname outputXbrlInstance = xpCtx.inScopeVars[outputInstanceQname] xbrlElt = outputXbrlInstance.modelDocument.xmlRootElement # in source instance document # add context prevCntx = outputXbrlInstance.matchContext( entityIdentScheme, entityIdentValue, periodType, periodStart, periodEndInstant, dimAspects, segOCCs, scenOCCs) if prevCntx is not None: cntxId = prevCntx.id newCntxElt = prevCntx else: cntxId = 'c-{0:02n}'.format( len(outputXbrlInstance.contexts) + 1) newCntxElt = XmlUtil.addChild(xbrlElt, XbrlConst.xbrli, "context", attributes=("id", cntxId), afterSibling=xpCtx.outputLastContext.get(outputInstanceQname)) xpCtx.outputLastContext[outputInstanceQname] = newCntxElt entityElt = XmlUtil.addChild(newCntxElt, XbrlConst.xbrli, "entity") XmlUtil.addChild(entityElt, XbrlConst.xbrli, "identifier", attributes=("scheme", entityIdentScheme), text=entityIdentValue) periodElt = XmlUtil.addChild(newCntxElt, XbrlConst.xbrli, "period") if periodType == "forever": XmlUtil.addChild(periodElt, XbrlConst.xbrli, "forever") elif periodType == "instant": XmlUtil.addChild(periodElt, XbrlConst.xbrli, "instant", text=XmlUtil.dateunionValue(periodEndInstant, subtractOneDay=True)) elif periodType == "duration": XmlUtil.addChild(periodElt, XbrlConst.xbrli, "startDate", text=XmlUtil.dateunionValue(periodStart)) XmlUtil.addChild(periodElt, XbrlConst.xbrli, "endDate", text=XmlUtil.dateunionValue(periodEndInstant, subtractOneDay=True)) segmentElt = None scenarioElt = None from arelle.ModelInstanceObject import ModelDimensionValue if dimAspects: for dimQname in sorted(dimAspects.keys()): dimValue = dimAspects[dimQname] if isinstance(dimValue, ModelDimensionValue): if dimValue.isExplicit: dimMemberQname = dimValue.memberQname contextEltName = dimValue.contextElement else: # qname for explicit or node for typed dimMemberQname = dimValue contextEltName = xpCtx.modelXbrl.qnameDimensionContextElement.get(dimQname) if contextEltName == "segment": if segmentElt is None: segmentElt = XmlUtil.addChild(entityElt, XbrlConst.xbrli, "segment") contextElt = segmentElt elif contextEltName == "scenario": if scenarioElt is None: scenarioElt = XmlUtil.addChild(newCntxElt, XbrlConst.xbrli, "scenario") contextElt = scenarioElt else: continue dimConcept = xpCtx.modelXbrl.qnameConcepts[dimQname] dimAttr = ("dimension", XmlUtil.addQnameValue(xbrlElt, dimConcept.qname)) if dimConcept.isTypedDimension: dimElt = XmlUtil.addChild(contextElt, XbrlConst.xbrldi, "xbrldi:typedMember", attributes=dimAttr) if isinstance(dimValue, ModelDimensionValue) and dimValue.isTyped: XmlUtil.copyChildren(dimElt, dimValue) elif dimMemberQname: dimElt = XmlUtil.addChild(contextElt, XbrlConst.xbrldi, "xbrldi:explicitMember", attributes=dimAttr, text=XmlUtil.addQnameValue(xbrlElt, dimMemberQname)) if segOCCs: if segmentElt is None: segmentElt = XmlUtil.addChild(entityElt, XbrlConst.xbrli, "segment") XmlUtil.copyNodes(segmentElt, segOCCs) if scenOCCs: if scenarioElt is None: scenarioElt = XmlUtil.addChild(newCntxElt, XbrlConst.xbrli, "scenario") XmlUtil.copyNodes(scenarioElt, scenOCCs) outputXbrlInstance.modelDocument.contextDiscover(newCntxElt) XmlValidate.validate(outputXbrlInstance, newCntxElt) # does unit exist # add unit if modelConcept.isNumeric: prevUnit = outputXbrlInstance.matchUnit(multiplyBy, divideBy) if prevUnit is not None: unitId = prevUnit.id newUnitElt = prevUnit else: unitId = 'u-{0:02n}'.format( len(outputXbrlInstance.units) + 1) newUnitElt = XmlUtil.addChild(xbrlElt, XbrlConst.xbrli, "unit", attributes=("id", unitId), afterSibling=xpCtx.outputLastUnit.get(outputInstanceQname)) xpCtx.outputLastUnit[outputInstanceQname] = newUnitElt if len(divideBy) == 0: for multiply in multiplyBy: XmlUtil.addChild(newUnitElt, XbrlConst.xbrli, "measure", text=XmlUtil.addQnameValue(xbrlElt, multiply)) else: divElt = XmlUtil.addChild(newUnitElt, XbrlConst.xbrli, "divide") numElt = XmlUtil.addChild(divElt, XbrlConst.xbrli, "unitNumerator") denElt = XmlUtil.addChild(divElt, XbrlConst.xbrli, "unitDenominator") for multiply in multiplyBy: XmlUtil.addChild(numElt, XbrlConst.xbrli, "measure", text=XmlUtil.addQnameValue(xbrlElt, multiply)) for divide in divideBy: XmlUtil.addChild(denElt, XbrlConst.xbrli, "measure", text=XmlUtil.addQnameValue(xbrlElt, divide)) outputXbrlInstance.modelDocument.unitDiscover(newUnitElt) XmlValidate.validate(outputXbrlInstance, newUnitElt) # add fact attrs = [("contextRef", cntxId)] precision = None decimals = None if modelConcept.isNumeric: attrs.append(("unitRef", unitId)) value = formula.evaluate(xpCtx) valueSeqLen = len(value) if valueSeqLen > 1: xpCtx.modelXbrl.error("xbrlfe:nonSingletonOutputValue", _("Formula %(xlinkLabel)s value is a sequence of length %(valueSequenceLength)s"), modelObject=formula, xlinkLabel=formula.xlinkLabel, valueSequenceLength=valueSeqLen) else: if valueSeqLen == 0: #xsi:nil if no value attrs.append((XbrlConst.qnXsiNil, "true")) v = None else: # add precision/decimals for non-fraction numerics if modelConcept.isNumeric and not modelConcept.isFraction: if formula.hasDecimals: decimals = formula.evaluateRule(xpCtx, Aspect.DECIMALS) attrs.append(("decimals", decimals)) else: if formula.hasPrecision: precision = formula.evaluateRule(xpCtx, Aspect.PRECISION) else: precision = 0 attrs.append(("precision", precision)) x = value[0] if isinstance(x,float): from math import (log10, isnan, isinf, fabs) if (isnan(x) or (precision and (isinf(precision) or precision == 0)) or (decimals and isinf(decimals))): v = xsString(xpCtx, x) elif decimals is not None: v = "%.*f" % ( int(decimals), x) elif precision is not None and precision != 0: a = fabs(x) log = log10(a) if a != 0 else 0 v = "%.*f" % ( int(precision) - int(log) - (1 if a >= 1 else 0), x) else: # no implicit precision yet v = xsString(xpCtx, x) elif isinstance(x,QName): v = XmlUtil.addQnameValue(xbrlElt, x) elif isinstance(x,datetime.datetime): v = XmlUtil.dateunionValue(x) else: v = xsString(xpCtx, x) newFact = XmlUtil.addChild(xbrlElt, conceptQname, attributes=attrs, text=v, afterSibling=xpCtx.outputLastFact.get(outputInstanceQname)) xpCtx.outputLastFact[outputInstanceQname] = newFact outputXbrlInstance.modelDocument.factDiscover(newFact, outputXbrlInstance.facts) XmlValidate.validate(outputXbrlInstance, newFact) return newFact