📄 htmlvalidator.java
字号:
* content model recommends to insert making the situation * ok. If Boolean.True is returned, the content model current * position is moved forward. Otherwise this position remains * the same. * @param tElement * @return */ public Object tagIsValidForContext(TagElement tElement) { // Check the current content model, if one is available. node cv = getCurrentContentModel(); if (cv != null) return cv.show(tElement.getElement()); // Check exclusions and inclusions. ListIterator iter = stack.listIterator(stack.size()); hTag t; final int idx = tElement.getElement().index; // Check only known tags. if (idx >= 0) { BitSet inclusions = new BitSet(); while (iter.hasPrevious()) { t = (hTag) iter.previous(); if (!t.forcibly_closed) { if (t.element.exclusions != null && t.element.exclusions.get(idx) ) return Boolean.FALSE; if (t.element.inclusions != null) inclusions.or(t.element.inclusions); } } if (!inclusions.get(idx)) return Boolean.FALSE; } return Boolean.TRUE; } /** * Validate tag without storing in into the tag stack. This is called * for the empty tags and results the subsequent calls to the openTag * and closeTag. */ public void validateTag(TagElement tElement, htmlAttributeSet parameters) { openTag(tElement, parameters); closeTag(tElement); } /** * Check for mandatory elements, subsequent to the last tag: * @param tElement The element that will be inserted next. */ protected void checkContentModel(TagElement tElement, boolean first) { if (stack.isEmpty()) return; hTag last = (hTag) stack.getLast(); if (last.validationTrace == null) return; Object r = last.validationTrace.show(tElement.getElement()); if (r == Boolean.FALSE) s_error("The <" + last.element + "> does not match the content model " + last.validationTrace ); else if (r instanceof Element) // The content model recommends insertion of this element { if (!first) closeTag(last.tgElement); handleSupposedStartTag((Element) r); openTag(new TagElement((Element) r), null); } } /** * The method is called when the tag must be closed because * it does not allow the subsequent elements inside its context * or the end of stream has been reached. The parser is only * informed if the element being closed does not require the * end tag (the "omitEnd" flag is set). * The closing message must be passed to the parser mechanism * before passing message about the opening the next tag. * * @param element The tag being fictionally (forcibly) closed. */ protected abstract void handleSupposedEndTag(Element element); /** * The method is called when the validator decides to open the * tag on its own initiative. This may happen if the content model * includes the element with the optional (supposed) start tag. * * @param element The tag being opened. */ protected abstract void handleSupposedStartTag(Element element); /** * Handles the error message. This method must be overridden to pass * the message where required. * @param msg The message text. */ protected abstract void s_error(String msg); /** * Validate the parameters, report the error if the given parameter is * not in the parameter set, valid for the given attribute. The information * about the valid parameter set is taken from the Element, enclosed * inside the tag. The method does not validate the default parameters. * @param tag The tag * @param parameters The parameters of this tag. */ protected void validateParameters(TagElement tag, htmlAttributeSet parameters) { if (parameters == null || parameters == htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET || parameters == SimpleAttributeSet.EMPTY ) return; Enumeration enumeration = parameters.getAttributeNames(); while (enumeration.hasMoreElements()) { validateAttribute(tag, parameters, enumeration); } // Check for missing required values. AttributeList a = tag.getElement().getAttributes(); while (a != null) { if (a.getModifier() == DTDConstants.REQUIRED) if (parameters.getAttribute(a.getName()) == null) { s_error("Missing required attribute '" + a.getName() + "' for <" + tag.getHTMLTag() + ">" ); } a = a.next; } } private node getCurrentContentModel() { if (!stack.isEmpty()) { hTag last = (hTag) stack.getLast(); return last.validationTrace; } else return null; } private void closeLast() { handleSupposedEndTag(((hTag) stack.getLast()).element); stack.removeLast(); } private void openFictionalTag(Element e) { handleSupposedStartTag(e); stack.add(new hTag(new TagElement(e, true))); if (!e.omitStart()) s_error("<" + e + "> is expected (supposing it)"); } private void validateAttribute(TagElement tag, htmlAttributeSet parameters, Enumeration enumeration ) { Object foundAttribute; AttributeList dtdAttribute; foundAttribute = enumeration.nextElement(); dtdAttribute = tag.getElement().getAttribute(foundAttribute.toString()); if (dtdAttribute == null) { StringBuffer valid = new StringBuffer("The tag <" + tag.getHTMLTag() + "> cannot contain the attribute '" + foundAttribute + "'. The valid attributes for this tag are: " ); AttributeList a = tag.getElement().getAttributes(); while (a != null) { valid.append(a.name.toUpperCase()); valid.append(' '); a = a.next; } s_error(valid.toString()); } else { String value = parameters.getAttribute(foundAttribute).toString(); if (dtdAttribute.type == DTDConstants.NUMBER) validateNumberAttribute(tag, foundAttribute, value); if (dtdAttribute.type == DTDConstants.NAME || dtdAttribute.type == DTDConstants.ID ) validateNameOrIdAttribute(tag, foundAttribute, value); if (dtdAttribute.values != null) validateAttributeWithValueList(tag, foundAttribute, dtdAttribute, value ); } } private void validateAttributeWithValueList(TagElement tag, Object foundAttribute, AttributeList dtdAttribute, String value ) { if (!dtdAttribute.values.contains(value.toLowerCase()) && !dtdAttribute.values.contains(value.toUpperCase()) ) { StringBuffer valid; if (dtdAttribute.values.size() == 1) valid = new StringBuffer("The attribute '" + foundAttribute + "' of the tag <" + tag.getHTMLTag() + "> cannot have the value '" + value + "'. The only valid value is " ); else valid = new StringBuffer("The attribute '" + foundAttribute + "' of the tag <" + tag.getHTMLTag() + "> cannot have the value '" + value + "'. The " + dtdAttribute.values.size() + " valid values are: " ); Enumeration vv = dtdAttribute.values.elements(); while (vv.hasMoreElements()) { valid.append('"'); valid.append(vv.nextElement()); valid.append("\" "); } s_error(valid.toString()); } } private void validateNameOrIdAttribute(TagElement tag, Object foundAttribute, String value ) { boolean ok = true; if (!Character.isLetter(value.charAt(0))) ok = false; char c; for (int i = 0; i < value.length(); i++) { c = value.charAt(i); if (!( Character.isLetter(c) || Character.isDigit(c) || "".indexOf(c) >= 0 ) ) ok = false; } if (!ok) s_error("The '" + foundAttribute + "' attribute of the tag <" + tag.getHTMLTag() + "> must start from letter and consist of " + "letters, digits, hypens, colons, underscores and periods. " + "It cannot be '" + value + "'" ); } private void validateNumberAttribute(TagElement tag, Object foundAttribute, String value ) { try { Integer.parseInt(value); } catch (NumberFormatException ex) { s_error("The '" + foundAttribute + "' attribute of the tag <" + tag.getHTMLTag() + "> must be a valid number and not '" + value + "'" ); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -