def instance(xc, p, args, i=0): if len(args[i]) != 1: raise XPathContext.FunctionArgType(i + 1, "xbrl:xbrl") modelXbrl = xc.modelInstance(anytypeArg(xc, args, i, "xbrli:xbrl")) if modelXbrl: return modelXbrl raise XPathContext.FunctionArgType(i + 1, "xbrl:xbrl")
def fact_explicit_dimension_value_value(xc, p, args): context = item_context(xc, args) if context: qn = qnameArg(xc, p, args, 1, 'QName', emptyFallback=()) if qn == (): raise XPathContext.FunctionArgType(2, "xbrl:QName") dimConcept = xc.modelXbrl.qnameConcepts.get( qn) # check qname is explicit dimension if not dimConcept or not dimConcept.isExplicitDimension: raise XPathContext.XPathException( p, 'xfie:invalidExplicitDimensionQName', _('dimension does not specify an explicit dimension')) dimValue = context.dimValue(qn) if isinstance(dimValue, ModelObject.ModelDimensionValue) and dimValue.isExplicit: return dimValue.memberQname # known to be valid given instance is valid elif isinstance(dimValue, QName): #default, check if this is valid ''' removed 2011-03-01 FWG clarification that default always applies modelItem = xc.modelItem(args[0][0]) itemConcept = modelItem.concept from arelle.ValidateXbrlDimensions import checkPriItemDimValueValidity memConcept = xc.modelXbrl.qnameConcepts.get(dimValue) # remove check for pri item validity per FWG meeting notes 2011-01-13 if itemConcept: # and checkPriItemDimValueValidity(xc, itemConcept, dimConcept, memConcept): return dimValue ''' return dimValue return () # not an applicable primary item for default dimension raise XPathContext.FunctionArgType(1, "xbrl:item")
def is_period_type(args, periodElement): if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1, "xbrl:period") period = args[0][0] if isinstance(period,xml.dom.Node) and period.nodeType == 1 and \ period.localName == "period" and period.namespaceURI == XbrlConst.xbrli: return XmlUtil.hasChild(period, XbrlConst.xbrli, periodElement) raise XPathContext.FunctionArgType(1, "xbrl:period")
def measure_name(xc, p, args): if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1, "xbrl:measure") unit = args[0][0] if isinstance(unit,xml.dom.Node) and unit.nodeType == 1 and \ unit.localName == "measure" and unit.namespaceURI == XbrlConst.xbrli: return qname(unit, XmlUtil.text(unit)) raise XPathContext.FunctionArgType(1, "xbrl:unit")
def item(xc, args, i=0): if len(args[i]) != 1: raise XPathContext.FunctionArgType(i + 1, "xbrl:item") if len(args[0]) != 1: raise XPathContext.FunctionArgType(1, "xbrl:item") modelItem = xc.modelItem(args[i][0]) if modelItem: return modelItem raise XPathContext.FunctionArgType(i + 1, "xbrl:item")
def unit(xc, p, args): if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1, "xbrl:item") modelItem = xc.modelItem(args[0][0]) if modelItem: modelConcept = modelItem.concept if modelConcept.isNumeric and not modelConcept.isFraction: return modelItem.unit return [] raise XPathContext.FunctionArgType(1, "xbrl:item")
def unit_denominator(xc, p, args): if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1, "xbrl:unit") unit = args[0][0] if isinstance(unit, ModelObject.ModelObject): unit = unit.element if isinstance(unit,xml.dom.Node) and unit.nodeType == 1 and \ unit.localName == "unit" and unit.namespaceURI == XbrlConst.xbrli: measuresParent = XmlUtil.descendant(unit, XbrlConst.xbrli, "unitDenominator") if measuresParent is None: return [] return XmlUtil.descendants(measuresParent, XbrlConst.xbrli, "measure") raise XPathContext.FunctionArgType(1, "xbrl:unit")
def fact_typed_dimension_value(xc, p, args): if len(args) != 2: raise XPathContext.FunctionNumArgs() context = item_context(xc, args) if context: qn = qnameArg(xc, p, args, 1, 'QName', emptyFallback=()) if qn == (): raise XPathContext.FunctionArgType(2, "xbrl:QName") modelConcept = xc.modelXbrl.qnameConcepts.get( qn) # check qname is explicit dimension if not modelConcept or not modelConcept.isTypedDimension: raise XPathContext.XPathException( p, 'xfie:invalidTypedDimensionQName', _('dimension does not specify a typed dimension')) result = context.dimValue(qn) return result.typedMember if result else () raise XPathContext.FunctionArgType(1, "xbrl:item")
def seconds_from_duration(xc, p, contextItem, args): if len(args) != 1: raise XPathContext.FunctionNumArgs() d = anytypeArg(xc, args, 0, 'duration', missingArgFallback=()) if d == (): return d if isinstance(d, DayTimeDuration): return 0 if isinstance(d, YearMonthDuration): return d.dayHrsMinsSecs[2] raise XPathContext.FunctionArgType(1,"xs:duration")
def fn_sum(xc, p, contextItem, args): if len(args) != 1: raise XPathContext.FunctionNumArgs() addends = xc.atomize(p, args[0]) try: if len(addends) == 0: return 0 # xpath allows empty sequence argument hasFloat = False hasDecimal = False for a in addends: if math.isnan(a): return NaN if isinstance(a, float): hasFloat = True elif isinstance(a, Decimal): hasDecimal = True if hasFloat and hasDecimal: # promote decimals to float addends = [ float(a) if isinstance(a, Decimal) else a for a in addends ] return sum(addends) except TypeError: raise XPathContext.FunctionArgType(1, "summable sequence", addends, errCode='err:FORG0001')
def dateyearmonthcjk(arg): m = yearmonthcjkPattern.match(jpDigitsToNormal(arg)) if m and m.lastindex == 2: _mo = z2(m.group(2)) if "01" <= _mo <= "12": return "{0}-{1}".format(yr(m.group(1)), _mo) raise XPathContext.FunctionArgType(1, "xs:date")
def datemonthdayShortEnTR1(arg): m = monthdayShortEnTR1Pattern.match(arg) if m and m.lastindex == 2: _mo = monthnumber[m.group(1)] _day = z2(m.group(2)) return "--{0:02}-{1}".format(_mo, _day) raise XPathContext.FunctionArgType(1, "xs:gMonthDay")
def datedaymonthyear(arg): m = daymonthyearPattern.match(arg) if m and m.lastindex == 3 and checkDate(yr(m.group(3)), m.group(2), m.group(1)): return "{0}-{1}-{2}".format(yr(m.group(3)), z2(m.group(2)), z2(m.group(1))) raise XPathContext.FunctionArgType(1, "xs:date")
def numcommadecimal(arg): if numCommaDecimalPattern.match(arg): return arg.replace('.', '').replace(',', '.').replace(' ', '').replace('\u00A0', '') raise XPathContext.FunctionArgType(1, "ixt:nonNegativeDecimalType")
def datemonthdaySlashTR1(arg): m = monthdayslashPattern.match(arg) if m and m.lastindex == 2: mo = z2(m.group(1)) day = z2(m.group(2)) return "--{0}-{1}".format(mo, day) raise XPathContext.FunctionArgType(1, "xs:gMonthDay")
def numunitdecimalin(arg): m = numUnitDecimalInPattern.match(arg) if m: m2 = [g for g in m.groups() if g is not None] return m2[0].replace(',', '').replace(' ', '').replace( '\xa0', '') + '.' + z2(m2[-2]) raise XPathContext.FunctionArgType(1, "ixt:numunitdecimalinType")
def xfxc_element(xc, p, contextItem, args): if not 2 <= len(args) <= 4: raise XPathContext.FunctionNumArgs() qn = qnameArg(xc, p, args, 0, 'QName', emptyFallback=None) attrArg = args[1] if isinstance(args[1], (list, tuple)) else (args[1], ) # attributes have to be pairs if attrArg: if len(attrArg) & 1 or any( not isinstance(attrArg[i], (QName, _STR_BASE)) for i in range(0, len(attrArg), 2)): raise XPathContext.FunctionArgType( 1, "((xs:qname|xs:string),xs:anyAtomicValue)", errCode="xfxce:AttributesNotNameValuePairs") else: attrParam = [ (attrArg[i], attrArg[i + 1] ) # need name-value pairs for XmlUtil function for i in range(0, len(attrArg), 2) ] else: attrParam = None value = atomicArg(xc, p, args, 2, "xs:anyAtomicType", emptyFallback='') if not value: # be sure '' is None so no text node is created value = None if len(args) < 4: childElements = None else: childElements = xc.flattenSequence(args[3]) # scratchpad instance document emulates fn:doc( ) to hold XML nodes scratchpadXmlDocUrl = "http://www.xbrl.org/2012/function/creation/xml_scratchpad.xml" if scratchpadXmlDocUrl in xc.modelXbrl.urlDocs: modelDocument = xc.modelXbrl.urlDocs[scratchpadXmlDocUrl] else: # create scratchpad xml document # this will get the fake instance document in the list of modelXbrl docs so that it is garbage collected from arelle import ModelDocument modelDocument = ModelDocument.create( xc.modelXbrl, ModelDocument.Type.UnknownXML, scratchpadXmlDocUrl, initialXml= "<xfc:dummy xmlns:xfc='http://www.xbrl.org/2012/function/creation'/>" ) newElement = XmlUtil.addChild(modelDocument.xmlRootElement, qn, attributes=attrParam, text=value) if childElements: for element in childElements: if isinstance(element, etree.ElementBase): newElement.append(element) # node myst be validated for use in instance creation (typed dimension references) XmlValidate.validate(xc.modelXbrl, newElement) return newElement
def dateerayearmonthjp(arg): m = erayearmonthjpPattern.match(jpDigitsToNormal(arg)) if m and m.lastindex == 3: _yr = eraYear(m.group(1), m.group(2)) _mo = z2(m.group(3)) if "01" <= _mo <= "12": return "{0}-{1}".format(_yr, _mo) raise XPathContext.FunctionArgType(1, "xs:gYearMonth")
def datemonthyearin(arg): m = monthyearInPattern.match(arg) try: return "{0}-{1}".format(yr(devanagariDigitsToNormal(m.group(2))), gregorianHindiMonthNumber[m.group(1)]) except (AttributeError, IndexError, KeyError): pass raise XPathContext.FunctionArgType(1, "xs:gYearMonth")
def period_datetime(p, args, periodElement, addOneDay): if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1, "xbrl:period") period = args[0][0] if (isinstance(period, xml.dom.Node) and period.nodeType == 1 and period.localName == "period" and period.namespaceURI == XbrlConst.xbrli): child = XmlUtil.child(period, XbrlConst.xbrli, periodElement) if child: return dateTime(child, addOneDay=addOneDay, type=DATETIME) elif periodElement == "instant": raise XPathContext.XPathException(p, 'xfie:PeriodIsNotInstant', _('Period is not instant')) else: raise XPathContext.XPathException(p, 'xfie:PeriodIsForever', _('Period is forever')) raise XPathContext.FunctionArgType(1, "xbrl:period")
def datemonthyear(arg): m = monthyearPattern.match( arg) # "(M)M*(Y)Y(YY)", with non-numeric separator, if m and m.lastindex == 2: _mo = z2(m.group(1)) if "01" <= _mo <= "12": return "{0}-{1:2}".format(yr(m.group(2)), _mo) raise XPathContext.FunctionArgType(1, "xs:gYearMonth")
def element_name(xc, p, args, elementParent=False): if len(args) != 1: raise XPathContext.FunctionNumArgs() modelRel = anytypeArg(xc, args, 0, "arelle:ModelRelationship", None) if not modelRel: raise XPathContext.FunctionArgType(1, "arelle:modelRelationship") element = modelRel.element if elementParent: element = element.parentNode return qname(element)
def datemonthdayen(arg): m = monthdayEnPattern.match(arg) if m and m.lastindex == 2: _mo = monthnumber[m.group(1)] _day = z2(m.group(2)) if "01" <= _day <= maxDayInMo.get(_mo, "00"): return "--{0:02}-{1}".format(_mo, _day) raise XPathContext.FunctionArgType(1, "xs:gMonthDay")
def datemonthday(arg): m = monthdayPattern.match(arg) if m and m.lastindex == 2: mo = z2(m.group(1)) day = z2(m.group(2)) if "01" <= day <= maxDayInMo.get(mo, "00"): return "--{0}-{1}".format(mo, day) raise XPathContext.FunctionArgType(1, "xs:gMonthDay")
def call(xc, p, localname, args): try: if localname not in ixtFunctions: raise ixtFunctionNotAvailable if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1,"xs:string") return ixtFunctions[localname](str(args[0][0])) except ixtFunctionNotAvailable: raise XPathContext.FunctionNotAvailable("xfi:{0}".format(localname))
def call(xc, p, qn, args): try: _ixtFunction = ixtNamespaceFunctions[qn.namespaceURI][qn.localName] except KeyError: raise XPathContext.FunctionNotAvailable(str(qn)) if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1, "xs:string") return _ixtFunction(str(args[0][0]))
def parent_child(args, parentName, descendantName): if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1, "xbrl:" + parentName) parent = args[0][0] if isinstance(parent, ModelObject.ModelObject): parent = parent.element if isinstance(parent,xml.dom.Node) and parent.nodeType == 1 and \ parent.localName == parentName and parent.namespaceURI == XbrlConst.xbrli: if descendantName.startswith('@'): return parent.getAttribute(descendantName[1:]) elif descendantName == 'text()': return XmlUtil.text(parent) elif descendantName == 'strip-text()': return XmlUtil.text(parent).strip() else: return XmlUtil.child(parent, XbrlConst.xbrli, descendantName) raise XPathContext.FunctionArgType(1, "xbrl:" + parentName)
def numunitdecimal(arg): # remove comma (normal), full-width comma, and stops (periods) m = numUnitDecimalPattern.match(jpDigitsToNormal(arg)) if m and m.lastindex > 1: return m.group(1).replace('.', '').replace(',', '').replace( '\uFF0C', '').replace('\uFF0E', '') + '.' + z2(m.group( m.lastindex)) raise XPathContext.FunctionArgType(1, "ixt:nonNegativeDecimalType")
def datemonthdayyearen(arg): m = monthdayyearEnPattern.match(arg) if m and m.lastindex == 3: _yr = yr(m.group(3)) _mo = monthnumber[m.group(1)] _day = z2(m.group(2)) if checkDate(_yr, _mo, _day): return "{0}-{1:02}-{2}".format(_yr, _mo, _day) raise XPathContext.FunctionArgType(1, "xs:date")
def dateyearmonthdaycjk(arg): m = yearmonthdaycjkPattern.match(jpDigitsToNormal(arg)) if m and m.lastindex == 3: _yr = yr(m.group(1)) _mo = z2(m.group(2)) _day = z2(m.group(3)) if checkDate(_yr, _mo, _day): return "{0}-{1}-{2}".format(_yr, _mo, _day) raise XPathContext.FunctionArgType(1, "xs:date")