Search in sources :

Example 1 with VnuBadElementNameException

use of nu.validator.checker.VnuBadElementNameException in project validator by validator.

the class MessageEmitterAdapter method elaboration.

private void elaboration(Exception e) throws SAXException {
    if (!(e instanceof AbstractValidationException || e instanceof VnuBadAttrValueException || e instanceof VnuBadElementNameException || e instanceof DatatypeMismatchException)) {
        return;
    }
    if (e instanceof ImpossibleAttributeIgnoredException) {
        ImpossibleAttributeIgnoredException ex = (ImpossibleAttributeIgnoredException) e;
        Name elt = ex.getCurrentElement();
        elaborateElementSpecificAttributes(elt, ex.getAttributeName());
    } else if (e instanceof OnlyTextNotAllowedException) {
        OnlyTextNotAllowedException ex = (OnlyTextNotAllowedException) e;
        Name elt = ex.getCurrentElement();
        elaborateContentModel(elt);
    } else if (e instanceof OutOfContextElementException) {
        OutOfContextElementException ex = (OutOfContextElementException) e;
        Name parent = ex.getParent();
        Name child = ex.getCurrentElement();
        elaborateContentModelandContext(parent, child);
    } else if (e instanceof RequiredAttributesMissingException) {
        RequiredAttributesMissingException ex = (RequiredAttributesMissingException) e;
        Name elt = ex.getCurrentElement();
        elaborateElementSpecificAttributes(elt);
    } else if (e instanceof RequiredAttributesMissingOneOfException) {
        RequiredAttributesMissingOneOfException ex = (RequiredAttributesMissingOneOfException) e;
        Name elt = ex.getCurrentElement();
        elaborateElementSpecificAttributes(elt);
    } else if (e instanceof RequiredElementsMissingException) {
        RequiredElementsMissingException ex = (RequiredElementsMissingException) e;
        Name elt = ex.getParent();
        elaborateContentModel(elt);
    } else if (e instanceof RequiredElementsMissingOneOfException) {
        RequiredElementsMissingOneOfException ex = (RequiredElementsMissingOneOfException) e;
        Name elt = ex.getParent();
        elaborateContentModel(elt);
    } else if (e instanceof StringNotAllowedException) {
        StringNotAllowedException ex = (StringNotAllowedException) e;
        Name elt = ex.getCurrentElement();
        elaborateContentModel(elt);
    } else if (e instanceof TextNotAllowedException) {
        TextNotAllowedException ex = (TextNotAllowedException) e;
        Name elt = ex.getCurrentElement();
        elaborateContentModel(elt);
    } else if (e instanceof UnfinishedElementException) {
        UnfinishedElementException ex = (UnfinishedElementException) e;
        Name elt = ex.getCurrentElement();
        elaborateContentModel(elt);
    } else if (e instanceof UnfinishedElementOneOfException) {
        UnfinishedElementOneOfException ex = (UnfinishedElementOneOfException) e;
        Name elt = ex.getCurrentElement();
        elaborateContentModel(elt);
    } else if (e instanceof UnknownElementException) {
        UnknownElementException ex = (UnknownElementException) e;
        Name elt = ex.getParent();
        elaborateContentModel(elt);
    } else if (e instanceof BadAttributeValueException) {
        BadAttributeValueException ex = (BadAttributeValueException) e;
        Map<String, DatatypeException> map = ex.getExceptions();
        elaborateDatatypes(map);
    } else if (e instanceof VnuBadAttrValueException) {
        VnuBadAttrValueException ex = (VnuBadAttrValueException) e;
        Map<String, DatatypeException> map = ex.getExceptions();
        elaborateDatatypes(map);
    } else if (e instanceof VnuBadElementNameException) {
        VnuBadElementNameException ex = (VnuBadElementNameException) e;
        Map<String, DatatypeException> map = ex.getExceptions();
        elaborateDatatypes(map);
    } else if (e instanceof DatatypeMismatchException) {
        DatatypeMismatchException ex = (DatatypeMismatchException) e;
        Map<String, DatatypeException> map = ex.getExceptions();
        elaborateDatatypes(map);
    } else if (e instanceof StringNotAllowedException) {
        StringNotAllowedException ex = (StringNotAllowedException) e;
        Map<String, DatatypeException> map = ex.getExceptions();
        elaborateDatatypes(map);
    }
}
Also used : RequiredAttributesMissingException(com.thaiopensource.relaxng.exceptions.RequiredAttributesMissingException) RequiredAttributesMissingOneOfException(com.thaiopensource.relaxng.exceptions.RequiredAttributesMissingOneOfException) RequiredElementsMissingException(com.thaiopensource.relaxng.exceptions.RequiredElementsMissingException) RequiredElementsMissingOneOfException(com.thaiopensource.relaxng.exceptions.RequiredElementsMissingOneOfException) UnfinishedElementException(com.thaiopensource.relaxng.exceptions.UnfinishedElementException) OutOfContextElementException(com.thaiopensource.relaxng.exceptions.OutOfContextElementException) StringNotAllowedException(com.thaiopensource.relaxng.exceptions.StringNotAllowedException) UnfinishedElementOneOfException(com.thaiopensource.relaxng.exceptions.UnfinishedElementOneOfException) VnuBadElementNameException(nu.validator.checker.VnuBadElementNameException) DatatypeMismatchException(nu.validator.checker.DatatypeMismatchException) Name(com.thaiopensource.xml.util.Name) OnlyTextNotAllowedException(com.thaiopensource.relaxng.exceptions.OnlyTextNotAllowedException) Html5DatatypeException(nu.validator.datatype.Html5DatatypeException) DatatypeException(org.relaxng.datatype.DatatypeException) AbstractValidationException(com.thaiopensource.relaxng.exceptions.AbstractValidationException) ImpossibleAttributeIgnoredException(com.thaiopensource.relaxng.exceptions.ImpossibleAttributeIgnoredException) BadAttributeValueException(com.thaiopensource.relaxng.exceptions.BadAttributeValueException) VnuBadAttrValueException(nu.validator.checker.VnuBadAttrValueException) UnknownElementException(com.thaiopensource.relaxng.exceptions.UnknownElementException) OnlyTextNotAllowedException(com.thaiopensource.relaxng.exceptions.OnlyTextNotAllowedException) TextNotAllowedException(com.thaiopensource.relaxng.exceptions.TextNotAllowedException) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap)

Example 2 with VnuBadElementNameException

use of nu.validator.checker.VnuBadElementNameException in project validator by validator.

the class Assertions method startElement.

/**
 * @see nu.validator.checker.Checker#startElement(java.lang.String,
 *      java.lang.String, java.lang.String, org.xml.sax.Attributes)
 */
@Override
public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException {
    if ("http://www.w3.org/1999/xhtml" == uri && "template".equals(localName)) {
        numberOfTemplatesDeep++;
        if (numberOfTemplatesDeep != 1) {
            return;
        }
    } else if (numberOfTemplatesDeep > 0) {
        return;
    }
    Set<String> ids = new HashSet<>();
    String role = null;
    String inputTypeVal = null;
    String activeDescendant = null;
    String owns = null;
    String forAttr = null;
    boolean href = false;
    boolean activeDescendantWithAriaOwns = false;
    // see nu.validator.datatype.ImageCandidateStrings
    System.setProperty("nu.validator.checker.imageCandidateString.hasWidth", "0");
    StackNode parent = peek();
    int ancestorMask = 0;
    String parentRole = null;
    String parentName = null;
    if (parent != null) {
        ancestorMask = parent.getAncestorMask();
        parentName = parent.getName();
        parentRole = parent.getRole();
    }
    if ("http://www.w3.org/1999/xhtml" == uri) {
        boolean controls = false;
        boolean hidden = false;
        boolean toolbar = false;
        boolean usemap = false;
        boolean ismap = false;
        boolean selected = false;
        boolean itemid = false;
        boolean itemref = false;
        boolean itemscope = false;
        boolean itemtype = false;
        boolean tabindex = false;
        boolean languageJavaScript = false;
        boolean typeNotTextJavaScript = false;
        String xmlLang = null;
        String lang = null;
        String id = null;
        String list = null;
        int len = atts.getLength();
        for (int i = 0; i < len; i++) {
            String attUri = atts.getURI(i);
            if (attUri.length() == 0) {
                String attLocal = atts.getLocalName(i);
                if ("embed".equals(localName)) {
                    for (int j = 0; j < attLocal.length(); j++) {
                        char c = attLocal.charAt(j);
                        if (c >= 'A' && c <= 'Z') {
                            err("Bad attribute name \u201c" + attLocal + "\u201d. Attribute names for the" + " \u201cembed\u201d element must not" + " contain uppercase ASCII letters.");
                        }
                    }
                    if (!NCName.isNCName(attLocal)) {
                        err("Bad attribute name \u201c" + attLocal + "\u201d. Attribute names for the" + " \u201cembed\u201d element must be" + " XML-compatible.");
                    }
                }
                if ("style" == attLocal) {
                    String styleContents = atts.getValue(i);
                    ApplContext ac = new ApplContext("en");
                    ac.setCssVersionAndProfile("css3svg");
                    ac.setMedium("all");
                    ac.setTreatVendorExtensionsAsWarnings(true);
                    ac.setTreatCssHacksAsWarnings(true);
                    ac.setWarningLevel(-1);
                    ac.setFakeURL("file://localhost/StyleAttribute");
                    // 
                    StyleSheetParser styleSheetParser = new StyleSheetParser();
                    styleSheetParser.parseStyleAttribute(ac, new ByteArrayInputStream(styleContents.getBytes()), "", ac.getFakeURL(), getDocumentLocator().getLineNumber());
                    styleSheetParser.getStyleSheet().findConflicts(ac);
                    // 
                    Errors errors = styleSheetParser.getStyleSheet().getErrors();
                    if (errors.getErrorCount() > 0) {
                        incrementUseCounter("style-attribute-errors-found");
                    }
                    for (int j = 0; j < errors.getErrorCount(); j++) {
                        String message = "";
                        String cssProperty = "";
                        String cssMessage = "";
                        CssError error = errors.getErrorAt(j);
                        Throwable ex = error.getException();
                        if (ex instanceof CssParseException) {
                            CssParseException cpe = (CssParseException) ex;
                            if (// 
                            "generator.unrecognize".equals(cpe.getErrorType())) {
                                cssMessage = "Parse Error";
                            }
                            if (cpe.getProperty() != null) {
                                cssProperty = String.format("\u201c%s\u201D: ", cpe.getProperty());
                            }
                            if (cpe.getMessage() != null) {
                                cssMessage = cpe.getMessage();
                            }
                            if (!"".equals(cssMessage)) {
                                message = cssProperty + cssMessage + ".";
                            }
                        } else {
                            message = ex.getMessage();
                        }
                        if (!"".equals(message)) {
                            err("CSS: " + message);
                        }
                    }
                } else if ("tabindex" == attLocal) {
                    tabindex = true;
                } else if ("href" == attLocal) {
                    href = true;
                } else if ("controls" == attLocal) {
                    controls = true;
                } else if ("type" == attLocal && "param" != localName && "ol" != localName && "ul" != localName && "li" != localName) {
                    if ("input" == localName) {
                        inputTypeVal = atts.getValue(i).toLowerCase();
                    }
                    String attValue = atts.getValue(i);
                    if (AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("hidden", attValue)) {
                        hidden = true;
                    } else if (AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("toolbar", attValue)) {
                        toolbar = true;
                    }
                    if (!AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("text/javascript", attValue)) {
                        typeNotTextJavaScript = true;
                    }
                } else if ("role" == attLocal) {
                    role = atts.getValue(i);
                } else if ("aria-activedescendant" == attLocal) {
                    activeDescendant = atts.getValue(i);
                } else if ("aria-owns" == attLocal) {
                    owns = atts.getValue(i);
                } else if ("list" == attLocal) {
                    list = atts.getValue(i);
                } else if ("lang" == attLocal) {
                    lang = atts.getValue(i);
                } else if ("id" == attLocal) {
                    id = atts.getValue(i);
                } else if ("for" == attLocal && "label" == localName) {
                    forAttr = atts.getValue(i);
                    ancestorMask |= LABEL_FOR_MASK;
                } else if ("ismap" == attLocal) {
                    ismap = true;
                } else if ("selected" == attLocal) {
                    selected = true;
                } else if ("usemap" == attLocal && "input" != localName) {
                    usemap = true;
                } else if ("itemid" == attLocal) {
                    itemid = true;
                } else if ("itemref" == attLocal) {
                    itemref = true;
                } else if ("itemscope" == attLocal) {
                    itemscope = true;
                } else if ("itemtype" == attLocal) {
                    itemtype = true;
                } else if ("language" == attLocal && AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("javascript", atts.getValue(i))) {
                    languageJavaScript = true;
                } else if ("rev" == attLocal && !("1".equals(System.getProperty("nu.validator.schema.rdfa-full")))) {
                    errObsoleteAttribute("rev", localName, " Use the \u201Crel\u201D attribute instead," + " with a term having the opposite meaning.");
                } else if (OBSOLETE_ATTRIBUTES.containsKey(attLocal) && "ol" != localName && "ul" != localName && "li" != localName) {
                    String[] elementNames = OBSOLETE_ATTRIBUTES.get(attLocal);
                    Arrays.sort(elementNames);
                    if (Arrays.binarySearch(elementNames, localName) >= 0) {
                        String suggestion = OBSOLETE_ATTRIBUTES_MSG.containsKey(attLocal) ? " " + OBSOLETE_ATTRIBUTES_MSG.get(attLocal) : "";
                        errObsoleteAttribute(attLocal, localName, suggestion);
                    }
                } else if (OBSOLETE_STYLE_ATTRS.containsKey(attLocal)) {
                    String[] elementNames = OBSOLETE_STYLE_ATTRS.get(attLocal);
                    Arrays.sort(elementNames);
                    if (Arrays.binarySearch(elementNames, localName) >= 0) {
                        errObsoleteAttribute(attLocal, localName, " Use CSS instead.");
                    }
                } else if (INPUT_ATTRIBUTES.containsKey(attLocal) && "input" == localName) {
                    String[] allowedTypes = INPUT_ATTRIBUTES.get(attLocal);
                    Arrays.sort(allowedTypes);
                    inputTypeVal = inputTypeVal == null ? "text" : inputTypeVal;
                    if (Arrays.binarySearch(allowedTypes, inputTypeVal) < 0) {
                        err("Attribute \u201c" + attLocal + "\u201d is only allowed when the input" + " type is " + renderTypeList(allowedTypes) + ".");
                    }
                } else if ("autofocus" == attLocal) {
                    if (hasAutofocus) {
                        err("A document must not include more than one" + " \u201Cautofocus\u201D attribute.");
                    }
                    hasAutofocus = true;
                } else if (ATTRIBUTES_WITH_IMPLICIT_STATE_OR_PROPERTY.contains(attLocal)) {
                    String stateOrProperty = "aria-" + attLocal;
                    if (atts.getIndex("", stateOrProperty) > -1 && "true".equals(atts.getValue("", stateOrProperty))) {
                        warn("Attribute \u201C" + stateOrProperty + "\u201D is unnecessary for elements that" + " have attribute \u201C" + attLocal + "\u201D.");
                    }
                }
            } else if ("http://www.w3.org/XML/1998/namespace" == attUri) {
                if ("lang" == atts.getLocalName(i)) {
                    xmlLang = atts.getValue(i);
                }
            }
            if (atts.getType(i) == "ID" || "id" == atts.getLocalName(i)) {
                String attVal = atts.getValue(i);
                if (attVal.length() != 0) {
                    ids.add(attVal);
                }
            }
        }
        if (followW3Cspec) {
            if (("input".equals(localName) || "textarea".equals(localName)) && atts.getIndex("", "inputmode") > -1) {
                err("The \u201cinputmode\u201d attribute is not allowed by" + " the W3C HTML specification.");
            }
        }
        if ("input".equals(localName)) {
            if (atts.getIndex("", "name") > -1 && "isindex".equals(atts.getValue("", "name"))) {
                err("The value \u201cisindex\u201d for the \u201cname\u201d" + " attribute of the \u201cinput\u201d element is" + " not allowed.");
            }
            inputTypeVal = inputTypeVal == null ? "text" : inputTypeVal;
            if (atts.getIndex("", "autocomplete") > -1) {
                Class<?> datatypeClass = null;
                String autocompleteVal = atts.getValue("", "autocomplete");
                try {
                    if (!"on".equals(autocompleteVal) && !"off".equals(autocompleteVal)) {
                        if ("hidden".equals(inputTypeVal)) {
                            AutocompleteDetailsAny.THE_INSTANCE.checkValid(autocompleteVal);
                            datatypeClass = AutocompleteDetailsAny.class;
                        } else if ("text".equals(inputTypeVal) || "search".equals(autocompleteVal)) {
                            AutocompleteDetailsText.THE_INSTANCE.checkValid(autocompleteVal);
                            datatypeClass = AutocompleteDetailsText.class;
                        } else if ("password".equals(inputTypeVal)) {
                            AutocompleteDetailsPassword.THE_INSTANCE.checkValid(autocompleteVal);
                            datatypeClass = AutocompleteDetailsPassword.class;
                        } else if ("url".equals(inputTypeVal)) {
                            AutocompleteDetailsUrl.THE_INSTANCE.checkValid(autocompleteVal);
                            datatypeClass = AutocompleteDetailsUrl.class;
                        } else if ("email".equals(inputTypeVal)) {
                            AutocompleteDetailsEmail.THE_INSTANCE.checkValid(autocompleteVal);
                            datatypeClass = AutocompleteDetailsEmail.class;
                        } else if ("tel".equals(inputTypeVal)) {
                            AutocompleteDetailsTel.THE_INSTANCE.checkValid(autocompleteVal);
                            datatypeClass = AutocompleteDetailsTel.class;
                        } else if ("number".equals(inputTypeVal)) {
                            AutocompleteDetailsNumeric.THE_INSTANCE.checkValid(autocompleteVal);
                            datatypeClass = AutocompleteDetailsNumeric.class;
                        } else if ("month".equals(inputTypeVal)) {
                            AutocompleteDetailsMonth.THE_INSTANCE.checkValid(autocompleteVal);
                            datatypeClass = AutocompleteDetailsMonth.class;
                        } else if ("date".equals(inputTypeVal)) {
                            AutocompleteDetailsDate.THE_INSTANCE.checkValid(autocompleteVal);
                            datatypeClass = AutocompleteDetailsDate.class;
                        }
                    }
                } catch (DatatypeException e) {
                    try {
                        if (getErrorHandler() != null) {
                            String msg = e.getMessage();
                            msg = msg.substring(msg.indexOf(": ") + 2);
                            VnuBadAttrValueException ex = new VnuBadAttrValueException(localName, uri, "autocomplete", autocompleteVal, msg, getDocumentLocator(), datatypeClass, false);
                            getErrorHandler().error(ex);
                        }
                    } catch (ClassNotFoundException ce) {
                    }
                }
            }
        }
        if ("img".equals(localName) || "source".equals(localName)) {
            if (atts.getIndex("", "srcset") > -1) {
                String srcsetVal = atts.getValue("", "srcset");
                try {
                    if (atts.getIndex("", "sizes") > -1) {
                        ImageCandidateStringsWidthRequired.THE_INSTANCE.checkValid(srcsetVal);
                    } else {
                        ImageCandidateStrings.THE_INSTANCE.checkValid(srcsetVal);
                    }
                    // see nu.validator.datatype.ImageCandidateStrings
                    if ("1".equals(System.getProperty("nu.validator.checker.imageCandidateString.hasWidth"))) {
                        if (atts.getIndex("", "sizes") < 0) {
                            err("When the \u201csrcset\u201d attribute has" + " any image candidate string with a" + " width descriptor, the" + " \u201csizes\u201d attribute" + " must also be present.");
                        }
                    }
                } catch (DatatypeException e) {
                    Class<?> datatypeClass = ImageCandidateStrings.class;
                    if (atts.getIndex("", "sizes") > -1) {
                        datatypeClass = ImageCandidateStringsWidthRequired.class;
                    }
                    try {
                        if (getErrorHandler() != null) {
                            String msg = e.getMessage();
                            if (e instanceof Html5DatatypeException) {
                                Html5DatatypeException ex5 = (Html5DatatypeException) e;
                                if (!ex5.getDatatypeClass().equals(ImageCandidateURL.class)) {
                                    msg = msg.substring(msg.indexOf(": ") + 2);
                                }
                            }
                            VnuBadAttrValueException ex = new VnuBadAttrValueException(localName, uri, "srcset", srcsetVal, msg, getDocumentLocator(), datatypeClass, false);
                            getErrorHandler().error(ex);
                        }
                    } catch (ClassNotFoundException ce) {
                    }
                }
                if ("picture".equals(parentName) && !siblingSources.isEmpty()) {
                    for (Map.Entry<Locator, Map<String, String>> entry : siblingSources.entrySet()) {
                        Locator locator = entry.getKey();
                        Map<String, String> sourceAtts = entry.getValue();
                        String media = sourceAtts.get("media");
                        if (media == null && sourceAtts.get("type") == null) {
                            err("A \u201csource\u201d element that has a" + " following sibling" + " \u201csource\u201d element or" + " \u201cimg\u201d element with a" + " \u201csrcset\u201d attribute" + " must have a" + " \u201cmedia\u201d attribute and/or" + " \u201ctype\u201d attribute.", locator);
                            siblingSources.remove(locator);
                        } else if (media != null && AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("all", trimSpaces(media))) {
                            err("Value of \u201cmedia\u201d attribute here" + " must not be \u201call\u201d.", locator);
                        }
                    }
                }
            } else if (atts.getIndex("", "sizes") > -1) {
                err("The \u201csizes\u201d attribute may be specified" + " only if the \u201csrcset\u201d attribute is" + " also present.");
            }
        }
        if ("picture".equals(parentName) && "source".equals(localName)) {
            Map<String, String> sourceAtts = new HashMap<>();
            for (int i = 0; i < atts.getLength(); i++) {
                sourceAtts.put(atts.getLocalName(i), atts.getValue(i));
            }
            siblingSources.put((new LocatorImpl(getDocumentLocator())), sourceAtts);
        }
        if ("figure" == localName) {
            currentFigurePtr = currentPtr + 1;
        }
        if ((ancestorMask & FIGURE_MASK) != 0) {
            if ("img" == localName) {
                if (stack[currentFigurePtr].hasImg()) {
                    stack[currentFigurePtr].setEmbeddedContentFound();
                } else {
                    stack[currentFigurePtr].setImgFound();
                }
            } else if ("audio" == localName || "canvas" == localName || "embed" == localName || "iframe" == localName || "math" == localName || "object" == localName || "svg" == localName || "video" == localName) {
                stack[currentFigurePtr].setEmbeddedContentFound();
            }
        }
        if ("article" == localName || "aside" == localName || "nav" == localName || "section" == localName) {
            currentSectioningElementPtr = currentPtr + 1;
            currentSectioningDepth++;
        }
        if ("h1" == localName || "h2" == localName || "h3" == localName || "h4" == localName || "h5" == localName || "h6" == localName) {
            currentHeadingPtr = currentPtr + 1;
            if (currentSectioningElementPtr > -1) {
                stack[currentSectioningElementPtr].setHeadingFound();
            }
        }
        if (((ancestorMask & H1_MASK) != 0 || (ancestorMask & H2_MASK) != 0 || (ancestorMask & H3_MASK) != 0 || (ancestorMask & H4_MASK) != 0 || (ancestorMask & H5_MASK) != 0 || (ancestorMask & H6_MASK) != 0) && "img" == localName && atts.getIndex("", "alt") > -1 && !"".equals(atts.getValue("", "alt"))) {
            stack[currentHeadingPtr].setImgFound();
        }
        if ("option" == localName && !parent.hasOption()) {
            if (atts.getIndex("", "value") < 0) {
                parent.setNoValueOptionFound();
            } else if (atts.getIndex("", "value") > -1 && "".equals(atts.getValue("", "value"))) {
                parent.setEmptyValueOptionFound();
            } else {
                parent.setNonEmptyOption((new LocatorImpl(getDocumentLocator())));
            }
        }
        // Obsolete elements
        if (OBSOLETE_ELEMENTS.get(localName) != null) {
            err("The \u201C" + localName + "\u201D element is obsolete. " + OBSOLETE_ELEMENTS.get(localName));
        }
        // Exclusions
        Integer maskAsObject;
        int mask = 0;
        String descendantUiString = "The element \u201C" + localName + "\u201D";
        if ((maskAsObject = ANCESTOR_MASK_BY_DESCENDANT.get(localName)) != null) {
            mask = maskAsObject.intValue();
        } else if ("video" == localName && controls) {
            mask = A_BUTTON_MASK;
            descendantUiString = "The element \u201Cvideo\u201D with the" + " attribute \u201Ccontrols\u201D";
            checkForInteractiveAncestorRole(descendantUiString);
        } else if ("audio" == localName && controls) {
            mask = A_BUTTON_MASK;
            descendantUiString = "The element \u201Caudio\u201D with the" + " attribute \u201Ccontrols\u201D";
            checkForInteractiveAncestorRole(descendantUiString);
        } else if ("menu" == localName && toolbar) {
            mask = A_BUTTON_MASK;
            descendantUiString = "The element \u201Cmenu\u201D with the" + " attribute \u201Ctype=toolbar\u201D";
            checkForInteractiveAncestorRole(descendantUiString);
        } else if ("img" == localName && usemap) {
            mask = A_BUTTON_MASK;
            descendantUiString = "The element \u201Cimg\u201D with the" + " attribute \u201Cusemap\u201D";
            checkForInteractiveAncestorRole(descendantUiString);
        } else if ("object" == localName && usemap) {
            mask = A_BUTTON_MASK;
            descendantUiString = "The element \u201Cobject\u201D with the" + " attribute \u201Cusemap\u201D";
            checkForInteractiveAncestorRole(descendantUiString);
        } else if ("input" == localName && !hidden) {
            mask = A_BUTTON_MASK;
            checkForInteractiveAncestorRole(descendantUiString);
        } else if (tabindex) {
            mask = A_BUTTON_MASK;
            descendantUiString = "An element with the attribute" + " \u201Ctabindex\u201D";
            checkForInteractiveAncestorRole(descendantUiString);
        } else if (role != null && role != "" && Arrays.binarySearch(INTERACTIVE_ROLES, role) >= 0) {
            mask = A_BUTTON_MASK;
            descendantUiString = "An element with the attribute \u201C" + "role=" + role + "\u201D";
            checkForInteractiveAncestorRole(descendantUiString);
        }
        if (mask != 0) {
            int maskHit = ancestorMask & mask;
            if (maskHit != 0) {
                for (String ancestor : SPECIAL_ANCESTORS) {
                    if ((maskHit & 1) != 0) {
                        err(descendantUiString + " must not appear as a" + " descendant of the \u201C" + ancestor + "\u201D element.");
                    }
                    maskHit >>= 1;
                }
            }
        }
        if (Arrays.binarySearch(INTERACTIVE_ELEMENTS, localName) >= 0) {
            checkForInteractiveAncestorRole("The element \u201C" + localName + "\u201D");
        }
        // Ancestor requirements/restrictions
        if ("area" == localName && ((ancestorMask & MAP_MASK) == 0)) {
            err("The \u201Carea\u201D element must have a \u201Cmap\u201D ancestor.");
        } else if ("img" == localName) {
            String titleVal = atts.getValue("", "title");
            if (ismap && ((ancestorMask & HREF_MASK) == 0)) {
                err("The \u201Cimg\u201D element with the " + "\u201Cismap\u201D attribute set must have an " + "\u201Ca\u201D ancestor with the " + "\u201Chref\u201D attribute.");
            }
            if (atts.getIndex("", "alt") < 0) {
                if (followW3Cspec || (titleVal == null || "".equals(titleVal))) {
                    if ((ancestorMask & FIGURE_MASK) == 0) {
                        err("An \u201Cimg\u201D element must have an" + " \u201Calt\u201D attribute, except under" + " certain conditions. For details, consult" + " guidance on providing text alternatives" + " for images.");
                    } else {
                        stack[currentFigurePtr].setFigcaptionNeeded();
                        stack[currentFigurePtr].addImageLackingAlt(new LocatorImpl(getDocumentLocator()));
                    }
                }
            } else {
                if ("".equals(atts.getValue("", "alt")) && role != null) {
                    List<String> roles = Arrays.asList(// 
                    role.trim().toLowerCase().split("\\s+"));
                    if (!roles.contains("none") && !roles.contains("presentation")) {
                        err("An \u201Cimg\u201D element which has an" + " \u201Calt\u201D attribute whose value" + " is the empty string must not have a" + " \u201Crole\u201D attribute with any" + " value other than \u201Cnone\u201D or" + " \u201Cpresentation\u201D");
                    }
                }
            }
        } else if ("table" == localName) {
            if (atts.getIndex("", "summary") >= 0) {
                errObsoleteAttribute("summary", "table", " Consider describing the structure of the" + " \u201Ctable\u201D in a \u201Ccaption\u201D " + " element or in a \u201Cfigure\u201D element " + " containing the \u201Ctable\u201D; or," + " simplify the structure of the" + " \u201Ctable\u201D so that no description" + " is needed.");
            }
            if (atts.getIndex("", "border") > -1) {
                if (followW3Cspec) {
                    if (atts.getIndex("", "border") > -1 && (!("".equals(atts.getValue("", "border")) || "1".equals(atts.getValue("", "border"))))) {
                        errObsoleteAttribute("border", "table", " Use CSS instead.");
                    } else {
                        warnPresentationalAttribute("border", "table", " For example: \u201Ctable, td, th { border: 1px solid gray }\u201D");
                    }
                } else {
                    errObsoleteAttribute("border", "table", " Use CSS instead.");
                }
            }
        } else if ("track" == localName && atts.getIndex("", "default") >= 0) {
            for (Map.Entry<StackNode, TaintableLocatorImpl> entry : openMediaElements.entrySet()) {
                StackNode node = entry.getKey();
                TaintableLocatorImpl locator = entry.getValue();
                if (node.isTrackDescendant()) {
                    err("The \u201Cdefault\u201D attribute must not occur" + " on more than one \u201Ctrack\u201D element" + " within the same \u201Caudio\u201D or" + " \u201Cvideo\u201D element.");
                    if (!locator.isTainted()) {
                        warn("\u201Caudio\u201D or \u201Cvideo\u201D element" + " has more than one \u201Ctrack\u201D child" + " element with a \u201Cdefault\u201D attribute.", locator);
                        locator.markTainted();
                    }
                } else {
                    node.setTrackDescendants();
                }
            }
        } else if ("main" == localName) {
            for (int i = 0; i < currentPtr; i++) {
                String ancestorName = stack[currentPtr - i].getName();
                if (Arrays.binarySearch(PROHIBITED_MAIN_ANCESTORS, ancestorName) >= 0) {
                    err("The \u201Cmain\u201D element must not appear as a" + " descendant of the \u201C" + ancestorName + "\u201D element.");
                }
            }
            if (atts.getIndex("", "hidden") < 0) {
                if (hasVisibleMain) {
                    err("A document must not include more than one visible" + " \u201Cmain\u201D element.");
                }
                hasVisibleMain = true;
            }
        } else if ("h1" == localName) {
            if (currentSectioningDepth > 1) {
                warn(h1WarningMessage);
            } else if (currentSectioningDepth == 1) {
                secondLevelH1s.add(new LocatorImpl(getDocumentLocator()));
            } else {
                hasTopLevelH1 = true;
            }
        } else // progress
        if ("progress" == localName) {
            double value = getDoubleAttribute(atts, "value");
            if (!Double.isNaN(value)) {
                double max = getDoubleAttribute(atts, "max");
                if (Double.isNaN(max)) {
                    if (!(value <= 1.0)) {
                        err("The value of the  \u201Cvalue\u201D attribute must be less than or equal to one when the \u201Cmax\u201D attribute is absent.");
                    }
                } else {
                    if (!(value <= max)) {
                        err("The value of the  \u201Cvalue\u201D attribute must be less than or equal to the value of the \u201Cmax\u201D attribute.");
                    }
                }
            }
        } else // meter
        if ("meter" == localName) {
            double value = getDoubleAttribute(atts, "value");
            double min = getDoubleAttribute(atts, "min");
            double max = getDoubleAttribute(atts, "max");
            double optimum = getDoubleAttribute(atts, "optimum");
            double low = getDoubleAttribute(atts, "low");
            double high = getDoubleAttribute(atts, "high");
            if (!Double.isNaN(min) && !Double.isNaN(value) && !(min <= value)) {
                err("The value of the \u201Cmin\u201D attribute must be less than or equal to the value of the \u201Cvalue\u201D attribute.");
            }
            if (Double.isNaN(min) && !Double.isNaN(value) && !(0 <= value)) {
                err("The value of the \u201Cvalue\u201D attribute must be greater than or equal to zero when the \u201Cmin\u201D attribute is absent.");
            }
            if (!Double.isNaN(value) && !Double.isNaN(max) && !(value <= max)) {
                err("The value of the \u201Cvalue\u201D attribute must be less than or equal to the value of the \u201Cmax\u201D attribute.");
            }
            if (!Double.isNaN(value) && Double.isNaN(max) && !(value <= 1)) {
                err("The value of the \u201Cvalue\u201D attribute must be less than or equal to one when the \u201Cmax\u201D attribute is absent.");
            }
            if (!Double.isNaN(min) && !Double.isNaN(max) && !(min <= max)) {
                err("The value of the \u201Cmin\u201D attribute must be less than or equal to the value of the \u201Cmax\u201D attribute.");
            }
            if (Double.isNaN(min) && !Double.isNaN(max) && !(0 <= max)) {
                err("The value of the \u201Cmax\u201D attribute must be greater than or equal to zero when the \u201Cmin\u201D attribute is absent.");
            }
            if (!Double.isNaN(min) && Double.isNaN(max) && !(min <= 1)) {
                err("The value of the \u201Cmin\u201D attribute must be less than or equal to one when the \u201Cmax\u201D attribute is absent.");
            }
            if (!Double.isNaN(min) && !Double.isNaN(low) && !(min <= low)) {
                err("The value of the \u201Cmin\u201D attribute must be less than or equal to the value of the \u201Clow\u201D attribute.");
            }
            if (Double.isNaN(min) && !Double.isNaN(low) && !(0 <= low)) {
                err("The value of the \u201Clow\u201D attribute must be greater than or equal to zero when the \u201Cmin\u201D attribute is absent.");
            }
            if (!Double.isNaN(min) && !Double.isNaN(high) && !(min <= high)) {
                err("The value of the \u201Cmin\u201D attribute must be less than or equal to the value of the \u201Chigh\u201D attribute.");
            }
            if (Double.isNaN(min) && !Double.isNaN(high) && !(0 <= high)) {
                err("The value of the \u201Chigh\u201D attribute must be greater than or equal to zero when the \u201Cmin\u201D attribute is absent.");
            }
            if (!Double.isNaN(low) && !Double.isNaN(high) && !(low <= high)) {
                err("The value of the \u201Clow\u201D attribute must be less than or equal to the value of the \u201Chigh\u201D attribute.");
            }
            if (!Double.isNaN(high) && !Double.isNaN(max) && !(high <= max)) {
                err("The value of the \u201Chigh\u201D attribute must be less than or equal to the value of the \u201Cmax\u201D attribute.");
            }
            if (!Double.isNaN(high) && Double.isNaN(max) && !(high <= 1)) {
                err("The value of the \u201Chigh\u201D attribute must be less than or equal to one when the \u201Cmax\u201D attribute is absent.");
            }
            if (!Double.isNaN(low) && !Double.isNaN(max) && !(low <= max)) {
                err("The value of the \u201Clow\u201D attribute must be less than or equal to the value of the \u201Cmax\u201D attribute.");
            }
            if (!Double.isNaN(low) && Double.isNaN(max) && !(low <= 1)) {
                err("The value of the \u201Clow\u201D attribute must be less than or equal to one when the \u201Cmax\u201D attribute is absent.");
            }
            if (!Double.isNaN(min) && !Double.isNaN(optimum) && !(min <= optimum)) {
                err("The value of the \u201Cmin\u201D attribute must be less than or equal to the value of the \u201Coptimum\u201D attribute.");
            }
            if (Double.isNaN(min) && !Double.isNaN(optimum) && !(0 <= optimum)) {
                err("The value of the \u201Coptimum\u201D attribute must be greater than or equal to zero when the \u201Cmin\u201D attribute is absent.");
            }
            if (!Double.isNaN(optimum) && !Double.isNaN(max) && !(optimum <= max)) {
                err("The value of the \u201Coptimum\u201D attribute must be less than or equal to the value of the \u201Cmax\u201D attribute.");
            }
            if (!Double.isNaN(optimum) && Double.isNaN(max) && !(optimum <= 1)) {
                err("The value of the \u201Coptimum\u201D attribute must be less than or equal to one when the \u201Cmax\u201D attribute is absent.");
            }
        } else // map required attrs
        if ("map" == localName && id != null) {
            String nameVal = atts.getValue("", "name");
            if (nameVal != null && !nameVal.equals(id)) {
                err("The \u201Cid\u201D attribute on a \u201Cmap\u201D element must have an the same value as the \u201Cname\u201D attribute.");
            }
        } else if ("object" == localName) {
            if (atts.getIndex("", "typemustmatch") >= 0) {
                if ((atts.getIndex("", "data") < 0) || (atts.getIndex("", "type") < 0)) {
                    {
                        err("Element \u201Cobject\u201D must not have" + " attribute \u201Ctypemustmatch\u201D unless" + " both attribute \u201Cdata\u201D" + " and attribute \u201Ctype\u201D are also specified.");
                    }
                }
            }
        } else // script
        if ("script" == localName) {
            // script language
            if (languageJavaScript && typeNotTextJavaScript) {
                err("A \u201Cscript\u201D element with the \u201Clanguage=\"JavaScript\"\u201D attribute set must not have a \u201Ctype\u201D attribute whose value is not \u201Ctext/javascript\u201D.");
            }
            if (atts.getIndex("", "charset") >= 0) {
                warnObsoleteAttribute("charset", "script", "");
                if (!"utf-8".equals(atts.getValue("", "charset").toLowerCase())) {
                    err("The only allowed value for the \u201Ccharset\u201D" + " attribute for the \u201Cscript\u201D" + " element is \u201Cutf-8\u201D. (But the" + " attribute is not needed and should be" + " omitted altogether.)");
                }
            }
            // src-less script
            if (atts.getIndex("", "src") < 0) {
                if (atts.getIndex("", "charset") >= 0) {
                    err("Element \u201Cscript\u201D must not have attribute \u201Ccharset\u201D unless attribute \u201Csrc\u201D is also specified.");
                }
                if (atts.getIndex("", "defer") >= 0) {
                    err("Element \u201Cscript\u201D must not have attribute \u201Cdefer\u201D unless attribute \u201Csrc\u201D is also specified.");
                }
                if (atts.getIndex("", "async") >= 0) {
                    if (!(// 
                    atts.getIndex("", "type") > -1 && "module".equals(// 
                    atts.getValue("", "type").toLowerCase()))) {
                        err("Element \u201Cscript\u201D must not have" + " attribute \u201Casync\u201D unless" + " attribute \u201Csrc\u201D is also" + " specified or unless attribute" + " \u201Ctype\u201D is specified with" + " value \u201Cmodule\u201D.");
                    }
                }
                if (atts.getIndex("", "integrity") >= 0) {
                    err("Element \u201Cscript\u201D must not have attribute" + " \u201Cintegrity\u201D unless attribute" + " \u201Csrc\u201D is also specified.");
                }
            }
            if (atts.getIndex("", "type") > -1) {
                String scriptType = atts.getValue("", "type").toLowerCase();
                if (JAVASCRIPT_MIME_TYPES.contains(scriptType) || "".equals(scriptType)) {
                    warn("The \u201Ctype\u201D attribute is unnecessary for" + " JavaScript resources.");
                }
                if ("module".equals(scriptType)) {
                    if (atts.getIndex("", "integrity") > -1) {
                        err("A \u201Cscript\u201D element with an" + " \u201Cintegrity\u201D attribute must not have a" + " \u201Ctype\u201D attribute with the value" + " \u201Cmodule\u201D.");
                    }
                    if (atts.getIndex("", "defer") > -1) {
                        err("A \u201Cscript\u201D element with a" + " \u201Cdefer\u201D attribute must not have a" + " \u201Ctype\u201D attribute with the value" + " \u201Cmodule\u201D.");
                    }
                    if (atts.getIndex("", "nomodule") > -1) {
                        err("A \u201Cscript\u201D element with a" + " \u201Cnomodule\u201D attribute must not have a" + " \u201Ctype\u201D attribute with the value" + " \u201Cmodule\u201D.");
                    }
                }
            }
        } else if ("style" == localName) {
            if (atts.getIndex("", "type") > -1) {
                String styleType = atts.getValue("", "type").toLowerCase();
                if ("text/css".equals(styleType)) {
                    warn(" The \u201Ctype\u201D attribute for the" + " \u201Cstyle\u201D element is not needed and" + " should be omitted.");
                } else {
                    err(" The only allowed value for the \u201Ctype\u201D" + " attribute for the \u201Cstyle\u201D element" + " is \u201Ctext/css\u201D (with no" + " parameters). (But the attribute is not" + " needed and should be omitted altogether.)");
                }
            }
        } else // bdo required attrs
        if ("bdo" == localName && atts.getIndex("", "dir") < 0) {
            err("Element \u201Cbdo\u201D must have attribute \u201Cdir\u201D.");
        }
        // labelable elements
        if ("button" == localName || ("input" == localName && !AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("hidden", atts.getValue("", "type"))) || "meter" == localName || "output" == localName || "progress" == localName || "select" == localName || "textarea" == localName) {
            for (Map.Entry<StackNode, Locator> entry : openLabels.entrySet()) {
                StackNode node = entry.getKey();
                Locator locator = entry.getValue();
                if (node.isLabeledDescendants()) {
                    err("The \u201Clabel\u201D element may contain at most" + " one \u201Cbutton\u201D, \u201Cinput\u201D," + " \u201Cmeter\u201D, \u201Coutput\u201D," + " \u201Cprogress\u201D, \u201Cselect\u201D," + " or \u201Ctextarea\u201D descendant.");
                    warn("\u201Clabel\u201D element with multiple labelable" + " descendants.", locator);
                } else {
                    node.setLabeledDescendants();
                }
            }
            if ((ancestorMask & LABEL_FOR_MASK) != 0) {
                boolean hasMatchingFor = false;
                for (int i = 0; (stack[currentPtr - i].getAncestorMask() & LABEL_FOR_MASK) != 0; i++) {
                    String forVal = stack[currentPtr - i].getForAttr();
                    if (forVal != null && forVal.equals(id)) {
                        hasMatchingFor = true;
                        break;
                    }
                }
                if (id == null || !hasMatchingFor) {
                    err("Any \u201C" + localName + "\u201D descendant of a \u201Clabel\u201D" + " element with a \u201Cfor\u201D attribute" + " must have an ID value that matches that" + " \u201Cfor\u201D attribute.");
                }
            }
        }
        // lang and xml:lang for XHTML5
        if (lang != null && xmlLang != null && !equalsIgnoreAsciiCase(lang, xmlLang)) {
            err("When the attribute \u201Clang\u201D in no namespace and the attribute \u201Clang\u201D in the XML namespace are both present, they must have the same value.");
        }
        if (role != null && owns != null) {
            for (Set<String> value : REQUIRED_ROLE_ANCESTOR_BY_DESCENDANT.values()) {
                if (value.contains(role)) {
                    String[] ownedIds = AttributeUtil.split(owns);
                    for (String ownedId : ownedIds) {
                        Set<String> ownedIdsForThisRole = ariaOwnsIdsByRole.get(role);
                        if (ownedIdsForThisRole == null) {
                            ownedIdsForThisRole = new HashSet<>();
                        }
                        ownedIdsForThisRole.add(ownedId);
                        ariaOwnsIdsByRole.put(role, ownedIdsForThisRole);
                    }
                    break;
                }
            }
        }
        if ("datalist" == localName) {
            listIds.addAll(ids);
        }
        // label for
        if ("label" == localName) {
            String forVal = atts.getValue("", "for");
            if (forVal != null) {
                formControlReferences.add(new IdrefLocator(new LocatorImpl(getDocumentLocator()), forVal));
            }
        }
        if ("form" == localName) {
            formElementIds.addAll(ids);
        }
        if ((// 
        "button" == localName || // 
        "input" == localName && !hidden) || // 
        "meter" == localName || // 
        "output" == localName || // 
        "progress" == localName || // 
        "select" == localName || "textarea" == localName) {
            formControlIds.addAll(ids);
        }
        if ("button" == localName || "fieldset" == localName || ("input" == localName && !hidden) || "object" == localName || "output" == localName || "select" == localName || "textarea" == localName) {
            String formVal = atts.getValue("", "form");
            if (formVal != null) {
                formElementReferences.add(new IdrefLocator(new LocatorImpl(getDocumentLocator()), formVal));
            }
        }
        // input list
        if ("input" == localName && list != null) {
            listReferences.add(new IdrefLocator(new LocatorImpl(getDocumentLocator()), list));
        }
        // input@type=button
        if ("input" == localName && AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("button", atts.getValue("", "type"))) {
            if (atts.getValue("", "value") == null || "".equals(atts.getValue("", "value"))) {
                err("Element \u201Cinput\u201D with attribute \u201Ctype\u201D whose value is \u201Cbutton\u201D must have non-empty attribute \u201Cvalue\u201D.");
            }
        }
        // track
        if ("track" == localName) {
            if ("".equals(atts.getValue("", "label"))) {
                err("Attribute \u201Clabel\u201D for element \u201Ctrack\u201D must have non-empty value.");
            }
        }
        // multiple selected options
        if ("option" == localName && selected) {
            for (Map.Entry<StackNode, Locator> entry : openSingleSelects.entrySet()) {
                StackNode node = entry.getKey();
                if (node.isSelectedOptions()) {
                    err("The \u201Cselect\u201D element cannot have more than one selected \u201Coption\u201D descendant unless the \u201Cmultiple\u201D attribute is specified.");
                } else {
                    node.setSelectedOptions();
                }
            }
        }
        if ("meta" == localName) {
            if (AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("content-language", atts.getValue("", "http-equiv"))) {
                err("Using the \u201Cmeta\u201D element to specify the" + " document-wide default language is obsolete." + " Consider specifying the language on the root" + " element instead.");
            } else if (AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("x-ua-compatible", atts.getValue("", "http-equiv")) && !AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("ie=edge", atts.getValue("", "content"))) {
                err("A \u201Cmeta\u201D element with an" + " \u201Chttp-equiv\u201D attribute whose value is" + " \u201CX-UA-Compatible\u201D" + " must have a" + " \u201Ccontent\u201D attribute with the value" + " \u201CIE=edge\u201D.");
            }
            if (atts.getIndex("", "charset") > -1) {
                if (!"utf-8".equals(atts.getValue("", "charset").toLowerCase())) {
                    err("The only allowed value for the \u201Ccharset\u201D" + " attribute for the \u201Cmeta\u201D" + " element is \u201Cutf-8\u201D.");
                }
                if (hasMetaCharset) {
                    err("A document must not include more than one" + " \u201Cmeta\u201D element with a" + " \u201Ccharset\u201D attribute.");
                }
                if (hasContentTypePragma) {
                    err("A document must not include both a" + " \u201Cmeta\u201D element with an" + " \u201Chttp-equiv\u201D attribute" + " whose value is \u201Ccontent-type\u201D," + " and a \u201Cmeta\u201D element with a" + " \u201Ccharset\u201D attribute.");
                }
                hasMetaCharset = true;
            }
            if (atts.getIndex("", "name") > -1) {
                if ("description".equals(atts.getValue("", "name"))) {
                    if (hasMetaDescription) {
                        err("A document must not include more than one" + " \u201Cmeta\u201D element with its" + " \u201Cname\u201D attribute set to the" + " value \u201Cdescription\u201D.");
                    }
                    hasMetaDescription = true;
                }
                if ("viewport".equals(atts.getValue("", "name")) && atts.getIndex("", "content") > -1) {
                    String contentVal = atts.getValue("", "content").toLowerCase();
                    if (contentVal.contains("user-scalable=no") || contentVal.contains("maximum-scale=1.0")) {
                        warn("Consider avoiding viewport values that" + " prevent users from resizing documents.");
                    }
                }
                if ("theme-color".equals(atts.getValue("", "name")) && atts.getIndex("", "content") > -1) {
                    String contentVal = atts.getValue("", "content").toLowerCase();
                    try {
                        Color.THE_INSTANCE.checkValid(contentVal);
                    } catch (DatatypeException e) {
                        try {
                            if (getErrorHandler() != null) {
                                String msg = e.getMessage();
                                if (e instanceof Html5DatatypeException) {
                                    msg = msg.substring(msg.indexOf(": ") + 2);
                                }
                                // 
                                VnuBadAttrValueException ex = new VnuBadAttrValueException(localName, uri, "content", contentVal, msg, getDocumentLocator(), Color.class, false);
                                getErrorHandler().error(ex);
                            }
                        } catch (ClassNotFoundException ce) {
                        }
                    }
                }
            }
            if (atts.getIndex("", "http-equiv") > -1 && AttributeUtil.lowerCaseLiteralEqualsIgnoreAsciiCaseString("content-type", atts.getValue("", "http-equiv"))) {
                if (hasMetaCharset) {
                    err("A document must not include both a" + " \u201Cmeta\u201D element with an" + " \u201Chttp-equiv\u201D attribute" + " whose value is \u201Ccontent-type\u201D," + " and a \u201Cmeta\u201D element with a" + " \u201Ccharset\u201D attribute.");
                }
                if (hasContentTypePragma) {
                    err("A document must not include more than one" + " \u201Cmeta\u201D element with a" + " \u201Chttp-equiv\u201D attribute" + " whose value is \u201Ccontent-type\u201D.");
                }
                hasContentTypePragma = true;
            }
        }
        if ("link" == localName) {
            boolean hasRel = false;
            List<String> relList = new ArrayList<>();
            if (atts.getIndex("", "rel") > -1) {
                hasRel = true;
                // 
                Collections.addAll(// 
                relList, // 
                atts.getValue("", "rel").toLowerCase().split("\\s+"));
            }
            if (atts.getIndex("", "as") > -1 && ((relList != null && !relList.contains("preload") || !hasRel))) {
                err("A \u201Clink\u201D element with an" + " \u201Cas\u201D attribute must have a" + " \u201Crel\u201D attribute that contains the" + " value \u201Cpreload\u201D.");
            }
            if (atts.getIndex("", "integrity") > -1 && ((relList != null && !relList.contains("stylesheet") || !hasRel))) {
                err("A \u201Clink\u201D element with an" + " \u201Cintegrity\u201D attribute must have a" + " \u201Crel\u201D attribute that contains the" + " value \u201Cstylesheet\u201D.");
            }
            if (atts.getIndex("", "sizes") > -1 && ((relList != null && !relList.contains("icon") && !relList.contains("apple-touch-icon")) && !relList.contains("apple-touch-icon-precomposed") || !hasRel)) {
                err("A \u201Clink\u201D element with a" + " \u201Csizes\u201D attribute must have a" + " \u201Crel\u201D attribute that contains the" + " value \u201Cicon\u201D or the value" + " \u201Capple-touch-icon\u201D or the value" + " \u201Capple-touch-icon-precomposed\u201D.");
            }
            if (// 
            atts.getIndex("", "color") > -1 && (!hasRel || (relList != null && !relList.contains("mask-icon")))) {
                err("A \u201Clink\u201D element with a" + " \u201Ccolor\u201D attribute must have a" + " \u201Crel\u201D attribute that contains" + " the value \u201Cmask-icon\u201D.");
            }
            if (// 
            atts.getIndex("", "scope") > -1 && ((relList != null && !relList.contains("serviceworker")) || !hasRel)) {
                err("A \u201Clink\u201D element with a" + " \u201Cscope\u201D attribute must have a" + " \u201Crel\u201D attribute that contains the" + " value \u201Cserviceworker\u201D.");
            }
            if (// 
            atts.getIndex("", "updateviacache") > -1 && ((relList != null && !relList.contains("serviceworker")) || !hasRel)) {
                err("A \u201Clink\u201D element with an" + " \u201Cupdateviacache\u201D attribute must have a" + " \u201Crel\u201D attribute that contains the" + " value \u201Cserviceworker\u201D.");
            }
            if (// 
            atts.getIndex("", "workertype") > -1 && ((relList != null && !relList.contains("serviceworker")) || !hasRel)) {
                err("A \u201Clink\u201D element with a" + " \u201Cworkertype\u201D attribute must have a" + " \u201Crel\u201D attribute that contains the" + " value \u201Cserviceworker\u201D.");
            }
            if ((ancestorMask & BODY_MASK) != 0 && (relList != null && !(relList.contains("dns-prefetch") || relList.contains("pingback") || relList.contains("preconnect") || relList.contains("prefetch") || relList.contains("preload") || relList.contains("prerender") || relList.contains("stylesheet"))) && atts.getIndex("", "itemprop") < 0 && atts.getIndex("", "property") < 0) {
                err("A \u201Clink\u201D element must not appear" + " as a descendant of a \u201Cbody\u201D element" + " unless the \u201Clink\u201D element has an" + " \u201Citemprop\u201D attribute or has a" + " \u201Crel\u201D attribute whose value contains" + " \u201Cdns-prefetch\u201D," + " \u201Cpingback\u201D," + " \u201Cpreconnect\u201D," + " \u201Cprefetch\u201D," + " \u201Cpreload\u201D," + " \u201Cprerender\u201D, or" + " \u201Cstylesheet\u201D.");
            }
        }
        // microdata
        if (itemid && !(itemscope && itemtype)) {
            err("The \u201Citemid\u201D attribute must not be specified on elements that do not have both an \u201Citemscope\u201D attribute and an \u201Citemtype\u201D attribute specified.");
        }
        if (itemref && !itemscope) {
            err("The \u201Citemref\u201D attribute must not be specified on elements that do not have an \u201Citemscope\u201D attribute specified.");
        }
        if (itemtype && !itemscope) {
            err("The \u201Citemtype\u201D attribute must not be specified on elements that do not have an \u201Citemscope\u201D attribute specified.");
        }
        // having implicit ARIA semantics.
        if (ELEMENTS_WITH_IMPLICIT_ROLE.containsKey(localName) && ELEMENTS_WITH_IMPLICIT_ROLE.get(localName).equals(role)) {
            warn("The \u201C" + role + "\u201D role is unnecessary for" + " element" + " \u201C" + localName + "\u201D.");
        } else if (ELEMENTS_THAT_NEVER_NEED_ROLE.containsKey(localName) && ELEMENTS_THAT_NEVER_NEED_ROLE.get(localName).equals(role)) {
            warn("Element \u201C" + localName + "\u201D does not need a" + " \u201Crole\u201D attribute.");
        } else if ("input" == localName) {
            inputTypeVal = inputTypeVal == null ? "text" : inputTypeVal;
            if (INPUT_TYPES_WITH_IMPLICIT_ROLE.containsKey(inputTypeVal) && INPUT_TYPES_WITH_IMPLICIT_ROLE.get(inputTypeVal).equals(role)) {
                warnExplicitRoleUnnecessaryForType("input", role, inputTypeVal);
            } else if ("email".equals(inputTypeVal) || "search".equals(inputTypeVal) || "tel".equals(inputTypeVal) || "text".equals(inputTypeVal) || "url".equals(inputTypeVal)) {
                if (atts.getIndex("", "list") < 0) {
                    if ("textbox".equals(role)) {
                        warn("The \u201Ctextbox\u201D role is unnecessary" + " for an \u201Cinput\u201D element that" + " has no \u201Clist\u201D attribute and" + " whose type is" + " \u201C" + inputTypeVal + "\u201D.");
                    }
                } else {
                    if ("combobox".equals(role)) {
                        warn("The \u201Ccombobox\u201D role is unnecessary" + " for an \u201Cinput\u201D element that" + " has a \u201Clist\u201D attribute and" + " whose type is" + " \u201C" + inputTypeVal + "\u201D.");
                    }
                }
            }
        } else if (atts.getIndex("", "href") > -1 && "link".equals(role) && ("a".equals(localName) || "area".equals(localName) || "link".equals(localName))) {
            warn("The \u201Clink\u201D role is unnecessary for element" + " \u201C" + localName + "\u201D with attribute" + " \u201Chref\u201D.");
        } else if (("tbody".equals(localName) || "tfoot".equals(localName) || "thead".equals(localName)) && "rowgroup".equals(role)) {
            warn("The \u201Crowgroup\u201D role is unnecessary for element" + " \u201C" + localName + "\u201D.");
        } else if ("th" == localName && ("columnheader".equals(role) || "columnheader".equals(role))) {
            warn("The \u201C" + role + "\u201D role is unnecessary for" + " element \u201Cth\u201D.");
        } else if ("li" == localName && "listitem".equals(role) && !"menu".equals(parentName)) {
            warn("The \u201Clistitem\u201D role is unnecessary for an" + " \u201Cli\u201D element whose parent is" + " an \u201Col\u201D element or a" + " \u201Cul\u201D element.");
        } else if ("button" == localName && "button".equals(role) && "menu".equals(atts.getValue("", "type"))) {
            warnExplicitRoleUnnecessaryForType("button", "button", "menu");
        } else if ("menu" == localName && "toolbar".equals(role) && "toolbar".equals(atts.getValue("", "type"))) {
            warnExplicitRoleUnnecessaryForType("menu", "toolbar", "toolbar");
        } else if ("li" == localName && "listitem".equals(role) && !"menu".equals(parentName)) {
            warn("The \u201Clistitem\u201D role is unnecessary for an" + " \u201Cli\u201D element whose parent is" + " an \u201Col\u201D element or a" + " \u201Cul\u201D element.");
        }
    } else {
        int len = atts.getLength();
        for (int i = 0; i < len; i++) {
            if (atts.getType(i) == "ID") {
                String attVal = atts.getValue(i);
                if (attVal.length() != 0) {
                    ids.add(attVal);
                }
            }
            String attLocal = atts.getLocalName(i);
            if (atts.getURI(i).length() == 0) {
                if ("role" == attLocal) {
                    role = atts.getValue(i);
                } else if ("aria-activedescendant" == attLocal) {
                    activeDescendant = atts.getValue(i);
                } else if ("aria-owns" == attLocal) {
                    owns = atts.getValue(i);
                }
            }
        }
        allIds.addAll(ids);
    }
    // ARIA required owner/ancestors
    Set<String> requiredAncestorRoles = REQUIRED_ROLE_ANCESTOR_BY_DESCENDANT.get(role);
    if (requiredAncestorRoles != null && !"presentation".equals(parentRole) && !"tbody".equals(localName) && !"tfoot".equals(localName) && !"thead".equals(localName)) {
        if (!currentElementHasRequiredAncestorRole(requiredAncestorRoles)) {
            if (atts.getIndex("", "id") > -1 && !"".equals(atts.getValue("", "id"))) {
                needsAriaOwner.add(new IdrefLocator(new LocatorImpl(getDocumentLocator()), atts.getValue("", "id"), role));
            } else {
                errContainedInOrOwnedBy(role, getDocumentLocator());
            }
        }
    }
    // ARIA IDREFS
    for (String att : MUST_NOT_DANGLE_IDREFS) {
        String attVal = atts.getValue("", att);
        if (attVal != null) {
            String[] tokens = AttributeUtil.split(attVal);
            for (String token : tokens) {
                ariaReferences.add(new IdrefLocator(getDocumentLocator(), token, att));
            }
        }
    }
    allIds.addAll(ids);
    // aria-activedescendant accompanied by aria-owns
    if (activeDescendant != null && !"".equals(activeDescendant)) {
        // "aria-activedescendant");
        if (owns != null && !"".equals(owns)) {
            activeDescendantWithAriaOwns = true;
        // String[] tokens = AttributeUtil.split(owns);
        // for (int i = 0; i < tokens.length; i++) {
        // String token = tokens[i];
        // if (token.equals(activeDescendantVal)) {
        // activeDescendantWithAriaOwns = true;
        // break;
        // }
        // }
        }
    }
    // activedescendant
    for (Iterator<Map.Entry<StackNode, Locator>> iterator = openActiveDescendants.entrySet().iterator(); iterator.hasNext(); ) {
        Map.Entry<StackNode, Locator> entry = iterator.next();
        if (ids.contains(entry.getKey().getActiveDescendant())) {
            iterator.remove();
        }
    }
    if ("http://www.w3.org/1999/xhtml" == uri) {
        int number = specialAncestorNumber(localName);
        if (number > -1) {
            ancestorMask |= (1 << number);
        }
        if ("a" == localName && href) {
            ancestorMask |= HREF_MASK;
        }
        StackNode child = new StackNode(ancestorMask, localName, role, activeDescendant, forAttr);
        if ("style" == localName) {
            child.setIsCollectingCharacters(true);
        }
        if ("script" == localName) {
            child.setIsCollectingCharacters(true);
        }
        if (activeDescendant != null && !activeDescendantWithAriaOwns) {
            openActiveDescendants.put(child, new LocatorImpl(getDocumentLocator()));
        }
        if ("select" == localName && atts.getIndex("", "multiple") == -1) {
            openSingleSelects.put(child, getDocumentLocator());
        } else if ("label" == localName) {
            openLabels.put(child, new LocatorImpl(getDocumentLocator()));
        } else if ("video" == localName || "audio" == localName) {
            openMediaElements.put(child, new TaintableLocatorImpl(getDocumentLocator()));
        }
        push(child);
        if ("article" == localName || "aside" == localName || "nav" == localName || "section" == localName) {
            if (atts.getIndex("", "aria-label") > -1 && !"".equals(atts.getValue("", "aria-label"))) {
                child.setHeadingFound();
            }
        }
        if ("select" == localName && atts.getIndex("", "required") > -1 && atts.getIndex("", "multiple") < 0) {
            if (atts.getIndex("", "size") > -1) {
                String size = trimSpaces(atts.getValue("", "size"));
                if (!"".equals(size)) {
                    try {
                        if ((size.length() > 1 && size.charAt(0) == '+' && Integer.parseInt(size.substring(1)) == 1) || Integer.parseInt(size) == 1) {
                            child.setOptionNeeded();
                        } else {
                        // do nothing
                        }
                    } catch (NumberFormatException e) {
                    }
                }
            } else {
                // default size is 1
                child.setOptionNeeded();
            }
        }
        if (localName.contains("-")) {
            if (atts.getIndex("", "is") > -1) {
                err("Autonomous custom elements must not specify the" + " \u201cis\u201d attribute.");
            }
            try {
                CustomElementName.THE_INSTANCE.checkValid(localName);
            } catch (DatatypeException e) {
                try {
                    if (getErrorHandler() != null) {
                        String msg = e.getMessage();
                        if (e instanceof Html5DatatypeException) {
                            msg = msg.substring(msg.indexOf(": ") + 2);
                        }
                        VnuBadElementNameException ex = new VnuBadElementNameException(localName, uri, msg, getDocumentLocator(), CustomElementName.class, false);
                        getErrorHandler().error(ex);
                    }
                } catch (ClassNotFoundException ce) {
                }
            }
        }
    } else if ("http://n.validator.nu/custom-elements/" == uri) {
        /*
             * For elements with names containing "-" (custom elements), the
             * customelements/NamespaceChanging* code exposes them to jing as
             * elements in the http://n.validator.nu/custom-elements/ namespace.
             * Therefore our RelaxNG schema allows those elements. However,
             * schematronequiv.Assertions still sees those elements as being in
             * the HTML namespace, so here we need to emit an error for the case
             * where, in source transmitted with an XML content type, somebody
             * (for whatever reason) has elements in their markup which they
             * have explicitly placed in that namespace (otherwise, due to
             * allowing those elements in our RelaxNG schema, Jing on its own
             * won't emit any error for them).
             */
        err("Element \u201c" + localName + "\u201d from namespace" + " \u201chttp://n.validator.nu/custom-elements/\u201d" + " not allowed.");
    } else {
        StackNode child = new StackNode(ancestorMask, null, role, activeDescendant, forAttr);
        if (activeDescendant != null) {
            openActiveDescendants.put(child, new LocatorImpl(getDocumentLocator()));
        }
        push(child);
    }
    stack[currentPtr].setLocator(new LocatorImpl(getDocumentLocator()));
}
Also used : Html5DatatypeException(nu.validator.datatype.Html5DatatypeException) HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ArrayList(java.util.ArrayList) CssParseException(org.w3c.css.parser.CssParseException) VnuBadElementNameException(nu.validator.checker.VnuBadElementNameException) StyleSheetParser(org.w3c.css.css.StyleSheetParser) Html5DatatypeException(nu.validator.datatype.Html5DatatypeException) DatatypeException(org.relaxng.datatype.DatatypeException) Locator(org.xml.sax.Locator) ImageCandidateStringsWidthRequired(nu.validator.datatype.ImageCandidateStringsWidthRequired) VnuBadAttrValueException(nu.validator.checker.VnuBadAttrValueException) LocatorImpl(nu.validator.checker.LocatorImpl) TaintableLocatorImpl(nu.validator.checker.TaintableLocatorImpl) ArrayList(java.util.ArrayList) List(java.util.List) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) AutocompleteDetailsUrl(nu.validator.datatype.AutocompleteDetailsUrl) CustomElementName(nu.validator.datatype.CustomElementName) AutocompleteDetailsText(nu.validator.datatype.AutocompleteDetailsText) Color(nu.validator.datatype.Color) AutocompleteDetailsMonth(nu.validator.datatype.AutocompleteDetailsMonth) TaintableLocatorImpl(nu.validator.checker.TaintableLocatorImpl) ByteArrayInputStream(java.io.ByteArrayInputStream) AutocompleteDetailsTel(nu.validator.datatype.AutocompleteDetailsTel) ApplContext(org.w3c.css.util.ApplContext) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) CssError(org.w3c.css.parser.CssError)

Example 3 with VnuBadElementNameException

use of nu.validator.checker.VnuBadElementNameException in project validator by validator.

the class MessageEmitterAdapter method error.

/**
 * @param e
 * @throws SAXException
 */
private void error(SAXParseException e, boolean exact) throws SAXException {
    if ((!batchMode && fatalErrors > 0) || nonDocumentErrors > 0) {
        return;
    }
    Map<String, DatatypeException> datatypeErrors = null;
    if (e instanceof BadAttributeValueException) {
        datatypeErrors = ((BadAttributeValueException) e).getExceptions();
    }
    if (e instanceof VnuBadAttrValueException) {
        datatypeErrors = ((VnuBadAttrValueException) e).getExceptions();
    }
    if (e instanceof VnuBadElementNameException) {
        datatypeErrors = ((VnuBadElementNameException) e).getExceptions();
    }
    if (e instanceof DatatypeMismatchException) {
        datatypeErrors = ((DatatypeMismatchException) e).getExceptions();
    }
    if (datatypeErrors != null) {
        for (Map.Entry<String, DatatypeException> entry : datatypeErrors.entrySet()) {
            DatatypeException dex = entry.getValue();
            if (dex instanceof Html5DatatypeException) {
                Html5DatatypeException ex5 = (Html5DatatypeException) dex;
                if (ex5.isWarning()) {
                    this.warnings++;
                    throwIfTooManyMessages();
                    messageFromSAXParseException(MessageType.WARNING, e, exact, null);
                    return;
                }
            }
        }
    }
    this.errors++;
    throwIfTooManyMessages();
    messageFromSAXParseException(MessageType.ERROR, e, exact, null);
}
Also used : Html5DatatypeException(nu.validator.datatype.Html5DatatypeException) DatatypeException(org.relaxng.datatype.DatatypeException) Html5DatatypeException(nu.validator.datatype.Html5DatatypeException) BadAttributeValueException(com.thaiopensource.relaxng.exceptions.BadAttributeValueException) VnuBadAttrValueException(nu.validator.checker.VnuBadAttrValueException) VnuBadElementNameException(nu.validator.checker.VnuBadElementNameException) DatatypeMismatchException(nu.validator.checker.DatatypeMismatchException) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap)

Example 4 with VnuBadElementNameException

use of nu.validator.checker.VnuBadElementNameException in project validator by validator.

the class MessageEmitterAdapter method messageText.

/**
 * @param message
 * @throws SAXException
 */
private void messageText(Exception message) throws SAXException {
    if (message instanceof AbstractValidationException) {
        AbstractValidationException ave = (AbstractValidationException) message;
        rngMessageText(ave);
    } else if (message instanceof VnuBadAttrValueException) {
        VnuBadAttrValueException e = (VnuBadAttrValueException) message;
        vnuBadAttrValueMessageText(e);
    } else if (message instanceof VnuBadElementNameException) {
        VnuBadElementNameException e = (VnuBadElementNameException) message;
        vnuElementNameMessageText(e);
    } else {
        String msg = message.getMessage();
        if (msg != null) {
            MessageTextHandler messageTextHandler = emitter.startText();
            if (messageTextHandler != null) {
                emitStringWithQurlyQuotes(messageTextHandler, msg);
            }
            emitter.endText();
        }
    }
}
Also used : AbstractValidationException(com.thaiopensource.relaxng.exceptions.AbstractValidationException) VnuBadAttrValueException(nu.validator.checker.VnuBadAttrValueException) VnuBadElementNameException(nu.validator.checker.VnuBadElementNameException)

Aggregations

VnuBadAttrValueException (nu.validator.checker.VnuBadAttrValueException)4 VnuBadElementNameException (nu.validator.checker.VnuBadElementNameException)4 HashMap (java.util.HashMap)3 Map (java.util.Map)3 Html5DatatypeException (nu.validator.datatype.Html5DatatypeException)3 DatatypeException (org.relaxng.datatype.DatatypeException)3 AbstractValidationException (com.thaiopensource.relaxng.exceptions.AbstractValidationException)2 BadAttributeValueException (com.thaiopensource.relaxng.exceptions.BadAttributeValueException)2 TreeMap (java.util.TreeMap)2 DatatypeMismatchException (nu.validator.checker.DatatypeMismatchException)2 ImpossibleAttributeIgnoredException (com.thaiopensource.relaxng.exceptions.ImpossibleAttributeIgnoredException)1 OnlyTextNotAllowedException (com.thaiopensource.relaxng.exceptions.OnlyTextNotAllowedException)1 OutOfContextElementException (com.thaiopensource.relaxng.exceptions.OutOfContextElementException)1 RequiredAttributesMissingException (com.thaiopensource.relaxng.exceptions.RequiredAttributesMissingException)1 RequiredAttributesMissingOneOfException (com.thaiopensource.relaxng.exceptions.RequiredAttributesMissingOneOfException)1 RequiredElementsMissingException (com.thaiopensource.relaxng.exceptions.RequiredElementsMissingException)1 RequiredElementsMissingOneOfException (com.thaiopensource.relaxng.exceptions.RequiredElementsMissingOneOfException)1 StringNotAllowedException (com.thaiopensource.relaxng.exceptions.StringNotAllowedException)1 TextNotAllowedException (com.thaiopensource.relaxng.exceptions.TextNotAllowedException)1 UnfinishedElementException (com.thaiopensource.relaxng.exceptions.UnfinishedElementException)1