def nodes_correspond(xc, p, args): if len(args) != 2: raise XPathContext.FunctionNumArgs() node1 = nodeArg(xc, args, 0, "node()?", missingArgFallback=(), emptyFallback=()) node2 = nodeArg(xc, args, 1, "node()?", missingArgFallback=(), emptyFallback=()) if node1 == (): if node2 == (): return True return False if node2 == (): return False return XbrlUtil.nodesCorrespond(xc.modelXbrl, node1, node2, xc.modelXbrl)
def isEqualTo(self, other, equalMode=XbrlUtil.XPATH_EQ): if isinstance(other, ModelValue.QName): return self.isExplicit and self.memberQname == other elif other is None: return False elif self.isExplicit: return self.memberQname == other.memberQname else: return XbrlUtil.nodesCorrespond(self.modelXbrl, self.typedMember, other.typedMember, equalMode=equalMode, excludeIDs=XbrlUtil.NO_IDs_EXCLUDED)
def isEqualTo(self, other, equalMode=XbrlUtil.XPATH_EQ): """(bool) -- True if explicit member QNames equal or typed member nodes correspond, given equalMode (s-equal, s-equal2, or xpath-equal for formula) :param equalMode: XbrlUtil.S_EQUAL (ordinary S-equality from 2.1 spec), XbrlUtil.S_EQUAL2 (XDT definition of equality, adding QName comparisions), or XbrlUtil.XPATH_EQ (XPath EQ on all types) """ if other is None: return False if self.isExplicit: # other is either ModelDimensionValue or the QName value of explicit dimension return self.memberQname == (other.memberQname if isinstance(other, (ModelDimensionValue,DimValuePrototype)) else other) else: # typed dimension compared to another ModelDimensionValue or other is the value nodes return XbrlUtil.nodesCorrespond(self.modelXbrl, self.typedMember, other.typedMember if isinstance(other, (ModelDimensionValue,DimValuePrototype)) else other, equalMode=equalMode, excludeIDs=XbrlUtil.NO_IDs_EXCLUDED)
def isEqualTo(self, other, equalMode=XbrlUtil.XPATH_EQ): if isinstance(other, ModelValue.QName): return self.isExplicit and self.memberQname == other elif other is None: return False elif self.isExplicit: return self.memberQname == other.memberQname else: return XbrlUtil.nodesCorrespond( self.modelXbrl, self.typedMember, other.typedMember, equalMode=equalMode, excludeIDs=XbrlUtil.NO_IDs_EXCLUDED)
def deep_equal(xc, p, contextItem, args): if len(args) != 2: raise XPathContext.FunctionNumArgs() return XbrlUtil.nodesCorrespond(xc.modelXbrl, args[0], args[1])
def aspectMatches(fact1, fact2, aspects): matches = True for aspect in (aspects if hasattr(aspects, '__iter__') else (aspects, )): if aspect == Aspect.LOCATION: if (fact1.modelXbrl == fact2.modelXbrl and # test deemed true for multi-instance comparisons fact1.element.parentNode != fact2.element.parentNode): matches = False elif aspect == Aspect.CONCEPT: if fact1.concept.qname != fact2.concept.qname: matches = False elif fact1.isTuple or fact2.isTuple: return True # only match the aspects both facts have elif aspect == Aspect.PERIOD: if not fact1.context.isPeriodEqualTo(fact2.context): matches = False elif aspect == Aspect.ENTITY_IDENTIFIER: if not fact1.context.isEntityIdentifierEqualTo(fact2.context): matches = False elif aspect == Aspect.COMPLETE_SEGMENT: if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.segment, fact2.context.segment, dts2=fact2.modelXbrl): matches = False elif aspect == Aspect.COMPLETE_SCENARIO: if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.scenario, fact2.context.scenario, dts2=fact2.modelXbrl): matches = False elif aspect in (Aspect.NON_XDT_SEGMENT, Aspect.NON_XDT_SCENARIO): nXs1 = fact1.context.nonDimValues(aspect) nXs2 = fact2.context.nonDimValues(aspect) if len(nXs1) != len(nXs2): matches = False else: for i in range(len(nXs1)): if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, nXs1[i], nXs2[i], dts2=fact2.modelXbrl): matches = False break elif aspect == Aspect.UNIT: u1 = fact1.unit u2 = fact2.unit if (u1 is None) != (u2 is None): matches = False elif u1 and u2 and u1.measures != u2.measures: matches = False elif aspect == Aspect.DIMENSIONS: ''' (no implicit filtering on ALL dimensions for now) dimQnames1 = fact1.context.dimAspects dimQnames2 = fact2.context.dimAspects if len(dimQnames1 ^ dimQnames2): # dims not in both matches = False else: for dimQname1 in dimQnames1: if dimQname1 not in dimQnames2 or \ not aspectMatches(fact1, fact2, dimQname1): matches = False break ''' elif isinstance(aspect, QName): from arelle.ModelObject import ModelDimensionValue dimValue1 = fact1.context.dimValue(aspect) dimValue2 = fact2.context.dimValue(aspect) if isinstance(dimValue1, ModelDimensionValue): if dimValue1.isExplicit: if isinstance(dimValue2, QName): if dimValue1.memberQname != dimValue2: matches = False elif isinstance(dimValue2, ModelDimensionValue): if dimValue2.isTyped: matches = False elif dimValue1.memberQname != dimValue2.memberQname: matches = False elif dimValue1.isTyped: if isinstance(dimValue2, QName): matches = False elif isinstance(dimValue2, ModelDimensionValue): if dimValue2.isExplicit: matches = False elif not XbrlUtil.nodesCorrespond( fact1.modelXbrl, dimValue1.typedMember, dimValue2.typedMember, dts2=fact2.modelXbrl): matches = False elif isinstance(dimValue1, QName): if isinstance(dimValue2, QName): if dimValue1 != dimValue2: matches = False elif isinstance(dimValue2, ModelDimensionValue): if dimValue2.isTyped: matches = False elif dimValue1 != dimValue2.memberQname: matches = False elif dimValue1 is None: if dimValue2: matches = False if not matches: break return matches
def aspectMatches(fact1, fact2, aspects): matches = True for aspect in (aspects if hasattr(aspects,'__iter__') else (aspects,)): if aspect == Aspect.LOCATION: if (fact1.modelXbrl == fact2.modelXbrl and # test deemed true for multi-instance comparisons fact1.element.parentNode != fact2.element.parentNode): matches = False elif aspect == Aspect.CONCEPT: if fact1.concept.qname != fact2.concept.qname: matches = False elif fact1.isTuple or fact2.isTuple: return True # only match the aspects both facts have elif aspect == Aspect.PERIOD: if not fact1.context.isPeriodEqualTo(fact2.context): matches = False elif aspect == Aspect.ENTITY_IDENTIFIER: if not fact1.context.isEntityIdentifierEqualTo(fact2.context): matches = False elif aspect == Aspect.COMPLETE_SEGMENT: if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.segment, fact2.context.segment, dts2=fact2.modelXbrl): matches = False elif aspect == Aspect.COMPLETE_SCENARIO: if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.scenario, fact2.context.scenario, dts2=fact2.modelXbrl): matches = False elif aspect in (Aspect.NON_XDT_SEGMENT, Aspect.NON_XDT_SCENARIO): nXs1 = fact1.context.nonDimValues(aspect) nXs2 = fact2.context.nonDimValues(aspect) if len(nXs1) != len(nXs2): matches = False else: for i in range(len(nXs1)): if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, nXs1[i], nXs2[i], dts2=fact2.modelXbrl): matches = False break elif aspect == Aspect.UNIT: u1 = fact1.unit u2 = fact2.unit if (u1 is None) != (u2 is None): matches = False elif u1 and u2 and u1.measures != u2.measures: matches = False elif aspect == Aspect.DIMENSIONS: ''' (no implicit filtering on ALL dimensions for now) dimQnames1 = fact1.context.dimAspects dimQnames2 = fact2.context.dimAspects if len(dimQnames1 ^ dimQnames2): # dims not in both matches = False else: for dimQname1 in dimQnames1: if dimQname1 not in dimQnames2 or \ not aspectMatches(fact1, fact2, dimQname1): matches = False break ''' elif isinstance(aspect, QName): from arelle.ModelObject import ModelDimensionValue dimValue1 = fact1.context.dimValue(aspect) dimValue2 = fact2.context.dimValue(aspect) if isinstance(dimValue1, ModelDimensionValue): if dimValue1.isExplicit: if isinstance(dimValue2, QName): if dimValue1.memberQname != dimValue2: matches = False elif isinstance(dimValue2, ModelDimensionValue): if dimValue2.isTyped: matches = False elif dimValue1.memberQname != dimValue2.memberQname: matches = False elif dimValue1.isTyped: if isinstance(dimValue2, QName): matches = False elif isinstance(dimValue2, ModelDimensionValue): if dimValue2.isExplicit: matches = False elif not XbrlUtil.nodesCorrespond(fact1.modelXbrl, dimValue1.typedMember, dimValue2.typedMember, dts2=fact2.modelXbrl): matches = False elif isinstance(dimValue1,QName): if isinstance(dimValue2, QName): if dimValue1 != dimValue2: matches = False elif isinstance(dimValue2, ModelDimensionValue): if dimValue2.isTyped: matches = False elif dimValue1 != dimValue2.memberQname: matches = False elif dimValue1 is None: if dimValue2: matches = False if not matches: break return matches
def aspectMatches(xpCtx, fact1, fact2, aspects): if fact1 is None or fact2 is None: # fallback (atomic) never matches any aspect return False matches = True for aspect in (aspects if hasattr(aspects,'__iter__') else (aspects,)): if aspect == Aspect.LOCATION: if (fact1.modelXbrl == fact2.modelXbrl and # test deemed true for multi-instance comparisons fact1.getparent() != fact2.getparent()): matches = False elif aspect == Aspect.CONCEPT: if fact1.concept.qname != fact2.concept.qname: matches = False elif fact1.isTuple or fact2.isTuple: return True # only match the aspects both facts have elif aspect == Aspect.PERIOD: if not fact1.context.isPeriodEqualTo(fact2.context): matches = False elif aspect == Aspect.ENTITY_IDENTIFIER: if not fact1.context.isEntityIdentifierEqualTo(fact2.context): matches = False elif aspect == Aspect.COMPLETE_SEGMENT: if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.segment, fact2.context.segment, dts2=fact2.modelXbrl): matches = False elif aspect == Aspect.COMPLETE_SCENARIO: if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.scenario, fact2.context.scenario, dts2=fact2.modelXbrl): matches = False elif aspect in (Aspect.NON_XDT_SEGMENT, Aspect.NON_XDT_SCENARIO): nXs1 = fact1.context.nonDimValues(aspect) nXs2 = fact2.context.nonDimValues(aspect) if len(nXs1) != len(nXs2): matches = False else: for i in range(len(nXs1)): if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, nXs1[i], nXs2[i], dts2=fact2.modelXbrl): matches = False break elif aspect == Aspect.UNIT: u1 = fact1.unit u2 = fact2.unit if (u1 is None) != (u2 is None): matches = False elif u1 is not None and u2 is not None and u1.measures != u2.measures: matches = False elif aspect == Aspect.DIMENSIONS: ''' (no implicit filtering on ALL dimensions for now) dimQnames1 = fact1.context.dimAspects dimQnames2 = fact2.context.dimAspects if len(dimQnames1 ^ dimQnames2): # dims not in both matches = False else: for dimQname1 in dimQnames1: if dimQname1 not in dimQnames2 or \ not aspectMatches(fact1, fact2, dimQname1): matches = False break ''' elif isinstance(aspect, QName): from arelle.ModelInstanceObject import ModelDimensionValue dimValue1 = fact1.context.dimValue(aspect) dimValue2 = fact2.context.dimValue(aspect) if isinstance(dimValue1, ModelDimensionValue): if dimValue1.isExplicit: if isinstance(dimValue2, QName): if dimValue1.memberQname != dimValue2: matches = False elif isinstance(dimValue2, ModelDimensionValue): if dimValue2.isTyped: matches = False elif dimValue1.memberQname != dimValue2.memberQname: matches = False elif dimValue2 is None: matches = False elif dimValue1.isTyped: if isinstance(dimValue2, QName): matches = False elif isinstance(dimValue2, ModelDimensionValue): if dimValue2.isExplicit: matches = False elif dimValue1.dimension.typedDomainElement in xpCtx.modelXbrl.modelFormulaEqualityDefinitions: equalityDefinition = xpCtx.modelXbrl.modelFormulaEqualityDefinitions[dimValue1.dimension.typedDomainElement] matches = equalityDefinition.evalTest(xpCtx, fact1, fact2) elif not XbrlUtil.nodesCorrespond(fact1.modelXbrl, dimValue1.typedMember, dimValue2.typedMember, dts2=fact2.modelXbrl): matches = False elif dimValue2 is None: matches = False elif isinstance(dimValue1,QName): # first dim is default value of an explicit dim if isinstance(dimValue2, QName): # second dim is default value of an explicit dim # multi-instance does not consider member's qname here where it is a default # only check if qnames match if the facts are from same instance if fact1.modelXbrl == fact2.modelXbrl and dimValue1 != dimValue2: matches = False elif isinstance(dimValue2, ModelDimensionValue): if dimValue2.isTyped: matches = False elif dimValue1 != dimValue2.memberQname: matches = False elif dimValue2 is None: # no dim aspect for fact 2 if fact1.modelXbrl == fact2.modelXbrl: # only allowed for multi-instance matches = False elif dimValue1 is None: # absent dim member from fact1 allowed if fact2 is default in different instance if isinstance(dimValue2,QName): if fact1.modelXbrl == fact2.modelXbrl: matches = False elif dimValue2 is not None: matches = False # else if both are None, matches True for single and multiple instance if not matches: break return matches