Ejemplo n.º 1
0
def validate(modelXbrl, elt, recurse=True, attrQname=None, ixFacts=False):
    global ModelInlineValueObject, ixMsgCode
    if ModelInlineValueObject is None:
        from arelle.ModelInstanceObject import ModelInlineValueObject
        from arelle.XhtmlValidate import ixMsgCode
    isIxFact = isinstance(elt, ModelInlineValueObject)
    facets = None

    # attrQname can be provided for attributes that are global and LAX
    if (getattr(elt, "xValid", UNVALIDATED) == UNVALIDATED) and (not isIxFact
                                                                 or ixFacts):
        qnElt = elt.qname if ixFacts and isIxFact else elt.elementQname
        modelConcept = modelXbrl.qnameConcepts.get(qnElt)
        isAbstract = False
        if modelConcept is not None:
            isNillable = modelConcept.isNillable
            type = modelConcept.type
            if modelConcept.isAbstract:
                baseXsdType = "noContent"
                isAbstract = True
            elif modelConcept.isFraction:
                baseXsdType = "fraction"
            else:
                baseXsdType = modelConcept.baseXsdType
                facets = modelConcept.facets
        elif qnElt == XbrlConst.qnXbrldiExplicitMember:  # not in DTS
            baseXsdType = "QName"
            type = None
            isNillable = False
        elif qnElt == XbrlConst.qnXbrldiTypedMember:  # not in DTS
            baseXsdType = "noContent"
            type = None
            isNillable = False
        else:
            baseXsdType = None
            type = None
            isNillable = True  # allow nil if no schema definition
        isNil = elt.get("{http://www.w3.org/2001/XMLSchema-instance}nil") in (
            "true", "1")
        if attrQname is None:
            if isNil and not isNillable:
                if ModelInlineValueObject is not None and isinstance(
                        elt, ModelInlineValueObject):
                    errElt = "{0} fact {1}".format(elt.elementQname, elt.qname)
                else:
                    errElt = elt.elementQname
                modelXbrl.error(
                    "xmlSchema:nilNonNillableElement",
                    _("Element %(element)s fact %(fact)s type %(typeName)s is nil but element has not been defined nillable"
                      ),
                    modelObject=elt,
                    element=errElt,
                    fact=elt.qname,
                    typeName=modelConcept.baseXsdType
                    if modelConcept is not None else "unknown")
            try:
                if isAbstract:
                    raise ValueError("element is abstract")
                if isNil:
                    text = ""
                elif baseXsdType == "noContent":
                    text = elt.textValue  # no descendant text nodes
                else:
                    text = elt.stringValue  # include descendant text nodes
                    if modelConcept is not None:
                        if len(text) == 0:
                            if modelConcept.default is not None:
                                text = modelConcept.default
                            elif modelConcept.fixed is not None:
                                text = modelConcept.fixed
                        if baseXsdType == "token" and modelConcept.isEnumeration:
                            if modelConcept.instanceOfType(
                                    XbrlConst.qnEnumeration2ItemTypes):
                                baseXsdType = "enumerationHrefs"
                            else:
                                baseXsdType = "enumerationQNames"
            except Exception as err:
                if ModelInlineValueObject is not None and isinstance(
                        elt, ModelInlineValueObject):
                    errElt = "{0} fact {1}".format(elt.elementQname, elt.qname)
                else:
                    errElt = elt.elementQname
                if isIxFact and err.__class__.__name__ == "FunctionArgType":
                    modelXbrl.error(
                        ixMsgCode("transformValueError", elt),
                        _("Inline element %(element)s fact %(fact)s type %(typeName)s transform %(transform)s value error: %(value)s"
                          ),
                        modelObject=elt,
                        element=errElt,
                        fact=elt.qname,
                        transform=elt.format,
                        typeName=modelConcept.baseXsdType
                        if modelConcept is not None else "unknown",
                        value=XmlUtil.innerText(elt,
                                                ixExclude=True,
                                                ixContinuation=elt.namespaceURI
                                                == XbrlConst.ixbrl11))
                elif isIxFact and err.__class__.__name__ == "ixtFunctionNotAvailable":
                    modelXbrl.error(
                        ixMsgCode("invalidTransformation",
                                  elt,
                                  sect="validation"),
                        _("Fact %(fact)s has unrecognized transformation %(transform)s, value: %(value)s"
                          ),
                        modelObject=elt,
                        element=errElt,
                        fact=elt.qname,
                        transform=elt.format,
                        typeName=modelConcept.baseXsdType
                        if modelConcept is not None else "unknown",
                        value=XmlUtil.innerText(elt,
                                                ixExclude=True,
                                                ixContinuation=elt.namespaceURI
                                                == XbrlConst.ixbrl11))
                elif isAbstract:
                    modelXbrl.error(
                        "xmlSchema:abstractElement",
                        _("Element %(element)s has abstract declaration, value: %(value)s"
                          ),
                        modelObject=elt,
                        element=errElt,
                        error=str(err),
                        value=elt.text)
                else:
                    modelXbrl.error(
                        "xmlSchema:valueError",
                        _("Element %(element)s error %(error)s value: %(value)s"
                          ),
                        modelObject=elt,
                        element=errElt,
                        error=str(err),
                        value=elt.text)
                elt.sValue = elt.xValue = text = INVALIDixVALUE
                elt.xValid = INVALID
            if text is not INVALIDixVALUE:
                validateValue(modelXbrl, elt, None, baseXsdType, text,
                              isNillable, isNil, facets)
                # note that elt.sValue and elt.xValue are not innerText but only text elements on specific element (or attribute)
            if type is not None:
                definedAttributes = type.attributes
            else:
                definedAttributes = {}
            presentAttributes = set()
        # validate attributes
        # find missing attributes for default values
        for attrTag, attrValue in elt.items():
            qn = qnameClarkName(attrTag)
            #qn = qname(attrTag, noPrefixIsNoNamespace=True)
            baseXsdAttrType = None
            facets = None
            if attrQname is not None:  # validate all attributes and element
                if attrQname != qn:
                    continue
            elif type is not None:
                presentAttributes.add(qn)
                if qn in definedAttributes:  # look for concept-type-specific attribute definition
                    modelAttr = definedAttributes[qn]
                elif qn.namespaceURI:  # may be a globally defined attribute
                    modelAttr = modelXbrl.qnameAttributes.get(qn)
                else:
                    modelAttr = None
                if modelAttr is not None:
                    baseXsdAttrType = modelAttr.baseXsdType
                    facets = modelAttr.facets
            if baseXsdAttrType is None:  # look for global attribute definition
                attrObject = modelXbrl.qnameAttributes.get(qn)
                if attrObject is not None:
                    baseXsdAttrType = attrObject.baseXsdType
                    facets = attrObject.facets
                elif attrTag == "{http://xbrl.org/2006/xbrldi}dimension":  # some fallbacks?
                    baseXsdAttrType = "QName"
                elif attrTag == "id":
                    baseXsdAttrType = "ID"
                elif elt.namespaceURI == "http://www.w3.org/2001/XMLSchema":
                    if attrTag in {"type", "ref", "base", "refer", "itemType"}:
                        baseXsdAttrType = "QName"
                    elif attrTag in {"name"}:
                        baseXsdAttrType = "NCName"
                    elif attrTag in {"default", "fixed", "form"}:
                        baseXsdAttrType = "string"
                elif elt.namespaceURI == "http://xbrl.org/2006/xbrldi":
                    if attrTag == "dimension":
                        baseXsdAttrType = "QName"
                elif qn in predefinedAttributeTypes:
                    baseXsdAttrType, facets = predefinedAttributeTypes[qn]
            validateValue(modelXbrl,
                          elt,
                          attrTag,
                          baseXsdAttrType,
                          attrValue,
                          facets=facets)
        # if no attributes assigned above, there won't be an xAttributes, if so assign a shared dict to save memory
        try:
            elt.xAttributes
        except AttributeError:
            elt.xAttributes = xAttributesSharedEmptyDict

        if type is not None:
            if attrQname is None:
                missingAttributes = type.requiredAttributeQnames - presentAttributes - elt.slottedAttributesNames
                if missingAttributes:
                    modelXbrl.error(
                        "xmlSchema:attributesRequired",
                        _("Element %(element)s type %(typeName)s missing required attributes: %(attributes)s"
                          ),
                        modelObject=elt,
                        element=qnElt,
                        typeName=baseXsdType,
                        attributes=','.join(str(a) for a in missingAttributes))
                extraAttributes = presentAttributes - _DICT_SET(
                    definedAttributes.keys()) - XbrlConst.builtinAttributes
                if extraAttributes:
                    attributeWildcards = type.attributeWildcards
                    extraAttributes -= set(
                        a for a in extraAttributes
                        if validateAnyWildcard(qnElt, a, attributeWildcards))
                    if isIxFact:
                        extraAttributes -= XbrlConst.ixAttributes
                    if extraAttributes:
                        modelXbrl.error(
                            "xmlSchema:attributesExtraneous",
                            _("Element %(element)s type %(typeName)s extraneous attributes: %(attributes)s"
                              ),
                            modelObject=elt,
                            element=qnElt,
                            typeName=baseXsdType,
                            attributes=','.join(
                                str(a) for a in extraAttributes))
                # add default attribute values
                for attrQname in (type.defaultAttributeQnames -
                                  presentAttributes):
                    modelAttr = type.attributes[attrQname]
                    validateValue(modelXbrl,
                                  elt,
                                  attrQname.clarkNotation,
                                  modelAttr.baseXsdType,
                                  modelAttr.default,
                                  facets=modelAttr.facets)
            if recurse:
                global validateElementSequence, modelGroupCompositorTitle
                if validateElementSequence is None:
                    from arelle.XmlValidateParticles import validateElementSequence, modelGroupCompositorTitle
                try:
                    #childElts = list(elt) # uses __iter__ for inline facts
                    childElts = [e for e in elt if isinstance(e, ModelObject)]
                    if isNil:
                        if childElts or elt.text:
                            modelXbrl.error(
                                "xmlSchema:nilElementHasContent",
                                _("Element %(element)s is nil but has contents"
                                  ),
                                modelObject=elt,
                                element=qnElt)
                    else:
                        errResult = validateElementSequence(
                            modelXbrl, type, childElts, ixFacts)
                        if errResult is not None and errResult[2]:
                            iElt, occured, errDesc, errArgs = errResult
                            errElt = childElts[iElt] if iElt < len(
                                childElts) else elt
                            errArgs["modelObject"] = errElt
                            errArgs["element"] = errElt.qname
                            errArgs["parentElement"] = elt.qname
                            if "compositor" in errArgs:  # compositor is an object, provide friendly string
                                errArgs[
                                    "compositor"] = modelGroupCompositorTitle(
                                        errArgs["compositor"])
                            modelXbrl.error(*errDesc, **errArgs)

                            # when error is in an xbrli element, check any further unvalidated children
                            if qnElt.namespaceURI == XbrlConst.xbrli and iElt < len(
                                    childElts):
                                for childElt in childElts[iElt:]:
                                    if (getattr(childElt, "xValid",
                                                UNVALIDATED) == UNVALIDATED):
                                        validate(modelXbrl,
                                                 childElt,
                                                 ixFacts=ixFacts)
                    recurse = False  # cancel child element validation below, recursion was within validateElementSequence
                except AttributeError as ex:
                    raise ex
                    #pass  # HF Why is this here????
    if recurse:  # if there is no complex or simple type (such as xbrli:measure) then this code is used
        for child in (elt.modelTupleFacts if ixFacts and isIxFact else elt):
            if isinstance(child, ModelObject):
                validate(modelXbrl, child, recurse, attrQname, ixFacts)
Ejemplo n.º 2
0
def validate(modelXbrl, elt, recurse=True, attrQname=None, ixFacts=False):
    global ModelInlineValueObject, ixMsgCode
    if ModelInlineValueObject is None:
        from arelle.ModelInstanceObject import ModelInlineValueObject
        from arelle.XhtmlValidate import ixMsgCode
    isIxFact = isinstance(elt, ModelInlineValueObject)
    facets = None

    # attrQname can be provided for attributes that are global and LAX
    if (getattr(elt,"xValid", UNVALIDATED) == UNVALIDATED) and (not isIxFact or ixFacts):
        qnElt = elt.qname if ixFacts and isIxFact else elt.elementQname
        modelConcept = modelXbrl.qnameConcepts.get(qnElt)
        isAbstract = False
        if modelConcept is not None:
            isNillable = modelConcept.isNillable
            type = modelConcept.type
            if modelConcept.isAbstract:
                baseXsdType = "noContent"
                isAbstract = True
            elif modelConcept.isFraction:
                baseXsdType = "fraction"
            else:
                baseXsdType = modelConcept.baseXsdType
                facets = modelConcept.facets
        elif qnElt == XbrlConst.qnXbrldiExplicitMember: # not in DTS
            baseXsdType = "QName"
            type = None
            isNillable = False
        elif qnElt == XbrlConst.qnXbrldiTypedMember: # not in DTS
            baseXsdType = "noContent"
            type = None
            isNillable = False
        else:
            baseXsdType = None
            type = None
            isNillable = True # allow nil if no schema definition
        isNil = elt.get("{http://www.w3.org/2001/XMLSchema-instance}nil") in ("true", "1")
        if attrQname is None:
            if isNil and not isNillable:
                if ModelInlineValueObject is not None and isinstance(elt, ModelInlineValueObject):
                    errElt = "{0} fact {1}".format(elt.elementQname, elt.qname)
                else:
                    errElt = elt.elementQname
                modelXbrl.error("xmlSchema:nilNonNillableElement",
                    _("Element %(element)s fact %(fact)s type %(typeName)s is nil but element has not been defined nillable"),
                    modelObject=elt, element=errElt, fact=elt.qname, transform=elt.format,
                    typeName=modelConcept.baseXsdType if modelConcept is not None else "unknown",
                    value=XmlUtil.innerText(elt, ixExclude=True))
            try:
                if isAbstract:
                    raise ValueError("element is abstract")
                if isNil:
                    text = ""
                elif baseXsdType == "noContent":
                    text = elt.textValue # no descendant text nodes
                else:
                    text = elt.stringValue # include descendant text nodes
                    if len(text) == 0 and modelConcept is not None:
                        if modelConcept.default is not None:
                            text = modelConcept.default
                        elif modelConcept.fixed is not None:
                            text = modelConcept.fixed
            except Exception as err:
                if ModelInlineValueObject is not None and isinstance(elt, ModelInlineValueObject):
                    errElt = "{0} fact {1}".format(elt.elementQname, elt.qname)
                else:
                    errElt = elt.elementQname
                if isIxFact and err.__class__.__name__ == "FunctionArgType":
                    modelXbrl.error(ixMsgCode("transformValueError", elt),
                        _("Inline element %(element)s fact %(fact)s type %(typeName)s transform %(transform)s value error: %(value)s"),
                        modelObject=elt, element=errElt, fact=elt.qname, transform=elt.format,
                        typeName=modelConcept.baseXsdType if modelConcept is not None else "unknown",
                        value=XmlUtil.innerText(elt, ixExclude=True, ixContinuation=elt.namespaceURI==XbrlConst.ixbrl11))
                elif isIxFact and err.__class__.__name__ == "ixtFunctionNotAvailable":
                    modelXbrl.error(ixMsgCode("formatCodeUndefined", elt),
                        _("Inline element %(element)s fact %(fact)s type %(typeName)s transform %(transform)s not available, value: %(value)s"),
                        modelObject=elt, element=errElt, fact=elt.qname, transform=elt.format,
                        typeName=modelConcept.baseXsdType if modelConcept is not None else "unknown",
                        value=XmlUtil.innerText(elt, ixExclude=True, ixContinuation=elt.namespaceURI==XbrlConst.ixbrl11))
                elif isAbstract:
                    modelXbrl.error("xmlSchema:abstractElement",
                        _("Element %(element)s has abstract declaration, value: %(value)s"),
                        modelObject=elt, element=errElt, error=str(err), value=elt.text)
                else:
                    modelXbrl.error("xmlSchema:valueError",
                        _("Element %(element)s error %(error)s value: %(value)s"),
                        modelObject=elt, element=errElt, error=str(err), value=elt.text)
                elt.sValue = elt.xValue = text = INVALIDixVALUE
                elt.xValid = INVALID
            if text is not INVALIDixVALUE:
                validateValue(modelXbrl, elt, None, baseXsdType, text, isNillable, isNil, facets)
                # note that elt.sValue and elt.xValue are not innerText but only text elements on specific element (or attribute)
            if type is not None:
                definedAttributes = type.attributes
            else:
                definedAttributes = {}
            presentAttributes = set()
        # validate attributes
        # find missing attributes for default values
        for attrTag, attrValue in elt.items():
            qn = qnameClarkName(attrTag)
            #qn = qname(attrTag, noPrefixIsNoNamespace=True)
            baseXsdAttrType = None
            facets = None
            if attrQname is not None: # validate all attributes and element
                if attrQname != qn:
                    continue
            elif type is not None:
                presentAttributes.add(qn)
                if qn in definedAttributes: # look for concept-type-specific attribute definition
                    modelAttr = definedAttributes[qn]
                elif qn.namespaceURI:   # may be a globally defined attribute
                    modelAttr = modelXbrl.qnameAttributes.get(qn)
                else:
                    modelAttr = None
                if modelAttr is not None:
                    baseXsdAttrType = modelAttr.baseXsdType
                    facets = modelAttr.facets
            if baseXsdAttrType is None: # look for global attribute definition
                attrObject = modelXbrl.qnameAttributes.get(qn)
                if attrObject is not None:
                    baseXsdAttrType = attrObject.baseXsdType
                    facets = attrObject.facets
                elif attrTag == "{http://xbrl.org/2006/xbrldi}dimension": # some fallbacks?
                    baseXsdAttrType = "QName"
                elif attrTag == "id":
                    baseXsdAttrType = "ID"
                elif elt.namespaceURI == "http://www.w3.org/2001/XMLSchema":
                    if attrTag in {"type", "ref", "base", "refer", "itemType"}:
                        baseXsdAttrType = "QName"
                    elif attrTag in {"name"}:
                        baseXsdAttrType = "NCName"
                    elif attrTag in {"default", "fixed", "form"}:
                        baseXsdAttrType = "string"
                elif elt.namespaceURI == "http://xbrl.org/2006/xbrldi":
                    if attrTag == "dimension":
                        baseXsdAttrType = "QName"
                elif qn in predefinedAttributeTypes:
                    baseXsdAttrType, facets = predefinedAttributeTypes[qn]
            validateValue(modelXbrl, elt, attrTag, baseXsdAttrType, attrValue, facets=facets)
        # if no attributes assigned above, there won't be an xAttributes, if so assign a shared dict to save memory
        try:
            elt.xAttributes
        except AttributeError:
            elt.xAttributes = xAttributesSharedEmptyDict
            
        if type is not None:
            if attrQname is None:
                missingAttributes = type.requiredAttributeQnames - presentAttributes - elt.slottedAttributesNames
                if missingAttributes:
                    modelXbrl.error("xmlSchema:attributesRequired",
                        _("Element %(element)s type %(typeName)s missing required attributes: %(attributes)s"),
                        modelObject=elt,
                        element=qnElt,
                        typeName=baseXsdType,
                        attributes=','.join(str(a) for a in missingAttributes))
                extraAttributes = presentAttributes - _DICT_SET(definedAttributes.keys()) - XbrlConst.builtinAttributes
                if extraAttributes:
                    attributeWildcards = type.attributeWildcards
                    extraAttributes -= set(a
                                           for a in extraAttributes
                                           if validateAnyWildcard(qnElt, a, attributeWildcards))
                    if isIxFact:
                        extraAttributes -= XbrlConst.ixAttributes
                    if extraAttributes:
                        modelXbrl.error("xmlSchema:attributesExtraneous",
                            _("Element %(element)s type %(typeName)s extraneous attributes: %(attributes)s"),
                            modelObject=elt,
                            element=qnElt,
                            typeName=baseXsdType,
                            attributes=','.join(str(a) for a in extraAttributes))
                # add default attribute values
                for attrQname in (type.defaultAttributeQnames - presentAttributes):
                    modelAttr = type.attributes[attrQname]
                    validateValue(modelXbrl, elt, attrQname.clarkNotation, modelAttr.baseXsdType, modelAttr.default, facets=modelAttr.facets)
            if recurse:
                global validateElementSequence, modelGroupCompositorTitle
                if validateElementSequence is None:
                    from arelle.XmlValidateParticles import validateElementSequence, modelGroupCompositorTitle
                try:
                    #childElts = list(elt) # uses __iter__ for inline facts
                    childElts = [e for e in elt if isinstance(e, ModelObject)]
                    if isNil:
                        if childElts or elt.text:
                            modelXbrl.error("xmlSchema:nilElementHasContent",
                                _("Element %(element)s is nil but has contents"),
                                modelObject=elt,
                                element=qnElt)
                    else:
                        errResult = validateElementSequence(modelXbrl, type, childElts, ixFacts)
                        if errResult is not None and errResult[2]:
                            iElt, occured, errDesc, errArgs = errResult
                            errElt = childElts[iElt] if iElt < len(childElts) else elt
                            errArgs["modelObject"] = errElt
                            errArgs["element"] = errElt.qname
                            errArgs["parentElement"] = elt.qname
                            if "compositor" in errArgs:  # compositor is an object, provide friendly string
                                errArgs["compositor"] = modelGroupCompositorTitle(errArgs["compositor"])
                            modelXbrl.error(*errDesc,**errArgs)
                                                        
                            # when error is in an xbrli element, check any further unvalidated children
                            if qnElt.namespaceURI == XbrlConst.xbrli and iElt < len(childElts):
                                for childElt in childElts[iElt:]:
                                    if (getattr(childElt,"xValid", UNVALIDATED) == UNVALIDATED):
                                        validate(modelXbrl, childElt, ixFacts=ixFacts)
                    recurse = False # cancel child element validation below, recursion was within validateElementSequence
                except AttributeError as ex:
                    raise ex
                    #pass  # HF Why is this here????
    if recurse: # if there is no complex or simple type (such as xbrli:measure) then this code is used
        for child in (elt.modelTupleFacts if ixFacts and isIxFact else elt):
            if isinstance(child, ModelObject):     
                validate(modelXbrl, child, recurse, attrQname, ixFacts)