Esempio n. 1
0
 def addReferencedFile(docElt, elt):
     if elt.tag in ("a", "img", "{http://www.w3.org/1999/xhtml}a", "{http://www.w3.org/1999/xhtml}img"):
         for attrTag, attrValue in elt.items():
             if (attrTag in ("href", "src") and 
                 scheme(attrValue) not in ("data", "javascript") and (
                     not localFilesOnly or 
                     (not isHttpUrl(attrValue) and not os.path.isabs(attrValue)))):
                 attrValue = attrValue.partition('#')[0] # remove anchor
                 if attrValue: # ignore anchor references to base document
                     base = docElt.modelDocument.baseForElement(docElt)
                     normalizedUri = docElt.modelXbrl.modelManager.cntlr.webCache.normalizeUrl(attrValue, base)
                     if not docElt.modelXbrl.fileSource.isInArchive(normalizedUri):
                         normalizedUri = docElt.modelXbrl.modelManager.cntlr.webCache.getfilename(normalizedUri)
                     if modelXbrl.fileSource.isInArchive(normalizedUri, checkExistence=True) or modelXbrl.fileSource.exists(normalizedUri):
                         referencedFiles.add(attrValue) # add file name within source directory
Esempio n. 2
0
 def addReferencedFile(docElt, elt):
     if elt.tag in ("a", "img", "{http://www.w3.org/1999/xhtml}a", "{http://www.w3.org/1999/xhtml}img"):
         for attrTag, attrValue in elt.items():
             if (attrTag in ("href", "src") and 
                 scheme(attrValue) not in ("data", "javascript") and (
                     not localFilesOnly or 
                     (not isHttpUrl(attrValue) and not os.path.isabs(attrValue)))):
                 attrValue = attrValue.partition('#')[0].strip() # remove anchor
                 if attrValue not in ("", "."): # ignore anchor references to base document
                     base = docElt.modelDocument.baseForElement(docElt)
                     normalizedUri = docElt.modelXbrl.modelManager.cntlr.webCache.normalizeUrl(attrValue, base)
                     if not docElt.modelXbrl.fileSource.isInArchive(normalizedUri):
                         normalizedUri = docElt.modelXbrl.modelManager.cntlr.webCache.getfilename(normalizedUri)
                     if modelXbrl.fileSource.isInArchive(normalizedUri, checkExistence=True) or modelXbrl.fileSource.exists(normalizedUri):
                         referencedFiles.add(attrValue) # add file name within source directory
Esempio n. 3
0
def validateHtmlContent(modelXbrl, referenceElt, htmlEltTree, validatedObjectLabel, messageCodePrefix, isInline=False):
    checkedGraphicsFiles = set() # only check any graphics file reference once per footnote
    _xhtmlNs = "{{{}}}".format(xhtml)
    _xhtmlNsLen = len(_xhtmlNs)
    _tableTags = ("table", _xhtmlNs + "table")
    _anchorAncestorTags = set(_xhtmlNs + tag for tag in ("html", "body", "div"))
    allowedExternalHrefPattern = modelXbrl.modelManager.disclosureSystem.allowedExternalHrefPattern
    for elt in htmlEltTree.iter():
        if isinstance(elt, ModelObject) and elt.namespaceURI == xhtml:
            eltTag = elt.localName
        elif isinstance(elt, (_ElementTree, _Comment, _ProcessingInstruction)):
            continue # comment or other non-parsed element
        else:
            eltTag = elt.tag
            if eltTag.startswith(_xhtmlNs):
                eltTag = eltTag[_xhtmlNsLen:]
        if isInline:
            if eltTag in efmBlockedInlineHtmlElements:
                modelXbrl.error("EFM.5.02.05.disallowedElement",
                    _("%(validatedObjectLabel)s has disallowed element <%(element)s>"),
                    modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                    element=eltTag)
            if eltTag == "a" and "href" not in elt.keys() and any(a.tag not in _anchorAncestorTags for a in elt.iterancestors()):
                modelXbrl.warning("EFM.5.02.05.anchorElementPosition",
                    _("If element <a> does not have attribute @href, it should not have any ancestors other than html, body, or div.  Disallowed ancestors: %(disallowedAncestors)s"),
                    modelObject=elt, disallowedAncestors=", ".join(a.tag.rpartition('}')[2] for a in elt.iterancestors() if a.tag not in _anchorAncestorTags))      
        for attrTag, attrValue in elt.items():
            if isInline:
                if attrTag in efmBlockedInlineHtmlElementAttributes.get(eltTag,()):
                    modelXbrl.error("EFM.5.02.05.disallowedAttribute",
                        _("%(validatedObjectLabel)s has disallowed attribute on element <%(element)s>: %(attribute)s=\"%(value)s\""),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        element=eltTag, attribute=attrTag, value=attrValue)
                elif attrTag == "{http://www.w3.org/XML/1998/namespace}base":
                    modelXbrl.error("EFM.5.02.05.xmlBaseDisallowed",
                        _("%(validatedObjectLabel)s has disallowed attribute on element <%(element)s>: xml:base=\"%(value)s\""),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        element=eltTag, value=attrValue)
                elif attrTag == "{http://www.w3.org/2001/XMLSchema-instance}schemaLocation":
                    modelXbrl.warning("EFM.5.02.05.schemaLocationDisallowed",
                        _("%(validatedObjectLabel)s has disallowed attribute on element <%(element)s>: xsi:schemaLocation=\"%(value)s\""),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        element=eltTag, value=attrValue)
            if ((attrTag == "href" and eltTag == "a") or 
                (attrTag == "src" and eltTag == "img")):
                if "javascript:" in attrValue:
                    modelXbrl.error(messageCodePrefix + "activeContent",
                        _("%(validatedObjectLabel)s has javascript in '%(attribute)s' for <%(element)s>"),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        attribute=attrTag, element=eltTag,
                        messageCodes=("EFM.6.05.34.activeContent", "EFM.5.02.05.activeContent"))
                elif eltTag == "a" and (not allowedExternalHrefPattern or allowedExternalHrefPattern.match(attrValue)):
                    pass
                elif scheme(attrValue) in ("http", "https", "ftp"):
                    modelXbrl.error(messageCodePrefix + "externalReference",
                        _("%(validatedObjectLabel)s has an invalid external reference in '%(attribute)s' for <%(element)s>: %(value)s"),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        attribute=attrTag, element=eltTag, value=attrValue,
                        messageCodes=("EFM.6.05.34.externalReference", "EFM.5.02.05.externalReference"))
                if attrTag == "src" and attrValue not in checkedGraphicsFiles:
                    if scheme(attrValue) == "data":
                        modelXbrl.error(messageCodePrefix + "graphicDataUrl",
                            _("%(validatedObjectLabel)s references a graphics data URL which isn't accepted '%(attribute)s' for <%(element)s>"),
                            modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                            attribute=attrValue[:32], element=eltTag)
                    elif attrValue.lower()[-4:] not in ('.jpg', '.gif'):
                        modelXbrl.error(messageCodePrefix + "graphicFileType",
                            _("%(validatedObjectLabel)s references a graphics file which isn't .gif or .jpg '%(attribute)s' for <%(element)s>"),
                            modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                            attribute=attrValue, element=eltTag,
                            messageCodes=("EFM.6.05.34.graphicFileType", "EFM.5.02.05.graphicFileType"))
                    else:   # test file contents
                        try:
                            if validateGraphicFile(referenceElt, attrValue) != attrValue.lower()[-3:]:
                                modelXbrl.error(messageCodePrefix +"graphicFileContent",
                                    _("%(validatedObjectLabel)s references a graphics file which doesn't have expected content '%(attribute)s' for <%(element)s>"),
                                    modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                                    attribute=attrValue, element=eltTag,
                                    messageCodes=("EFM.6.05.34.graphicFileContent", "EFM.5.02.05.graphicFileContent"))
                        except IOError as err:
                            modelXbrl.error(messageCodePrefix + "graphicFileError",
                                _("%(validatedObjectLabel)s references a graphics file which isn't openable '%(attribute)s' for <%(element)s>, error: %(error)s"),
                                modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                                attribute=attrValue, element=eltTag, error=err,
                                messageCodes=("EFM.6.05.34.graphicFileError", "EFM.5.02.05.graphicFileError"))
                    checkedGraphicsFiles.add(attrValue)
            if eltTag == "meta" and attrTag == "content" and not attrValue.startswith("text/html"):
                modelXbrl.error(messageCodePrefix + "disallowedMetaContent",
                    _("%(validatedObjectLabel)s <meta> content is \"%(metaContent)s\" but must be \"text/html\""),
                    modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                    metaContent=attrValue,
                    messageCodes=("EFM.6.05.34.disallowedMetaContent", "EFM.5.02.05.disallowedMetaContent"))
        if eltTag == "table" and any(a.tag in _tableTags
                                     for a in elt.iterancestors()):
            modelXbrl.error(messageCodePrefix + "nestedTable",
                _("%(validatedObjectLabel)s has nested <table> elements."),
                modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                messageCodes=("EFM.6.05.34.nestedTable", "EFM.5.02.05.nestedTable"))
Esempio n. 4
0
def validateTextBlockFacts(modelXbrl):
    #handler = TextBlockHandler(modelXbrl)
    loadDTD(modelXbrl)
    checkedGraphicsFiles = set() #  only check any graphics file reference once per fact
    allowedExternalHrefPattern = modelXbrl.modelManager.disclosureSystem.allowedExternalHrefPattern
    
    if isInlineDTD:
        htmlBodyTemplate = "<body><div>\n{0}\n</div></body>\n"
    else:
        htmlBodyTemplate = "<body>\n{0}\n</body>\n"
    _xhtmlNs = "{{{}}}".format(xhtml)
    _xhtmlNsLen = len(_xhtmlNs)
    
    for f1 in modelXbrl.facts:
        # build keys table for 6.5.14
        concept = f1.concept
        if f1.xsiNil != "true" and \
           concept is not None and \
           concept.isTextBlock and \
           XMLpattern.match(f1.value):
            #handler.fact = f1
            # test encoded entity tags
            for match in namedEntityPattern.finditer(f1.value):
                entity = match.group()
                if not entity in xhtmlEntities:
                    modelXbrl.error(("EFM.6.05.16", "GFM.1.2.15"),
                        _("Fact %(fact)s contextID %(contextID)s has disallowed entity %(entity)s"),
                        modelObject=f1, fact=f1.qname, contextID=f1.contextID, entity=entity, error=entity)
            # test html
            for xmltext in [f1.value] + CDATApattern.findall(f1.value):
                '''
                try:
                    xml.sax.parseString(
                        "<?xml version='1.0' encoding='utf-8' ?>\n<body>\n{0}\n</body>\n".format(
                         removeEntities(xmltext)).encode('utf-8'),handler,handler)
                except (xml.sax.SAXParseException,
                        xml.sax.SAXException,
                        UnicodeDecodeError) as err:
                    # ignore errors which are not errors (e.g., entity codes checked previously
                    if not err.endswith("undefined entity"):
                        handler.modelXbrl.error(("EFM.6.05.15", "GFM.1.02.14"),
                            _("Fact %(fact)s contextID %(contextID)s has text which causes the XML error %(error)s"),
                            modelObject=f1, fact=f1.qname, contextID=f1.contextID, error=err)
                '''
                xmlBodyWithoutEntities = htmlBodyTemplate.format(removeEntities(xmltext))
                try:
                    textblockXml = XML(xmlBodyWithoutEntities)
                    if not edbodyDTD.validate( textblockXml ):
                        errors = edbodyDTD.error_log.filter_from_errors()
                        htmlError = any(e.type_name in ("DTD_INVALID_CHILD", "DTD_UNKNOWN_ATTRIBUTE") 
                                        for e in errors)
                        modelXbrl.error("EFM.6.05.16" if htmlError else ("EFM.6.05.15.dtdError", "GFM.1.02.14"),
                            _("Fact %(fact)s contextID %(contextID)s has text which causes the XML error %(error)s"),
                            modelObject=f1, fact=f1.qname, contextID=f1.contextID, 
                            error=', '.join(e.message for e in errors),
                            messageCodes=("EFM.6.05.16", "EFM.6.05.15.dtdError", "GFM.1.02.14"))
                    for elt in textblockXml.iter():
                        eltTag = elt.tag
                        if isinstance(elt, ModelObject) and elt.namespaceURI == xhtml:
                            eltTag = elt.localName
                        elif isinstance(elt, (_ElementTree, _Comment, _ProcessingInstruction)):
                            continue # comment or other non-parsed element
                        else:
                            eltTag = elt.tag
                            if eltTag.startswith(_xhtmlNs):
                                eltTag = eltTag[_xhtmlNsLen:]
                        if isInlineDTD and eltTag in efmBlockedInlineHtmlElements:
                            modelXbrl.error("EFM.5.02.05.disallowedElement",
                                _("%(validatedObjectLabel)s has disallowed element <%(element)s>"),
                                modelObject=elt, validatedObjectLabel=f1.qname,
                                element=eltTag)
                        for attrTag, attrValue in elt.items():
                            if isInlineDTD:
                                if attrTag in efmBlockedInlineHtmlElementAttributes.get(eltTag,()):
                                    modelXbrl.error("EFM.5.02.05.disallowedAttribute",
                                        _("%(validatedObjectLabel)s has disallowed attribute on element <%(element)s>: %(attribute)s=\"%(value)s\""),
                                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                                        element=eltTag, attribute=attrTag, value=attrValue)
                            if ((attrTag == "href" and eltTag == "a") or 
                                (attrTag == "src" and eltTag == "img")):
                                if "javascript:" in attrValue:
                                    modelXbrl.error("EFM.6.05.16.activeContent",
                                        _("Fact %(fact)s of context %(contextID)s has javascript in '%(attribute)s' for <%(element)s>"),
                                        modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                        attribute=attrTag, element=eltTag)
                                elif eltTag == "a" and (not allowedExternalHrefPattern or allowedExternalHrefPattern.match(attrValue)):
                                    pass
                                elif scheme(attrValue) in ("http", "https", "ftp"):
                                    modelXbrl.error("EFM.6.05.16.externalReference",
                                        _("Fact %(fact)s of context %(contextID)s has an invalid external reference in '%(attribute)s' for <%(element)s>"),
                                        modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                        attribute=attrTag, element=eltTag)
                                if attrTag == "src" and attrValue not in checkedGraphicsFiles:
                                    if scheme(attrValue)  == "data":
                                        modelXbrl.error("EFM.6.05.16.graphicDataUrl",
                                            _("Fact %(fact)s of context %(contextID)s references a graphics data URL which isn't accepted '%(attribute)s' for <%(element)s>"),
                                            modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                            attribute=attrValue[:32], element=eltTag)
                                    elif attrValue.lower()[-4:] not in ('.jpg', '.gif'):
                                        modelXbrl.error("EFM.6.05.16.graphicFileType",
                                            _("Fact %(fact)s of context %(contextID)s references a graphics file which isn't .gif or .jpg '%(attribute)s' for <%(element)s>"),
                                            modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                            attribute=attrValue, element=eltTag)
                                    else:   # test file contents
                                        try:
                                            if validateGraphicFile(f1, attrValue) != attrValue.lower()[-3:]:
                                                modelXbrl.error("EFM.6.05.16.graphicFileContent",
                                                    _("Fact %(fact)s of context %(contextID)s references a graphics file which doesn't have expected content '%(attribute)s' for <%(element)s>"),
                                                    modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                                    attribute=attrValue, element=eltTag)
                                        except IOError as err:
                                            modelXbrl.error("EFM.6.05.16.graphicFileError",
                                                _("Fact %(fact)s of context %(contextID)s references a graphics file which isn't openable '%(attribute)s' for <%(element)s>, error: %(error)s"),
                                                modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                                attribute=attrValue, element=eltTag, error=err)
                                    checkedGraphicsFiles.add(attrValue)
                        if eltTag == "table" and any(a is not None for a in elt.iterancestors("table")):
                            modelXbrl.error("EFM.6.05.16.nestedTable",
                                _("Fact %(fact)s of context %(contextID)s has nested <table> elements."),
                                modelObject=f1, fact=f1.qname, contextID=f1.contextID)
                except (XMLSyntaxError,
                        UnicodeDecodeError) as err:
                    #if not err.endswith("undefined entity"):
                    modelXbrl.error(("EFM.6.05.15", "GFM.1.02.14"),
                        _("Fact %(fact)s contextID %(contextID)s has text which causes the XML error %(error)s"),
                        modelObject=f1, fact=f1.qname, contextID=f1.contextID, error=err)
                    
                checkedGraphicsFiles.clear()
Esempio n. 5
0
def checkImageContents(modelXbrl, imgElt, imgType, isFile, data):
    if "svg" in imgType:
        try:
            rootElement = True
            for elt in XML(data).iter():
                if rootElement:
                    if elt.tag != "{http://www.w3.org/2000/svg}svg":
                        modelXbrl.error(
                            "ESEF.2.5.1.imageFileCannotBeLoaded",
                            _("Image SVG has root element which is not svg"),
                            modelObject=imgElt)
                    rootElement = False
                eltTag = elt.tag.rpartition("}")[2]  # strip namespace
                if ((eltTag in ("object", "script"))
                        or (eltTag in ("audio", "foreignObject", "iframe",
                                       "image", "use", "video"))):
                    href = elt.get("href", "")
                    if eltTag in ("object", "script") or "javascript:" in href:
                        modelXbrl.error(
                            "ESEF.2.5.1.executableCodePresent",
                            _("Inline XBRL images MUST NOT contain executable code: %(element)s"
                              ),
                            modelObject=imgElt,
                            element=eltTag)
                    elif scheme(href) in ("http", "https", "ftp"):
                        modelXbrl.error(
                            "ESEF.2.5.1.referencesPointingOutsideOfTheReportingPackagePresent",
                            _("Inline XBRL instance document [image] MUST NOT contain any reference pointing to resources outside the reporting package: %(element)s"
                              ),
                            modelObject=imgElt,
                            element=eltTag)
        except (XMLSyntaxError, UnicodeDecodeError) as err:
            modelXbrl.error("ESEF.2.5.1.imageFileCannotBeLoaded",
                            _("Image SVG has XML error %(error)s"),
                            modelObject=imgElt,
                            error=err)
    elif not any(t in imgType for t in ("gif", "jpg", "jpeg", "png")):
        modelXbrl.error(
            "ESEF.2.5.1.imageFormatNotSupported",
            _("Images included in the XHTML document MUST be saved in PNG, GIF, SVG or JPG/JPEG formats: %(imgType)s is not supported"
              ),
            modelObject=imgElt,
            imgType=imgType)
    else:
        if data[:3] == b"GIF" and data[3:6] in (b'89a', b'89b', b'87a'):
            headerType = "gif"
        elif ((data[:4] == b'\xff\xd8\xff\xe0' and data[6:11] == b'JFIF\x00')
              or
              (data[:4] == b'\xff\xd8\xff\xe1' and data[6:11] == b'Exif\x00')):
            headerType = "jpg"
        elif data[:8] == b"\x89PNG\r\n\x1a\n":
            headerType = "png"
        elif data[:2] in (b"MM", b"II"):
            headerType = "tiff"
        elif data[:2] in (b"BM", b"BA"):
            headerType = "bmp"
        elif data[:4] == b"\x00\x00\x01\x00":
            headerType = "ico"
        elif data[:4] == b"\x00\x00\x02\x00":
            headerType = "cur"
        elif len(data) == 0:
            headerType = "none"
        else:
            headerType = "unrecognized"
        if (("gif" in imgType and headerType != "gif") or
            (("jpg" in imgType or "jpeg" in imgType) and headerType != "jpg")
                or ("png" in imgType and headerType != "png")):
            modelXbrl.error(
                "ESEF.2.5.1.imageDoesNotMatchItsFileExtension"
                if isFile else "ESEF.2.5.1.incorrectMIMETypeSpecified",
                _("Image type %(imgType)s has wrong header type: %(headerType)s"
                  ),
                modelObject=imgElt,
                imgType=imgType,
                headerType=headerType,
                messageCodes=("ESEF.2.5.1.imageDoesNotMatchItsFileExtension",
                              "ESEF.2.5.1.incorrectMIMETypeSpecified"))
Esempio n. 6
0
def validateXbrlFinally(val, *args, **kwargs):
    if not (val.validateEFMHTMplugin):
        return

    modelXbrl = val.modelXbrl
    allowedExternalHrefPattern = modelXbrl.modelManager.disclosureSystem.allowedExternalHrefPattern
    #efmHtmDTD = None
    #with open(os.path.join(os.path.dirname(__file__), "resources", "efm-htm.dtd")) as fh:
    #    efmHtmDTD = DTD(fh)
    #if efmHtmDTD and not efmHtmDTD.validate( modelXbrl.modelDocument.xmlRootElement ):
    #    for e in efmHtmDTD.error_log.filter_from_errors():
    #        if "declared in the external subset contains white spaces nodes" not in e.message:
    #            modelXbrl.error("html.syntax",
    #                _("HTML error %(error)s"),
    #                error=e.message)
    numHtmlTags = 0
    inBody = False
    for elt in modelXbrl.modelDocument.xmlRootElement.iter():
        if isinstance(elt, (_ElementTree, _Comment, _ProcessingInstruction)):
            continue  # comment or other non-parsed element
        eltTag = elt.tag.lower()
        for attrTag, attrValue in elt.items():
            if ((attrTag == "href" and eltTag == "a")
                    or (attrTag == "src" and eltTag == "img")):
                if "javascript:" in attrValue:
                    modelXbrl.error(
                        "EFM.5.02.02.10.activeContent",
                        _("Element has javascript in '%(attribute)s' for <%(element)s>"
                          ),
                        modelObject=elt,
                        attribute=attrTag,
                        element=eltTag)
                elif eltTag == "a" and (
                        not allowedExternalHrefPattern
                        or allowedExternalHrefPattern.match(attrValue)):
                    pass
                elif scheme(attrValue) in ("http", "https", "ftp", "mailto"):
                    modelXbrl.error(
                        "EFM.6.05.16.externalReference",
                        _("Element has an invalid external reference in '%(attribute)s' for <%(element)s>"
                          ),
                        modelObject=elt,
                        attribute=attrTag,
                        element=eltTag)
                if attrTag == "src":
                    if scheme(attrValue) == "data":
                        modelXbrl.error(
                            "EFM.5.02.02.10.graphicDataUrl",
                            _("Element references a graphics data URL which isn't accepted '%(attribute)s' for <%(element)s>"
                              ),
                            modelObject=elt,
                            attribute=attrValue[:32],
                            element=eltTag)
                    elif attrValue.lower()[-4:] not in ('.jpg', '.gif'):
                        modelXbrl.error(
                            "EFM.5.02.02.10.graphicFileType",
                            _("Element references a graphics file which isn't .gif or .jpg '%(attribute)s' for <%(element)s>"
                              ),
                            modelObject=elt,
                            attribute=attrValue,
                            element=eltTag)
            elif attrTag in disallowedElementAttrs.get(
                    eltTag, ()) or attrTag in disallowedElementAttrs["*"]:
                modelXbrl.error(
                    "EFM.5.02.02.05.disallowedAttribute",
                    _("Element has disallowed attribute '%(attribute)s' for <%(element)s>"
                      ),
                    modelObject=elt,
                    attribute=attrTag,
                    element=eltTag)
            elif attrTag.startswith("xmlns"):
                modelXbrl.error(
                    "EFM.5.02.02.05.xmlns",
                    _("Element has disallowed xmlns declaration '%(attribute)s' for <%(element)s>"
                      ),
                    modelObject=elt,
                    attribute=attrTag,
                    element=eltTag)
        if eltTag == "html":
            numHtmlTags += 1
            if numHtmlTags > 1:
                modelXbrl.error("EFM.5.02.02.02.htmlTags",
                                _("Document can only have one html tag"),
                                modelObject=elt)
        elif eltTag in ("head", "meta", "isindex", "title"):
            pass  # these are allowed
        elif eltTag == "body":
            inBody = True
        elif eltTag == "table":
            if any(a is not None for a in elt.iterancestors("table")):
                modelXbrl.error("EFM.5.02.02.10.nestedTable",
                                _("Element is a disallowed nested <table>."),
                                modelObject=elt)
        elif eltTag in disallowedElements:
            modelXbrl.error("EFM.5.02.02.04.disallowedElement",
                            _("Element is disallowed: <%(element)s>"),
                            modelObject=elt,
                            element=eltTag)
        elif eltTag not in recognizedElements:
            modelXbrl.error("EFM.5.02.02.03.unrecognizedElement",
                            _("Element is not recognized: <%(element)s>"),
                            modelObject=elt,
                            element=eltTag)
        elif not inBody:
            modelXbrl.error("EFM.5.02.02.03.bodyTags",
                            _("Element is not in a body: <%(element)s>"),
                            modelObject=elt,
                            element=eltTag)
Esempio n. 7
0
def validateXbrlFinally(val, *args, **kwargs):
    if not (val.validateESEFplugin):
        return

    _xhtmlNs = "{{{}}}".format(xhtml)
    _xhtmlNsLen = len(_xhtmlNs)
    modelXbrl = val.modelXbrl
    modelDocument = modelXbrl.modelDocument

    _statusMsg = _("validating {0} filing rules").format(
        val.disclosureSystem.name)
    modelXbrl.profileActivity()
    modelXbrl.modelManager.showStatus(_statusMsg)

    reportXmlLang = None
    firstRootmostXmlLangDepth = 9999999

    _ifrsNs = None
    for targetNs in modelXbrl.namespaceDocs.keys():
        if ifrsNsPattern.match(targetNs):
            _ifrsNs = targetNs
    if not _ifrsNs:
        modelXbrl.error("ESEF.RTS.ifrsRequired",
                        _("RTS on ESEF requires IFRS taxonomy."),
                        modelObject=modelXbrl)
        return

    esefPrimaryStatementPlaceholders = set(
        qname(_ifrsNs, n) for n in esefPrimaryStatementPlaceholderNames)
    esefMandatoryElements2020 = set(
        qname(_ifrsNs, n) for n in esefMandatoryElementNames2020)

    if modelDocument.type == ModelDocument.Type.INSTANCE:
        modelXbrl.error("ESEF.I.1.instanceShallBeInlineXBRL",
                        _("RTS on ESEF requires inline XBRL instances."),
                        modelObject=modelXbrl)

    checkFilingDimensions(
        val)  # sets up val.primaryItems and val.domainMembers
    val.hasExtensionSchema = val.hasExtensionPre = val.hasExtensionCal = val.hasExtensionDef = val.hasExtensionLbl = False
    checkFilingDTS(val, modelXbrl.modelDocument, [])
    modelXbrl.profileActivity("... filer DTS checks", minTimeToShow=1.0)

    if not (val.hasExtensionSchema and val.hasExtensionPre
            and val.hasExtensionCal and val.hasExtensionDef
            and val.hasExtensionLbl):
        missingFiles = []
        if not val.hasExtensionSchema: missingFiles.append("schema file")
        if not val.hasExtensionPre:
            missingFiles.append("presentation linkbase")
        if not val.hasExtensionCal: missingFiles.append("calculation linkbase")
        if not val.hasExtensionDef: missingFiles.append("definition linkbase")
        if not val.hasExtensionLbl: missingFiles.append("label linkbase")
        modelXbrl.warning(
            "ESEF.3.1.1.extensionTaxonomyWrongFilesStructure",
            _("Extension taxonomies MUST consist of at least a schema file and presentation, calculation, definition and label linkbases"
              ": missing %(missingFiles)s"),
            modelObject=modelXbrl,
            missingFiles=", ".join(missingFiles))

    #if modelDocument.type == ModelDocument.Type.INLINEXBRLDOCUMENTSET:
    #    # reports only under reports, none elsewhere
    #    modelXbrl.fileSource.dir

    if modelDocument.type in (ModelDocument.Type.INLINEXBRL,
                              ModelDocument.Type.INLINEXBRLDOCUMENTSET,
                              ModelDocument.Type.INSTANCE):
        footnotesRelationshipSet = modelXbrl.relationshipSet("XBRL-footnotes")
        orphanedFootnotes = set()
        noLangFootnotes = set()
        factLangFootnotes = defaultdict(set)
        footnoteRoleErrors = set()
        transformRegistryErrors = set()

        def checkFootnote(elt, text):
            if text:  # non-empty footnote must be linked to a fact if not empty
                if not any(
                        isinstance(rel.fromModelObject, ModelFact) for rel in
                        footnotesRelationshipSet.toModelObject(elt)):
                    orphanedFootnotes.add(elt)
            lang = elt.xmlLang
            if not lang:
                noLangFootnotes.add(elt)
            else:
                for rel in footnotesRelationshipSet.toModelObject(elt):
                    if rel.fromModelObject is not None:
                        factLangFootnotes[rel.fromModelObject].add(lang)
            if elt.role != XbrlConst.footnote or not all(
                    rel.arcrole == XbrlConst.factFootnote
                    and rel.linkrole == XbrlConst.defaultLinkRole
                    for rel in footnotesRelationshipSet.toModelObject(elt)):
                footnoteRoleErrors.add(elt)

        # check file name of each inline document (which might be below a top-level IXDS)
        for doc in modelXbrl.urlDocs.values():
            if doc.type == ModelDocument.Type.INLINEXBRL:
                _baseName, _baseExt = os.path.splitext(doc.basename)
                if _baseExt not in (".xhtml", ".html"):
                    modelXbrl.warning(
                        "ESEF.RTS.Art.3.fileNameExtension",
                        _("FileName SHOULD have the extension .xhtml or .html: %(fileName)s"
                          ),
                        modelObject=doc,
                        fileName=doc.basename)
                docinfo = doc.xmlRootElement.getroottree().docinfo
                if " html" in docinfo.doctype:
                    modelXbrl.warning(
                        "ESEF.RTS.Art.3.htmlDoctype",
                        _("Doctype SHOULD NOT be html: %(fileName)s"),
                        modelObject=doc,
                        fileName=doc.basename)

        if modelDocument.type in (ModelDocument.Type.INLINEXBRL,
                                  ModelDocument.Type.INLINEXBRLDOCUMENTSET):
            hiddenEltIds = {}
            presentedHiddenEltIds = defaultdict(list)
            eligibleForTransformHiddenFacts = []
            requiredToDisplayFacts = []
            requiredToDisplayFactIds = {}
            firstIxdsDoc = True
            for ixdsHtmlRootElt in modelXbrl.ixdsHtmlElements:  # ix root elements for all ix docs in IXDS
                ixNStag = ixdsHtmlRootElt.modelDocument.ixNStag
                ixTags = set(ixNStag + ln
                             for ln in ("nonNumeric", "nonFraction",
                                        "references", "relationship"))
                ixTextTags = set(ixNStag + ln
                                 for ln in ("nonFraction", "continuation",
                                            "footnote"))
                ixExcludeTag = ixNStag + "exclude"
                ixTupleTag = ixNStag + "tuple"
                ixFractionTag = ixNStag + "fraction"
                for elt, depth in etreeIterWithDepth(ixdsHtmlRootElt):
                    eltTag = elt.tag
                    if isinstance(
                            elt,
                        (_ElementTree, _Comment, _ProcessingInstruction)):
                        continue  # comment or other non-parsed element
                    else:
                        eltTag = elt.tag
                        if eltTag.startswith(_xhtmlNs):
                            eltTag = eltTag[_xhtmlNsLen:]
                            if firstIxdsDoc and (not reportXmlLang or depth <
                                                 firstRootmostXmlLangDepth):
                                xmlLang = elt.get(
                                    "{http://www.w3.org/XML/1998/namespace}lang"
                                )
                                if xmlLang:
                                    reportXmlLang = xmlLang
                                    firstRootmostXmlLangDepth = depth
                        if ((eltTag in ("object", "script"))
                                or (eltTag == "a"
                                    and "javascript:" in elt.get("href", ""))
                                or (eltTag == "img"
                                    and "javascript:" in elt.get("src", ""))):
                            modelXbrl.error(
                                "ESEF.2.5.1.executableCodePresent",
                                _("Inline XBRL documents MUST NOT contain executable code: %(element)s"
                                  ),
                                modelObject=elt,
                                element=eltTag)
                        elif eltTag == "img":
                            src = elt.get("src", "").strip()
                            hasParentIxTextTag = False  # check if image is in an ix text-bearing element
                            _ancestorElt = elt
                            while (_ancestorElt is not None):
                                if _ancestorElt.tag == ixExcludeTag:  # excluded from any parent text-bearing ix element
                                    break
                                if _ancestorElt.tag in ixTextTags:
                                    hasParentIxTextTag = True
                                    break
                                _ancestorElt = _ancestorElt.getparent()
                            if scheme(src) in ("http", "https", "ftp"):
                                modelXbrl.error(
                                    "ESEF.3.5.1.inlinXbrlContainsExternalReferences",
                                    _("Inline XBRL instance documents MUST NOT contain any reference pointing to resources outside the reporting package: %(element)s"
                                      ),
                                    modelObject=elt,
                                    element=eltTag)
                            elif not src.startswith("data:image"):
                                if hasParentIxTextTag:
                                    modelXbrl.error(
                                        "ESEF.2.5.1.imageInIXbrlElementNotEmbedded",
                                        _("Images appearing within an inline XBRL element MUST be embedded regardless of their size."
                                          ),
                                        modelObject=elt)
                                else:
                                    # presume it to be an image file, check image contents
                                    try:
                                        base = elt.modelDocument.baseForElement(
                                            elt)
                                        normalizedUri = elt.modelXbrl.modelManager.cntlr.webCache.normalizeUrl(
                                            src, base)
                                        if not elt.modelXbrl.fileSource.isInArchive(
                                                normalizedUri):
                                            normalizedUri = elt.modelXbrl.modelManager.cntlr.webCache.getfilename(
                                                normalizedUri)
                                        imglen = 0
                                        with elt.modelXbrl.fileSource.file(
                                                normalizedUri,
                                                binary=True)[0] as fh:
                                            imglen += len(fh.read())
                                        if imglen < browserMaxBase64ImageLength:
                                            modelXbrl.error(
                                                "ESEF.2.5.1.embeddedImageNotUsingBase64Encoding",
                                                _("Images MUST be included in the XHTML document as a base64 encoded string unless their size exceeds support of browsers (%(maxImageSize)s): %(file)s."
                                                  ),
                                                modelObject=elt,
                                                maxImageSize=
                                                browserMaxBase64ImageLength,
                                                file=os.path.basename(
                                                    normalizedUri))
                                    except IOError as err:
                                        modelXbrl.error(
                                            "ESEF.2.5.1.imageFileCannotBeLoaded",
                                            _("Image file which isn't openable '%(src)s', error: %(error)s"
                                              ),
                                            modelObject=elt,
                                            src=src,
                                            error=err)
                            elif not any(
                                    src.startswith(m)
                                    for m in allowedImgMimeTypes):
                                modelXbrl.error(
                                    "ESEF.2.5.1.embeddedImageNotUsingBase64Encoding",
                                    _("Images MUST be included in the XHTML document as a base64 encoded string, encoding disallowed: %(src)s."
                                      ),
                                    modelObject=elt,
                                    src=attrValue[:128])

                        elif eltTag == "a":
                            href = elt.get("href", "").strip()
                            if scheme(href) in ("http", "https", "ftp"):
                                modelXbrl.error(
                                    "ESEF.3.5.1.inlinXbrlContainsExternalReferences",
                                    _("Inline XBRL instance documents MUST NOT contain any reference pointing to resources outside the reporting package: %(element)s"
                                      ),
                                    modelObject=elt,
                                    element=eltTag)
                        elif eltTag == "base" or elt.tag == "{http://www.w3.org/XML/1998/namespace}base":
                            modelXbrl.error(
                                "ESEF.2.4.2.htmlOrXmlBaseUsed",
                                _("The HTML <base> elements and xml:base attributes MUST NOT be used in the Inline XBRL document."
                                  ),
                                modelObject=elt,
                                element=eltTag)
                        elif eltTag == "link" and elt.get(
                                "type") == "text/css":
                            if len(modelXbrl.ixdsHtmlElements) > 1:
                                f = elt.get("href")
                                if not f or isHttpUrl(f) or os.path.isabs(f):
                                    modelXbrl.warning(
                                        "ESEF.2.5.4.externalCssReportPackage",
                                        _("The CSS file should be physically stored within the report package: %{file}s."
                                          ),
                                        modelObject=elt,
                                        file=f)
                            else:
                                modelXbrl.error(
                                    "ESEF.2.5.4.externalCssFileForSingleIXbrlDocument",
                                    _("Where an Inline XBRL document set contains a single document, the CSS MUST be embedded within the document."
                                      ),
                                    modelObject=elt,
                                    element=eltTag)
                        elif eltTag == "style" and elt.get(
                                "type") == "text/css":
                            if len(modelXbrl.ixdsHtmlElements) > 1:
                                modelXbrl.warning(
                                    "ESEF.2.5.4.embeddedCssForMultiHtmlIXbrlDocumentSets",
                                    _("Where an Inline XBRL document set contains multiple documents, the CSS SHOULD be defined in a separate file."
                                      ),
                                    modelObject=elt,
                                    element=eltTag)

                    if eltTag in ixTags and elt.get("target"):
                        modelXbrl.error(
                            "ESEF.2.5.3.targetAttributeUsed",
                            _("Target attribute MUST not be used: element %(localName)s, target attribute %(target)s."
                              ),
                            modelObject=elt,
                            localName=elt.elementQname,
                            target=elt.get("target"))
                    if eltTag == ixTupleTag:
                        modelXbrl.error(
                            "ESEF.2.4.1.tupleElementUsed",
                            _("The ix:tuple element MUST not be used in the Inline XBRL document: %(qname)s."
                              ),
                            modelObject=elt,
                            qname=elt.qname)
                    if eltTag == ixFractionTag:
                        modelXbrl.error(
                            "ESEF.2.4.1.fractionElementUsed",
                            _("The ix:fraction element MUST not be used in the Inline XBRL document."
                              ),
                            modelObject=elt)
                    if elt.get("{http://www.w3.org/XML/1998/namespace}base"
                               ) is not None:
                        modelXbrl.error(
                            "ESEF.2.4.1.xmlBaseUsed",
                            _("xml:base attributes MUST NOT be used in the Inline XBRL document: element %(localName)s, base attribute %(base)s."
                              ),
                            modelObject=elt,
                            localName=elt.elementQname,
                            base=elt.get(
                                "{http://www.w3.org/XML/1998/namespace}base"))
                    if isinstance(elt, ModelInlineFootnote):
                        checkFootnote(elt, elt.value)
                    elif isinstance(
                            elt, ModelResource
                    ) and elt.qname == XbrlConst.qnLinkFootnote:
                        checkFootnote(elt, elt.value)
                    elif isinstance(elt, ModelInlineFact):
                        if elt.format is not None and elt.format.namespaceURI not in IXT_NAMESPACES:
                            transformRegistryErrors.add(elt)
                for ixHiddenElt in ixdsHtmlRootElt.iterdescendants(
                        tag=ixNStag + "hidden"):
                    for tag in (ixNStag + "nonNumeric",
                                ixNStag + "nonFraction"):
                        for ixElt in ixHiddenElt.iterdescendants(tag=tag):
                            if (
                                    getattr(ixElt, "xValid",
                                            0) >= VALID  # may not be validated
                            ):  # add future "and" conditions on elements which can be in hidden
                                if (ixElt.concept.baseXsdType
                                        not in untransformableTypes
                                        and not ixElt.isNil):
                                    eligibleForTransformHiddenFacts.append(
                                        ixElt)
                                elif ixElt.id is None:
                                    requiredToDisplayFacts.append(ixElt)
                            if ixElt.id:
                                hiddenEltIds[ixElt.id] = ixElt
                firstIxdsDoc = False
            if eligibleForTransformHiddenFacts:
                modelXbrl.warning(
                    "ESEF.2.4.1.transformableElementIncludedInHiddenSection",
                    _("The ix:hidden section of Inline XBRL document MUST not include elements eligible for transformation. "
                      "%(countEligible)s fact(s) were eligible for transformation: %(elements)s"
                      ),
                    modelObject=eligibleForTransformHiddenFacts,
                    countEligible=len(eligibleForTransformHiddenFacts),
                    elements=", ".join(
                        sorted(
                            set(
                                str(f.qname)
                                for f in eligibleForTransformHiddenFacts))))
            for ixdsHtmlRootElt in modelXbrl.ixdsHtmlElements:
                for ixElt in ixdsHtmlRootElt.getroottree().iterfind(
                        "//{http://www.w3.org/1999/xhtml}*[@style]"):
                    hiddenFactRefMatch = styleIxHiddenPattern.match(
                        ixElt.get("style", ""))
                    if hiddenFactRefMatch:
                        hiddenFactRef = hiddenFactRefMatch.group(2)
                        if hiddenFactRef not in hiddenEltIds:
                            modelXbrl.error(
                                "ESEF.2.4.1.esefIxHiddenStyleNotLinkingFactInHiddenSection",
                                _("\"-esef-ix-hidden\" style identifies @id, %(id)s of a fact that is not in ix:hidden section."
                                  ),
                                modelObject=ixElt,
                                id=hiddenFactRef)
                        else:
                            presentedHiddenEltIds[hiddenFactRef].append(ixElt)
            for hiddenEltId, ixElt in hiddenEltIds.items():
                if (hiddenEltId not in presentedHiddenEltIds
                        and getattr(ixElt, "xValid", 0) >= VALID
                        and  # may not be validated
                    (ixElt.concept.baseXsdType in untransformableTypes
                     or ixElt.isNil)):
                    requiredToDisplayFacts.append(ixElt)
            if requiredToDisplayFacts:
                modelXbrl.warning(
                    "ESEF.2.4.1.factInHiddenSectionNotInReport",
                    _("The ix:hidden section contains %(countUnreferenced)s fact(s) whose @id is not applied on any \"-esef-ix- hidden\" style: %(elements)s"
                      ),
                    modelObject=requiredToDisplayFacts,
                    countUnreferenced=len(requiredToDisplayFacts),
                    elements=", ".join(
                        sorted(
                            set(str(f.qname)
                                for f in requiredToDisplayFacts))))
            del eligibleForTransformHiddenFacts, hiddenEltIds, presentedHiddenEltIds, requiredToDisplayFacts
        elif modelDocument.type == ModelDocument.Type.INSTANCE:
            for elt in modelDocument.xmlRootElement.iter():
                if elt.qname == XbrlConst.qnLinkFootnote:  # for now assume no private elements extend link:footnote
                    checkFootnote(elt, elt.stringValue)

        contextsWithDisallowedOCEs = []
        contextsWithDisallowedOCEcontent = []
        contextsWithPeriodTime = []
        contextsWithPeriodTimeZone = []
        contextIdentifiers = defaultdict(list)
        nonStandardTypedDimensions = defaultdict(set)
        for context in modelXbrl.contexts.values():
            for elt in context.iterdescendants(
                    "{http://www.xbrl.org/2003/instance}startDate",
                    "{http://www.xbrl.org/2003/instance}endDate",
                    "{http://www.xbrl.org/2003/instance}instant"):
                m = datetimePattern.match(elt.stringValue)
                if m:
                    if m.group(1):
                        contextsWithPeriodTime.append(context)
                    if m.group(3):
                        contextsWithPeriodTimeZone.append(context)
            for elt in context.iterdescendants(
                    "{http://www.xbrl.org/2003/instance}segment"):
                contextsWithDisallowedOCEs.append(context)
                break
            for elt in context.iterdescendants(
                    "{http://www.xbrl.org/2003/instance}scenario"):
                if isinstance(elt, ModelObject):
                    if any(True for child in elt.iterchildren()
                           if isinstance(child, ModelObject)
                           and child.tag not in (
                               "{http://xbrl.org/2006/xbrldi}explicitMember",
                               "{http://xbrl.org/2006/xbrldi}typedMember")):
                        contextsWithDisallowedOCEcontent.append(context)
            # check periods here
            contextIdentifiers[context.entityIdentifier].append(context)

        if contextsWithDisallowedOCEs:
            modelXbrl.error(
                "ESEF.2.1.3.segmentUsed",
                _("xbrli:segment container MUST NOT be used in contexts: %(contextIds)s"
                  ),
                modelObject=contextsWithDisallowedOCEs,
                contextIds=", ".join(c.id for c in contextsWithDisallowedOCEs))
        if contextsWithDisallowedOCEcontent:
            modelXbrl.error(
                "ESEF.2.1.3.scenarioContainsNonDimensionalContent",
                _("xbrli:scenario in contexts MUST NOT contain any other content than defined in XBRL Dimensions specification: %(contextIds)s"
                  ),
                modelObject=contextsWithDisallowedOCEcontent,
                contextIds=", ".join(
                    c.id for c in contextsWithDisallowedOCEcontent))
        if len(contextIdentifiers) > 1:
            modelXbrl.error(
                "ESEF.2.1.4.multipleIdentifiers",
                _("All entity identifiers in contexts MUST have identical content: %(contextIdentifiers)s"
                  ),
                modelObject=modelXbrl,
                contextIds=", ".join(i[1] for i in contextIdentifiers))
        for (contextScheme,
             contextIdentifier), contextElts in contextIdentifiers.items():
            if contextScheme != iso17442:
                modelXbrl.warning(
                    "ESEF.2.1.1.nonLEIContextScheme",
                    _("The scheme attribute of the xbrli:identifier element should have \"%(leiScheme)s\" as its content: %(contextScheme)s"
                      ),
                    modelObject=contextElts,
                    contextScheme=contextScheme,
                    leiScheme=iso17442)
            else:
                leiValidity = LeiUtil.checkLei(contextIdentifier)
                if leiValidity == LeiUtil.LEI_INVALID_LEXICAL:
                    modelXbrl.warning(
                        "ESEF.2.1.1.invalidIdentifierFormat",
                        _("The LEI context identifier has an invalid format: %(identifier)s"
                          ),
                        modelObject=contextElts,
                        identifier=contextIdentifier)
                elif leiValidity == LeiUtil.LEI_INVALID_CHECKSUM:
                    modelXbrl.warning(
                        "ESEF.2.1.1.invalidIdentifier",
                        _("The LEI context identifier has checksum error: %(identifier)s"
                          ),
                        modelObject=contextElts,
                        identifier=contextIdentifier)
        if contextsWithPeriodTime:
            modelXbrl.warning(
                "ESEF.2.1.2.periodWithTimeContent",
                _("Context period startDate, endDate and instant elements should be in whole days without time: %(contextIds)s"
                  ),
                modelObject=contextsWithPeriodTime,
                contextIds=", ".join(c.id for c in contextsWithPeriodTime))
        if contextsWithPeriodTimeZone:
            modelXbrl.warning(
                "ESEF.2.1.2.periodWithTimeZone",
                _("Context period startDate, endDate and instant elements should be in whole days without a timezone: %(contextIds)s"
                  ),
                modelObject=contextsWithPeriodTimeZone,
                contextIds=", ".join(c.id for c in contextsWithPeriodTimeZone))

        # identify unique contexts and units
        mapContext = {}
        mapUnit = {}
        uniqueContextHashes = {}
        for context in modelXbrl.contexts.values():
            h = context.contextDimAwareHash
            if h in uniqueContextHashes:
                if context.isEqualTo(uniqueContextHashes[h]):
                    mapContext[context] = uniqueContextHashes[h]
            else:
                uniqueContextHashes[h] = context
        del uniqueContextHashes
        uniqueUnitHashes = {}
        utrValidator = ValidateUtr(modelXbrl)
        utrUnitIds = set(
            u.unitId
            for unitItemType in utrValidator.utrItemTypeEntries.values()
            for u in unitItemType.values())
        for unit in modelXbrl.units.values():
            h = unit.hash
            if h in uniqueUnitHashes:
                if unit.isEqualTo(uniqueUnitHashes[h]):
                    mapUnit[unit] = uniqueUnitHashes[h]
            else:
                uniqueUnitHashes[h] = unit
            # check if any custom measure is in UTR
            for measureTerm in unit.measures:
                for measure in measureTerm:
                    ns = measure.namespaceURI
                    if ns != XbrlConst.iso4217 and not ns.startswith(
                            "http://www.xbrl.org/"):
                        if measure.localName in utrUnitIds:
                            modelXbrl.error(
                                "ESEF.RTS.III.1.G1-7-1.customUnitInUtr",
                                _("Custom measure SHOULD NOT duplicate a UnitID of UTR: %(measure)s"
                                  ),
                                modelObject=unit,
                                measure=measure)
        del uniqueUnitHashes

        reportedMandatory = set()
        precisionFacts = set()
        numFactsByConceptContextUnit = defaultdict(list)
        textFactsByConceptContext = defaultdict(list)
        footnotesRelationshipSet = modelXbrl.relationshipSet(
            XbrlConst.factFootnote, XbrlConst.defaultLinkRole)
        noLangFacts = []
        textFactsMissingReportLang = []
        conceptsUsed = set()

        for qn, facts in modelXbrl.factsByQname.items():
            if qn in mandatory:
                reportedMandatory.add(qn)
            for f in facts:
                if f.precision is not None:
                    precisionFacts.add(f)
                if f.isNumeric:
                    numFactsByConceptContextUnit[(f.qname,
                                                  mapContext.get(
                                                      f.context, f.context),
                                                  mapUnit.get(
                                                      f.unit,
                                                      f.unit))].append(f)
                    if f.concept is not None and not f.isNil and f.xValid >= VALID and f.xValue > 1 and f.concept.type is not None and (
                            f.concept.type.qname == PERCENT_TYPE
                            or f.concept.type.isDerivedFrom(PERCENT_TYPE)):
                        modelXbrl.warning(
                            "ESEF.2.2.2.percentGreaterThan100",
                            _("A percent fact should have value <= 100: %(element)s in context %(context)s value %(value)s"
                              ),
                            modelObject=f,
                            element=f.qname,
                            context=f.context.id,
                            value=f.xValue)
                elif f.concept is not None and f.concept.type is not None:
                    if f.concept.type.isOimTextFactType:
                        if not f.xmlLang:
                            noLangFacts.append(f)
                        elif f.context is not None:
                            textFactsByConceptContext[(
                                f.qname, mapContext.get(f.context,
                                                        f.context))].append(f)
                conceptsUsed.add(f.concept)
                if f.context is not None:
                    for dim in f.context.qnameDims.values():
                        conceptsUsed.add(dim.dimension)
                        if dim.isExplicit:
                            conceptsUsed.add(dim.member)
                        elif dim.isTyped:
                            conceptsUsed.add(dim.typedMember)

        if noLangFacts:
            modelXbrl.error(
                "ESEF.2.5.2.undefinedLanguageForTextFact",
                _("Each tagged text fact MUST have the 'xml:lang' attribute assigned or inherited."
                  ),
                modelObject=noLangFacts)

        # missing report lang text facts
        if reportXmlLang:
            for fList in textFactsByConceptContext.values():
                if not any(f.xmlLang == reportXmlLang for f in fList):
                    modelXbrl.error(
                        "ESEF.2.5.2.taggedTextFactOnlyInLanguagesOtherThanLanguageOfAReport",
                        _("Each tagged text fact MUST have the 'xml:lang' provided in at least the language of the report: %(element)s"
                          ),
                        modelObject=fList,
                        element=fList[0].qname)

        # 2.2.4 test
        for fList in numFactsByConceptContextUnit.values():
            if len(fList) > 1:
                f0 = fList[0]
                if any(f.isNil for f in fList):
                    _inConsistent = not all(f.isNil for f in fList)
                elif all(
                        inferredDecimals(f) == inferredDecimals(f0)
                        for f in fList[1:]):  # same decimals
                    v0 = rangeValue(f0.value)
                    _inConsistent = not all(
                        rangeValue(f.value) == v0 for f in fList[1:])
                else:  # not all have same decimals
                    aMax, bMin = rangeValue(f0.value, inferredDecimals(f0))
                    for f in fList[1:]:
                        a, b = rangeValue(f.value, inferredDecimals(f))
                        if a > aMax: aMax = a
                        if b < bMin: bMin = b
                    _inConsistent = (bMin < aMax)
                if _inConsistent:
                    modelXbrl.error(
                        ("ESEF.2.2.4.inconsistentDuplicateNumericFactInInlineXbrlDocument"
                         ),
                        "Inconsistent duplicate numeric facts MUST NOT appear in the content of an inline XBRL document. %(fact)s that was used more than once in contexts equivalent to %(contextID)s: values %(values)s.  ",
                        modelObject=fList,
                        fact=f0.qname,
                        contextID=f0.contextID,
                        values=", ".join(
                            strTruncate(f.value, 128) for f in fList))

        if precisionFacts:
            modelXbrl.warning(
                "ESEF.2.2.1.precisionAttributeUsed",
                _("The accuracy of numeric facts SHOULD be defined with the 'decimals' attribute rather than the 'precision' attribute: %(elements)s."
                  ),
                modelObject=precisionFacts,
                elements=", ".join(sorted(
                    str(e.qname) for e in precisionFacts)))

        missingElements = (mandatory - reportedMandatory)
        if missingElements:
            modelXbrl.error(
                "ESEF.???.missingRequiredElements",
                _("Required elements missing from document: %(elements)s."),
                modelObject=modelXbrl,
                elements=", ".join(sorted(str(qn) for qn in missingElements)))

        if transformRegistryErrors:
            modelXbrl.warning(
                "ESEF.2.2.3.transformRegistry",
                _("ESMA recommends applying the latest available version of the Transformation Rules Registry marked with 'Recommendation' status for these elements: %(elements)s."
                  ),
                modelObject=transformRegistryErrors,
                elements=", ".join(
                    sorted(
                        str(fact.qname) for fact in transformRegistryErrors)))

        if orphanedFootnotes:
            modelXbrl.error(
                "ESEF.2.3.1.unusedFootnote",
                _("Non-empty footnotes must be connected to fact(s)."),
                modelObject=orphanedFootnotes)

        if noLangFootnotes:
            modelXbrl.error(
                "ESEF.2.3.1.undefinedLanguageForFootnote",
                _("Each footnote MUST have the 'xml:lang' attribute whose value corresponds to the language of the text in the content of the respective footnote."
                  ),
                modelObject=noLangFootnotes)
        nonDefLangFtFacts = set(f for f, langs in factLangFootnotes.items()
                                if reportXmlLang not in langs)
        if nonDefLangFtFacts:
            modelXbrl.error(
                "ESEF.2.3.1.footnoteOnlyInLanguagesOtherThanLanguageOfAReport",
                _("Each fact MUST have at least one footnote with 'xml:lang' attribute whose value corresponds to the language of the text in the content of the respective footnote: %(qnames)s."
                  ),
                modelObject=nonDefLangFtFacts,
                qnames=", ".join(
                    sorted(str(f.qname) for f in nonDefLangFtFacts)))
        del nonDefLangFtFacts
        if footnoteRoleErrors:
            modelXbrl.error(
                "ESEF.2.3.1.nonStandardRoleForFootnote",
                _("The xlink:role attribute of a link:footnote and link:footnoteLink element as well as xlink:arcrole attribute of a link:footnoteArc MUST be defined in the XBRL Specification 2.1."
                  ),
                modelObject=footnoteRoleErrors)

        nonStdFootnoteElts = list()
        for modelLink in modelXbrl.baseSets[("XBRL-footnotes", None, None,
                                             None)]:
            for elt in modelLink.iterchildren():
                if isinstance(
                        elt, (_ElementTree, _Comment, _ProcessingInstruction)):
                    continue  # comment or other non-parsed element
                if elt.qname not in FOOTNOTE_LINK_CHILDREN:
                    nonStdFootnoteElts.append(elt)

        if nonStdFootnoteElts:
            modelXbrl.error(
                "ESEF.2.3.2.nonStandardElementInFootnote",
                _("A link:footnoteLink element MUST have no children other than link:loc, link:footnote, and link:footnoteArc."
                  ),
                modelObject=nonStdFootnoteElts)

        for qn in modelXbrl.qnameDimensionDefaults.values():
            conceptsUsed.add(modelXbrl.qnameConcepts.get(qn))

        # unused elements in linkbases
        for arcroles, err in (
            ((parentChild, ),
             "elementsNotUsedForTaggingAppliedInPresentationLinkbase"),
            ((summationItem, ),
             "elementsNotUsedForTaggingAppliedInCalculationLinkbase"),
            ((dimensionDomain, domainMember),
             "elementsNotUsedForTaggingAppliedInDefinitionLinkbase")):
            unreportedLbElts = set()
            for arcrole in arcroles:
                for rel in modelXbrl.relationshipSet(
                        arcrole).modelRelationships:
                    fr = rel.fromModelObject
                    to = rel.toModelObject
                    if arcrole in (parentChild, summationItem):
                        if fr is not None and not fr.isAbstract and fr not in conceptsUsed and isExtension(
                                val, rel):
                            unreportedLbElts.add(fr)
                        if to is not None and not to.isAbstract and to not in conceptsUsed and isExtension(
                                val, rel):
                            unreportedLbElts.add(to)
                    elif arcrole == dimensionDomain:  # dimension, always abstract
                        if fr is not None and fr not in conceptsUsed and isExtension(
                                val, rel):
                            unreportedLbElts.add(fr)
                        if to is not None and rel.isUsable and to not in conceptsUsed and isExtension(
                                val, rel):
                            unreportedLbElts.add(to)
                    elif arcrole == domainMember:
                        if to is not None and not fr.isAbstract and rel.isUsable and to not in conceptsUsed and isExtension(
                                val, rel):
                            unreportedLbElts.add(to)
            if unreportedLbElts:
                modelXbrl.error(
                    "ESEF.3.4.6." + err,
                    _("All usable concepts in extension taxonomy relationships MUST be applied by tagged facts: %(elements)s."
                      ),
                    modelObject=unreportedLbElts,
                    elements=", ".join(
                        sorted((str(c.qname) for c in unreportedLbElts))))

        # 3.4.4 check for presentation preferred labels
        missingConceptLabels = defaultdict(set)  # by role
        pfsConceptsRootInPreLB = set()

        def checkLabels(parent, relSet, labelrole, visited):
            if not parent.label(
                    labelrole, lang=reportXmlLang, fallbackToQname=False):
                if parent.name != "NotesAccountingPoliciesAndMandatoryTags":  # TEMPORARY TBD remove
                    missingConceptLabels[labelrole].add(parent)
            visited.add(parent)
            conceptRels = defaultdict(
                list)  # counts for concepts without preferred label role
            for rel in relSet.fromModelObject(parent):
                child = rel.toModelObject
                if child is not None:
                    labelrole = rel.preferredLabel
                    if not labelrole:
                        conceptRels[child].append(rel)
                    if child not in visited:
                        checkLabels(child, relSet, labelrole, visited)
            for concept, rels in conceptRels.items():
                if len(rels) > 1:
                    modelXbrl.warning(
                        "ESEF.3.4.4.missingPreferredLabelRole",
                        _("Preferred label role SHOULD be used when concept is duplicated in same presentation tree location: %(qname)s."
                          ),
                        modelObject=rels + [concept],
                        qname=concept.qname)
            visited.remove(parent)

        for ELR in modelXbrl.relationshipSet(parentChild).linkRoleUris:
            relSet = modelXbrl.relationshipSet(parentChild, ELR)
            for rootConcept in relSet.rootConcepts:
                checkLabels(rootConcept, relSet, None, set())
                # check for PFS element which isn't an orphan
                if rootConcept.qname in esefPrimaryStatementPlaceholders and relSet.fromModelObject(
                        rootConcept):
                    pfsConceptsRootInPreLB.add(rootConcept)
        for labelrole, concepts in missingConceptLabels.items():
            modelXbrl.warning(
                "ESEF.3.4.5.missingLabelForRoleInReportLanguage",
                _("Label for %(role)s role SHOULD be available in report language for concepts: %(qnames)s."
                  ),
                modelObject=concepts,
                qnames=", ".join(str(c.qname) for c in concepts),
                role=os.path.basename(labelrole) if labelrole else "standard")
        if not pfsConceptsRootInPreLB:
            # no PFS statements were recognized
            modelXbrl.error(
                "ESEF.RTS.Annex.II.Par.1.Par.7.missingPrimaryFinancialStatement",
                _("A primary financial statement placeholder element MUST be a root of a presentation linkbase tree."
                  ),
                modelObject=modelXbrl)
        # dereference
        del missingConceptLabels, pfsConceptsRootInPreLB

        # mandatory factc RTS Annex II
        missingMandatoryElements = esefMandatoryElements2020 - modelXbrl.factsByQname.keys(
        )
        if missingMandatoryElements:
            modelXbrl.error(
                "ESEF.RTS.Annex.II.Par.2.missingMandatoryMarkups",
                _("Mandatory elements to be marked up are missing: %(qnames)s."
                  ),
                modelObject=missingMandatoryElements,
                qnames=", ".join(
                    sorted(str(qn) for qn in missingMandatoryElements)))

        # duplicated core taxonomy elements
        for name, concepts in modelXbrl.nameConcepts.items():
            if len(concepts) > 1:
                i = None  # ifrs Concept
                for c in concepts:
                    if c.qname.namespaceURI == _ifrsNs:
                        i = c
                        break
                if i is not None:
                    for c in concepts:
                        if c != i and c.balance == i.balance and c.periodType == i.periodType:
                            modelXbrl.error(
                                "ESEF.RTS.Annex.IV.Par.4.2.extensionElementDuplicatesCoreElement",
                                _("Extension elements must not duplicate the existing elements from the core taxonomy and be identifiable %(qname)s."
                                  ),
                                modelObject=(c, i),
                                qname=c.qname)

    modelXbrl.profileActivity(_statusMsg, minTimeToShow=0.0)
    modelXbrl.modelManager.showStatus(None)
Esempio n. 8
0
def validateHtmlContent(modelXbrl, referenceElt, htmlEltTree, validatedObjectLabel, messageCodePrefix, isInline=False):
    checkedGraphicsFiles = set() # only check any graphics file reference once per footnote
    _xhtmlNs = "{{{}}}".format(xhtml)
    _xhtmlNsLen = len(_xhtmlNs)
    _tableTags = ("table", _xhtmlNs + "table")
    _anchorAncestorTags = set(_xhtmlNs + tag for tag in ("html", "body", "div"))
    allowedExternalHrefPattern = modelXbrl.modelManager.disclosureSystem.allowedExternalHrefPattern
    for elt in htmlEltTree.iter():
        if isinstance(elt, ModelObject) and elt.namespaceURI == xhtml:
            eltTag = elt.localName
        elif isinstance(elt, (_ElementTree, _Comment, _ProcessingInstruction)):
            continue # comment or other non-parsed element
        else:
            eltTag = elt.tag
            if eltTag.startswith(_xhtmlNs):
                eltTag = eltTag[_xhtmlNsLen:]
        if isInline:
            if eltTag in efmBlockedInlineHtmlElements:
                modelXbrl.error("EFM.5.02.05.disallowedElement",
                    _("%(validatedObjectLabel)s has disallowed element <%(element)s>"),
                    modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                    element=eltTag)
            if eltTag == "a" and "href" not in elt.keys() and any(a.tag not in _anchorAncestorTags for a in elt.iterancestors()):
                modelXbrl.warning("EFM.5.02.05.anchorElementPosition",
                    _("If element <a> does not have attribute @href, it should not have any ancestors other than html, body, or div.  Disallowed ancestors: %(disallowedAncestors)s"),
                    modelObject=elt, disallowedAncestors=", ".join(a.tag.rpartition('}')[2] for a in elt.iterancestors() if a.tag not in _anchorAncestorTags))      
        for attrTag, attrValue in elt.items():
            if isInline:
                if attrTag in efmBlockedInlineHtmlElementAttributes.get(eltTag,()):
                    modelXbrl.error("EFM.5.02.05.disallowedAttribute",
                        _("%(validatedObjectLabel)s has disallowed attribute on element <%(element)s>: %(attribute)s=\"%(value)s\""),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        element=eltTag, attribute=attrTag, value=attrValue)
                elif attrTag == "{http://www.w3.org/XML/1998/namespace}base":
                    modelXbrl.error("EFM.5.02.05.xmlBaseDisallowed",
                        _("%(validatedObjectLabel)s has disallowed attribute on element <%(element)s>: xml:base=\"%(value)s\""),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        element=eltTag, value=attrValue)
                elif attrTag == "{http://www.w3.org/2001/XMLSchema-instance}schemaLocation":
                    modelXbrl.warning("EFM.5.02.05.schemaLocationDisallowed",
                        _("%(validatedObjectLabel)s has disallowed attribute on element <%(element)s>: xsi:schemaLocation=\"%(value)s\""),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        element=eltTag, value=attrValue)
            if ((attrTag == "href" and eltTag == "a") or 
                (attrTag == "src" and eltTag == "img")):
                if "javascript:" in attrValue:
                    modelXbrl.error(messageCodePrefix + "activeContent",
                        _("%(validatedObjectLabel)s has javascript in '%(attribute)s' for <%(element)s>"),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        attribute=attrTag, element=eltTag,
                        messageCodes=("EFM.6.05.34.activeContent", "EFM.5.02.05.activeContent"))
                elif eltTag == "a" and (not allowedExternalHrefPattern or allowedExternalHrefPattern.match(attrValue)):
                    pass
                elif scheme(attrValue) in ("http", "https", "ftp"):
                    modelXbrl.error(messageCodePrefix + "externalReference",
                        _("%(validatedObjectLabel)s has an invalid external reference in '%(attribute)s' for <%(element)s>: %(value)s"),
                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                        attribute=attrTag, element=eltTag, value=attrValue,
                        messageCodes=("EFM.6.05.34.externalReference", "EFM.5.02.05.externalReference"))
                if attrTag == "src" and attrValue not in checkedGraphicsFiles:
                    if scheme(attrValue) == "data":
                        modelXbrl.error(messageCodePrefix + "graphicDataUrl",
                            _("%(validatedObjectLabel)s references a graphics data URL which isn't accepted '%(attribute)s' for <%(element)s>"),
                            modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                            attribute=attrValue[:32], element=eltTag)
                    elif attrValue.lower()[-4:] not in ('.jpg', '.gif'):
                        modelXbrl.error(messageCodePrefix + "graphicFileType",
                            _("%(validatedObjectLabel)s references a graphics file which isn't .gif or .jpg '%(attribute)s' for <%(element)s>"),
                            modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                            attribute=attrValue, element=eltTag,
                            messageCodes=("EFM.6.05.34.graphicFileType", "EFM.5.02.05.graphicFileType"))
                    else:   # test file contents
                        try:
                            if validateGraphicFile(referenceElt, attrValue) != attrValue.lower()[-3:]:
                                modelXbrl.error(messageCodePrefix +"graphicFileContent",
                                    _("%(validatedObjectLabel)s references a graphics file which doesn't have expected content '%(attribute)s' for <%(element)s>"),
                                    modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                                    attribute=attrValue, element=eltTag,
                                    messageCodes=("EFM.6.05.34.graphicFileContent", "EFM.5.02.05.graphicFileContent"))
                        except IOError as err:
                            modelXbrl.error(messageCodePrefix + "graphicFileError",
                                _("%(validatedObjectLabel)s references a graphics file which isn't openable '%(attribute)s' for <%(element)s>, error: %(error)s"),
                                modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                                attribute=attrValue, element=eltTag, error=err,
                                messageCodes=("EFM.6.05.34.graphicFileError", "EFM.5.02.05.graphicFileError"))
                    checkedGraphicsFiles.add(attrValue)
            if eltTag == "meta" and attrTag == "content" and not attrValue.startswith("text/html"):
                modelXbrl.error(messageCodePrefix + "disallowedMetaContent",
                    _("%(validatedObjectLabel)s <meta> content is \"%(metaContent)s\" but must be \"text/html\""),
                    modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                    metaContent=attrValue,
                    messageCodes=("EFM.6.05.34.disallowedMetaContent", "EFM.5.02.05.disallowedMetaContent"))
        if eltTag == "table" and any(a.tag in _tableTags
                                     for a in elt.iterancestors()):
            modelXbrl.error(messageCodePrefix + "nestedTable",
                _("%(validatedObjectLabel)s has nested <table> elements."),
                modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                messageCodes=("EFM.6.05.34.nestedTable", "EFM.5.02.05.nestedTable"))
Esempio n. 9
0
def validateTextBlockFacts(modelXbrl):
    #handler = TextBlockHandler(modelXbrl)
    loadDTD(modelXbrl)
    checkedGraphicsFiles = set() #  only check any graphics file reference once per fact
    allowedExternalHrefPattern = modelXbrl.modelManager.disclosureSystem.allowedExternalHrefPattern
    
    if isInlineDTD:
        htmlBodyTemplate = "<body><div>\n{0}\n</div></body>\n"
    else:
        htmlBodyTemplate = "<body>\n{0}\n</body>\n"
    _xhtmlNs = "{{{}}}".format(xhtml)
    _xhtmlNsLen = len(_xhtmlNs)
    
    for f1 in modelXbrl.facts:
        # build keys table for 6.5.14
        concept = f1.concept
        if f1.xsiNil != "true" and \
           concept is not None and \
           concept.isTextBlock and \
           XMLpattern.match(f1.value):
            #handler.fact = f1
            # test encoded entity tags
            for match in namedEntityPattern.finditer(f1.value):
                entity = match.group()
                if not entity in xhtmlEntities:
                    modelXbrl.error(("EFM.6.05.16", "GFM.1.2.15"),
                        _("Fact %(fact)s contextID %(contextID)s has disallowed entity %(entity)s"),
                        modelObject=f1, fact=f1.qname, contextID=f1.contextID, entity=entity, error=entity)
            # test html
            for xmltext in [f1.value] + CDATApattern.findall(f1.value):
                '''
                try:
                    xml.sax.parseString(
                        "<?xml version='1.0' encoding='utf-8' ?>\n<body>\n{0}\n</body>\n".format(
                         removeEntities(xmltext)).encode('utf-8'),handler,handler)
                except (xml.sax.SAXParseException,
                        xml.sax.SAXException,
                        UnicodeDecodeError) as err:
                    # ignore errors which are not errors (e.g., entity codes checked previously
                    if not err.endswith("undefined entity"):
                        handler.modelXbrl.error(("EFM.6.05.15", "GFM.1.02.14"),
                            _("Fact %(fact)s contextID %(contextID)s has text which causes the XML error %(error)s"),
                            modelObject=f1, fact=f1.qname, contextID=f1.contextID, error=err)
                '''
                xmlBodyWithoutEntities = htmlBodyTemplate.format(removeEntities(xmltext))
                try:
                    textblockXml = XML(xmlBodyWithoutEntities)
                    if not edbodyDTD.validate( textblockXml ):
                        errors = edbodyDTD.error_log.filter_from_errors()
                        htmlError = any(e.type_name in ("DTD_INVALID_CHILD", "DTD_UNKNOWN_ATTRIBUTE") 
                                        for e in errors)
                        modelXbrl.error("EFM.6.05.16" if htmlError else ("EFM.6.05.15.dtdError", "GFM.1.02.14"),
                            _("Fact %(fact)s contextID %(contextID)s has text which causes the XML error %(error)s"),
                            modelObject=f1, fact=f1.qname, contextID=f1.contextID, 
                            error=', '.join(e.message for e in errors),
                            messageCodes=("EFM.6.05.16", "EFM.6.05.15.dtdError", "GFM.1.02.14"))
                    for elt in textblockXml.iter():
                        eltTag = elt.tag
                        if isinstance(elt, ModelObject) and elt.namespaceURI == xhtml:
                            eltTag = elt.localName
                        elif isinstance(elt, (_ElementTree, _Comment, _ProcessingInstruction)):
                            continue # comment or other non-parsed element
                        else:
                            eltTag = elt.tag
                            if eltTag.startswith(_xhtmlNs):
                                eltTag = eltTag[_xhtmlNsLen:]
                        if isInlineDTD and eltTag in efmBlockedInlineHtmlElements:
                            modelXbrl.error("EFM.5.02.05.disallowedElement",
                                _("%(validatedObjectLabel)s has disallowed element <%(element)s>"),
                                modelObject=elt, validatedObjectLabel=f1.qname,
                                element=eltTag)
                        for attrTag, attrValue in elt.items():
                            if isInlineDTD:
                                if attrTag in efmBlockedInlineHtmlElementAttributes.get(eltTag,()):
                                    modelXbrl.error("EFM.5.02.05.disallowedAttribute",
                                        _("%(validatedObjectLabel)s has disallowed attribute on element <%(element)s>: %(attribute)s=\"%(value)s\""),
                                        modelObject=elt, validatedObjectLabel=validatedObjectLabel,
                                        element=eltTag, attribute=attrTag, value=attrValue)
                            if ((attrTag == "href" and eltTag == "a") or 
                                (attrTag == "src" and eltTag == "img")):
                                if "javascript:" in attrValue:
                                    modelXbrl.error("EFM.6.05.16.activeContent",
                                        _("Fact %(fact)s of context %(contextID)s has javascript in '%(attribute)s' for <%(element)s>"),
                                        modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                        attribute=attrTag, element=eltTag)
                                elif eltTag == "a" and (not allowedExternalHrefPattern or allowedExternalHrefPattern.match(attrValue)):
                                    pass
                                elif scheme(attrValue) in ("http", "https", "ftp"):
                                    modelXbrl.error("EFM.6.05.16.externalReference",
                                        _("Fact %(fact)s of context %(contextID)s has an invalid external reference in '%(attribute)s' for <%(element)s>"),
                                        modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                        attribute=attrTag, element=eltTag)
                                if attrTag == "src" and attrValue not in checkedGraphicsFiles:
                                    if scheme(attrValue)  == "data":
                                        modelXbrl.error("EFM.6.05.16.graphicDataUrl",
                                            _("Fact %(fact)s of context %(contextID)s references a graphics data URL which isn't accepted '%(attribute)s' for <%(element)s>"),
                                            modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                            attribute=attrValue[:32], element=eltTag)
                                    elif attrValue.lower()[-4:] not in ('.jpg', '.gif'):
                                        modelXbrl.error("EFM.6.05.16.graphicFileType",
                                            _("Fact %(fact)s of context %(contextID)s references a graphics file which isn't .gif or .jpg '%(attribute)s' for <%(element)s>"),
                                            modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                            attribute=attrValue, element=eltTag)
                                    else:   # test file contents
                                        try:
                                            if validateGraphicFile(f1, attrValue) != attrValue.lower()[-3:]:
                                                modelXbrl.error("EFM.6.05.16.graphicFileContent",
                                                    _("Fact %(fact)s of context %(contextID)s references a graphics file which doesn't have expected content '%(attribute)s' for <%(element)s>"),
                                                    modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                                    attribute=attrValue, element=eltTag)
                                        except IOError as err:
                                            modelXbrl.error("EFM.6.05.16.graphicFileError",
                                                _("Fact %(fact)s of context %(contextID)s references a graphics file which isn't openable '%(attribute)s' for <%(element)s>, error: %(error)s"),
                                                modelObject=f1, fact=f1.qname, contextID=f1.contextID,
                                                attribute=attrValue, element=eltTag, error=err)
                                    checkedGraphicsFiles.add(attrValue)
                        if eltTag == "table" and any(a is not None for a in elt.iterancestors("table")):
                            modelXbrl.error("EFM.6.05.16.nestedTable",
                                _("Fact %(fact)s of context %(contextID)s has nested <table> elements."),
                                modelObject=f1, fact=f1.qname, contextID=f1.contextID)
                except (XMLSyntaxError,
                        UnicodeDecodeError) as err:
                    #if not err.endswith("undefined entity"):
                    modelXbrl.error(("EFM.6.05.15", "GFM.1.02.14"),
                        _("Fact %(fact)s contextID %(contextID)s has text which causes the XML error %(error)s"),
                        modelObject=f1, fact=f1.qname, contextID=f1.contextID, error=err)
                    
                checkedGraphicsFiles.clear()