public XmlAttributeDescriptor getAttributeDescriptor(String attributeName, final XmlTag context) {
    String caseSensitiveAttributeName =
        !myCaseSensitive ? attributeName.toLowerCase() : attributeName;
    XmlAttributeDescriptor descriptor =
        super.getAttributeDescriptor(caseSensitiveAttributeName, context);
    if (descriptor == null)
      descriptor =
          RelaxedHtmlFromSchemaElementDescriptor.getAttributeDescriptorFromFacelets(
              attributeName, context);

    if (descriptor == null) {
      String prefix = XmlUtil.findPrefixByQualifiedName(attributeName);

      if ("xml"
          .equals(
              prefix)) { // todo this is not technically correct dtd document references namespaces
                         // but we should handle it at least for xml stuff
        XmlNSDescriptor nsdescriptor = context.getNSDescriptor(XmlUtil.XML_NAMESPACE_URI, true);
        if (nsdescriptor instanceof XmlNSDescriptorImpl) {
          descriptor =
              ((XmlNSDescriptorImpl) nsdescriptor)
                  .getAttribute(
                      XmlUtil.findLocalNameByQualifiedName(caseSensitiveAttributeName),
                      XmlUtil.XML_NAMESPACE_URI,
                      context);
        }
      }
    }
    if (descriptor == null && HtmlUtil.isHtml5Context(context)) {
      descriptor = myDelegate.getAttributeDescriptor(attributeName, context);
    }
    return descriptor;
  }
  @Override
  public void visitXmlAttributeValue(XmlAttributeValue value) {
    final PsiElement parent = value.getParent();
    if (!(parent instanceof XmlAttribute)) {
      checkReferences(value);
      return;
    }

    XmlAttribute attribute = (XmlAttribute) parent;

    XmlTag tag = attribute.getParent();

    XmlElementDescriptor elementDescriptor = tag.getDescriptor();
    XmlAttributeDescriptor attributeDescriptor =
        elementDescriptor != null ? elementDescriptor.getAttributeDescriptor(attribute) : null;

    if (attributeDescriptor != null && !skipValidation(value)) {
      String error = attributeDescriptor.validateValue(value, attribute.getValue());

      if (error != null) {
        addToResults(HighlightInfo.createHighlightInfo(getTagProblemInfoType(tag), value, error));
        return;
      }
    }

    checkReferences(value);
  }
  public XmlAttributeDescriptor getAttributeDescriptor(String attributeName, final XmlTag context) {
    final XmlAttributeDescriptor descriptor =
        myDelegate.getAttributeDescriptor(attributeName.toLowerCase(), context);
    if (descriptor != null) return descriptor;

    return RelaxedHtmlFromSchemaElementDescriptor.getAttributeDescriptorFromFacelets(
        attributeName, context);
  }
  protected void checkAttribute(
      @NotNull final XmlAttribute attribute,
      @NotNull final ProblemsHolder holder,
      final boolean isOnTheFly) {
    final XmlTag tag = attribute.getParent();

    if (tag instanceof HtmlTag) {
      XmlElementDescriptor elementDescriptor = tag.getDescriptor();
      if (elementDescriptor == null || elementDescriptor instanceof AnyXmlElementDescriptor) {
        return;
      }

      XmlAttributeDescriptor attributeDescriptor =
          elementDescriptor.getAttributeDescriptor(attribute);

      final String name = attribute.getName();

      if (attributeDescriptor == null && !attribute.isNamespaceDeclaration()) {
        if (!XmlUtil.attributeFromTemplateFramework(name, tag)
            && (!isCustomValuesEnabled() || !isCustomValue(name))) {
          final ASTNode node = attribute.getNode();
          assert node != null;
          final PsiElement nameElement =
              XmlChildRole.ATTRIBUTE_NAME_FINDER.findChild(node).getPsi();

          boolean maySwitchToHtml5 =
              HtmlUtil.isCustomHtml5Attribute(name) && !HtmlUtil.hasNonHtml5Doctype(tag);
          LocalQuickFix[] quickfixes = new LocalQuickFix[maySwitchToHtml5 ? 3 : 2];
          quickfixes[0] =
              new AddCustomTagOrAttributeIntentionAction(
                  getShortName(), name, XmlEntitiesInspection.UNKNOWN_ATTRIBUTE);
          quickfixes[1] = new RemoveAttributeIntentionAction(name);
          if (maySwitchToHtml5) {
            quickfixes[2] = new SwitchToHtml5WithHighPriorityAction();
          }

          holder.registerProblem(
              nameElement,
              XmlErrorMessages.message("attribute.is.not.allowed.here", name),
              ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
              quickfixes);
        }
      }
    }
  }
  private void checkAttribute(XmlAttribute attribute) {
    XmlTag tag = attribute.getParent();

    final String name = attribute.getName();
    PsiElement prevLeaf = PsiTreeUtil.prevLeaf(attribute);

    if (!(prevLeaf instanceof PsiWhiteSpace)) {
      TextRange textRange = attribute.getTextRange();
      addToResults(
          HighlightInfo.createHighlightInfo(
              tag instanceof HtmlTag ? HighlightInfoType.WARNING : HighlightInfoType.ERROR,
              textRange.getStartOffset(),
              textRange.getStartOffset(),
              XmlErrorMessages.message("attribute.should.be.preceded.with.space")));
    }

    if (attribute.isNamespaceDeclaration()) {
      checkReferences(attribute.getValueElement());
      return;
    }
    final String namespace = attribute.getNamespace();

    if (XmlUtil.XML_SCHEMA_INSTANCE_URI.equals(namespace)) {
      checkReferences(attribute.getValueElement());
      return;
    }

    XmlElementDescriptor elementDescriptor = tag.getDescriptor();
    if (elementDescriptor == null
        || elementDescriptor instanceof AnyXmlElementDescriptor
        || ourDoJaxpTesting) {
      return;
    }

    XmlAttributeDescriptor attributeDescriptor =
        elementDescriptor.getAttributeDescriptor(attribute);

    if (attributeDescriptor == null) {
      if (!XmlUtil.attributeFromTemplateFramework(name, tag)) {
        final String localizedMessage =
            XmlErrorMessages.message("attribute.is.not.allowed.here", name);
        final HighlightInfo highlightInfo =
            reportAttributeProblem(tag, name, attribute, localizedMessage);
        if (highlightInfo != null) {
          final XmlFile xmlFile = (XmlFile) tag.getContainingFile();
          if (xmlFile != null) {
            XmlExtension.getExtension(xmlFile).createAddAttributeFix(attribute, highlightInfo);
          }
        }
      }
    } else {
      checkDuplicateAttribute(tag, attribute);

      if (tag instanceof HtmlTag
          && attribute.getValueElement() == null
          && !HtmlUtil.isSingleHtmlAttribute(name)) {
        final String localizedMessage =
            XmlErrorMessages.message("empty.attribute.is.not.allowed", name);
        reportAttributeProblem(tag, name, attribute, localizedMessage);
      }

      // we skip resolve of attribute references since there is separate check when taking attribute
      // descriptors
      PsiReference[] attrRefs = attribute.getReferences();
      doCheckRefs(attribute, attrRefs, attribute.getNamespacePrefix().length() > 0 ? 2 : 1);
    }
  }