@Nullable
  protected XmlElementDescriptor computeElementDescriptor() {
    for (XmlElementDescriptorProvider provider :
        Extensions.getExtensions(XmlElementDescriptorProvider.EP_NAME)) {
      XmlElementDescriptor elementDescriptor = provider.getDescriptor(this);
      if (elementDescriptor != null) {
        return elementDescriptor;
      }
    }

    final String namespace = getNamespace();
    if (XmlUtil.EMPTY_URI.equals(namespace)) { // nonqualified items
      final XmlTag parent = getParentTag();
      if (parent != null) {
        final XmlElementDescriptor descriptor = parent.getDescriptor();
        if (descriptor != null) {
          XmlElementDescriptor fromParent = descriptor.getElementDescriptor(this, parent);
          if (fromParent != null && !(fromParent instanceof AnyXmlElementDescriptor)) {
            return fromParent;
          }
        }
      }
    }

    XmlElementDescriptor elementDescriptor = null;
    final XmlNSDescriptor nsDescriptor = getNSDescriptor(namespace, false);

    LOG.debug(
        "Descriptor for namespace "
            + namespace
            + " is "
            + (nsDescriptor != null ? nsDescriptor.getClass().getCanonicalName() : "NULL"));

    if (nsDescriptor != null) {
      if (!DumbService.getInstance(getProject()).isDumb()
          || DumbService.isDumbAware(nsDescriptor)) {
        elementDescriptor = nsDescriptor.getElementDescriptor(this);
      }
    }
    if (elementDescriptor == null) {
      return XmlUtil.findXmlDescriptorByType(this);
    }

    return elementDescriptor;
  }
  @Nullable
  private XmlNSDescriptor getNsDescriptorFormDocType(
      final XmlDoctype doctype, final XmlFile containingFile, final boolean forHtml) {
    XmlNSDescriptor descriptor = getNSDescriptorFromMetaData(doctype.getMarkupDecl(), true);

    final String filePath = getFilePathForLogging(containingFile);

    final String dtdUri = XmlUtil.getDtdUri(doctype);
    LOG.debug(
        "DTD url for doctype " + doctype.getText() + " in file " + filePath + " is " + dtdUri);

    if (dtdUri != null && !dtdUri.isEmpty()) {
      XmlFile xmlFile = XmlUtil.findNamespace(containingFile, dtdUri);
      if (xmlFile == null) {
        // try to auto-detect it
        xmlFile = XmlNamespaceIndex.guessDtd(dtdUri, containingFile);
      }
      final String schemaFilePath = getFilePathForLogging(xmlFile);

      LOG.debug("Schema file for " + filePath + " is " + schemaFilePath);

      XmlNSDescriptor descriptorFromDtd =
          getNSDescriptorFromMetaData(xmlFile == null ? null : xmlFile.getDocument(), forHtml);

      LOG.debug(
          "Descriptor from meta data for schema file "
              + schemaFilePath
              + " is "
              + (descriptorFromDtd != null
                  ? descriptorFromDtd.getClass().getCanonicalName()
                  : "NULL"));

      if (descriptor != null && descriptorFromDtd != null) {
        descriptor =
            new XmlNSDescriptorSequence(new XmlNSDescriptor[] {descriptor, descriptorFromDtd});
      } else if (descriptorFromDtd != null) {
        descriptor = descriptorFromDtd;
      }
    }
    return descriptor;
  }
  private XmlNSDescriptor getDefaultNSDescriptorInner(
      final String namespace, final boolean strict) {
    final XmlFile containingFile = XmlUtil.getContainingFile(this);
    if (containingFile == null) return null;
    final XmlProlog prolog = getProlog();
    final XmlDoctype doctype = prolog != null ? prolog.getDoctype() : null;
    boolean dtdUriFromDocTypeIsNamespace = false;

    if (XmlUtil.HTML_URI.equals(namespace)) {
      XmlNSDescriptor nsDescriptor =
          doctype != null ? getNsDescriptorFormDocType(doctype, containingFile, true) : null;
      if (doctype != null) {
        LOG.debug(
            "Descriptor from doctype "
                + doctype
                + " is "
                + (nsDescriptor != null ? nsDescriptor.getClass().getCanonicalName() : "NULL"));
      }

      if (nsDescriptor == null) {
        String htmlns =
            ExternalResourceManagerEx.getInstanceEx().getDefaultHtmlDoctype(getProject());
        if (htmlns.isEmpty()) {
          htmlns = Html5SchemaProvider.getHtml5SchemaLocation();
        }
        nsDescriptor = getDefaultNSDescriptor(htmlns, false);
      }
      return new HtmlNSDescriptorImpl(nsDescriptor);
    } else if (XmlUtil.XHTML_URI.equals(namespace)) {
      String xhtmlNamespace = XmlUtil.getDefaultXhtmlNamespace(getProject());
      if (xhtmlNamespace == null || xhtmlNamespace.isEmpty()) {
        xhtmlNamespace = Html5SchemaProvider.getXhtml5SchemaLocation();
      }
      return getDefaultNSDescriptor(xhtmlNamespace, false);
    } else if (namespace != null && namespace != XmlUtil.EMPTY_URI) {
      if (doctype == null || !namespace.equals(XmlUtil.getDtdUri(doctype))) {
        boolean documentIsSchemaThatDefinesNs =
            namespace.equals(XmlUtil.getTargetSchemaNsFromTag(getRootTag()));

        final XmlFile xmlFile =
            documentIsSchemaThatDefinesNs
                ? containingFile
                : XmlUtil.findNamespace(containingFile, namespace);
        if (xmlFile != null) {
          final XmlDocument document = xmlFile.getDocument();
          if (document != null) {
            return (XmlNSDescriptor) document.getMetaData();
          }
        }
      } else {
        dtdUriFromDocTypeIsNamespace = true;
      }
    }

    if (strict && !dtdUriFromDocTypeIsNamespace) return null;

    if (doctype != null) {
      XmlNSDescriptor descr = getNsDescriptorFormDocType(doctype, containingFile, false);

      if (descr != null) {
        return XmlExtension.getExtension(containingFile)
            .getDescriptorFromDoctype(containingFile, descr);
      }
    }

    if (strict) return null;
    if (namespace == XmlUtil.EMPTY_URI) {
      final XmlFile xmlFile = XmlUtil.findNamespace(containingFile, namespace);
      if (xmlFile != null) {
        return (XmlNSDescriptor) xmlFile.getDocument().getMetaData();
      }
    }
    try {
      final PsiFile fileFromText =
          PsiFileFactory.getInstance(getProject())
              .createFileFromText(
                  containingFile.getName() + ".dtd",
                  DTDLanguage.INSTANCE,
                  XmlUtil.generateDocumentDTD(this, false),
                  false,
                  false);
      if (fileFromText instanceof XmlFile) {
        fileFromText.putUserData(AUTO_GENERATED, Boolean.TRUE);
        return (XmlNSDescriptor) ((XmlFile) fileFromText).getDocument().getMetaData();
      }
    } catch (ProcessCanceledException ex) {
      throw ex;
    } catch (RuntimeException ignored) {
    } // e.g. dtd isn't mapped to xml type

    return null;
  }