📄 validationconsumer.java
字号:
&& ":-_.".indexOf (c) == -1 && !isExtender (c)) pass = false; } } if (!pass) error ("In " + context + " for " + id + ", '" + name + "' is not a name"); return pass; // true == OK } // use augmented Unicode rules, not full XML rules private boolean isNmtoken (String nmtoken, String context, String id) throws SAXException { char buf [] = nmtoken.toCharArray (); boolean pass = true; int max = buf.length; // XXX make this share code with isName for (int i = 0; pass && i < max; i++) { char c = buf [i]; if (!Character.isUnicodeIdentifierPart (c) && ":-_.".indexOf (c) == -1 && !isExtender (c)) pass = false; } if (!pass) error ("In " + context + " for " + id + ", '" + nmtoken + "' is not a name token"); return pass; // true == OK } private void checkEnumeration (String value, String type, String name) throws SAXException { if (!hasMatch (value, type)) // VC: Enumeration error ("Value '" + value + "' for attribute '" + name + "' is not permitted: " + type); } // used to test enumerated attributes and mixed content models // package private static boolean hasMatch (String value, String orList) { int len = value.length (); int max = orList.length () - len; for (int start = 0; (start = orList.indexOf (value, start)) != -1; start++) { char c; if (start > max) break; c = orList.charAt (start - 1); if (c != '|' && c != '('/*)*/) continue; c = orList.charAt (start + len); if (c != '|' && /*(*/ c != ')') continue; return true; } return false; } /** * <b>LexicalHandler</b> Records the declaration of the root * element, so it can be verified later. * Passed to the next consumer, unless this one was * preloaded with a particular DTD. */ public void startDTD (String name, String publicId, String systemId) throws SAXException { if (disableDeclarations) return; rootName = name; super.startDTD (name, publicId, systemId); } /** * <b>LexicalHandler</b> Verifies that all referenced notations * and unparsed entities have been declared. * Passed to the next consumer, unless this one was * preloaded with a particular DTD. */ public void endDTD () throws SAXException { if (disableDeclarations) return; // this is a convenient hook for end-of-dtd checks, but we // could also trigger it in the first startElement call. // locator info is more appropriate here though. // VC: Notation Declared (NDATA can refer to them before decls, // as can NOTATION attribute enumerations and defaults) int length = nDeferred.size (); for (int i = 0; i < length; i++) { String notation = (String) nDeferred.elementAt (i); if (!notations.contains (notation)) { error ("A declaration referred to notation '" + notation + "' which was never declared"); } } nDeferred.removeAllElements (); // VC: Entity Name (attribute values can refer to them // before they're declared); VC Attribute Default Legal length = uDeferred.size (); for (int i = 0; i < length; i++) { String entity = (String) uDeferred.elementAt (i); if (!unparsed.contains (entity)) { error ("An attribute default referred to entity '" + entity + "' which was never declared"); } } uDeferred.removeAllElements (); super.endDTD (); } // These are interned, so we can rely on "==" to find the type of // all attributes except enumerations ... // "(this|or|that|...)" and "NOTATION (this|or|that|...)" static final String types [] = { "CDATA", "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES" }; /** * <b>DecllHandler</b> Records attribute declaration for later use * in validating document content, and checks validity constraints * that are applicable to attribute declarations. * Passed to the next consumer, unless this one was * preloaded with a particular DTD. */ public void attributeDecl ( String eName, String aName, String type, String mode, String value ) throws SAXException { if (disableDeclarations) return; ElementInfo info = (ElementInfo) elements.get (eName); AttributeInfo ainfo = new AttributeInfo (); boolean checkOne = false; boolean interned = false; // cheap interning of type names and #FIXED, #REQUIRED // for faster startElement (we can use "==") for (int i = 0; i < types.length; i++) { if (types [i].equals (type)) { type = types [i]; interned = true; break; } } if ("#FIXED".equals (mode)) mode = "#FIXED"; else if ("#REQUIRED".equals (mode)) mode = "#REQUIRED"; ainfo.type = type; ainfo.mode = mode; ainfo.value = value; // we might not have seen the content model yet if (info == null) { info = new ElementInfo (eName); elements.put (eName, info); } if ("ID" == type) { checkOne = true; if (!("#REQUIRED" == mode || "#IMPLIED".equals (mode))) { // VC: ID Attribute Default error ("ID attribute '" + aName + "' must be #IMPLIED or #REQUIRED"); } } else if (!interned && type.startsWith ("NOTATION ")) { checkOne = true; // VC: Notation Attributes (notations must be declared) StringTokenizer tokens = new StringTokenizer ( type.substring (10, type.lastIndexOf (')')), "|"); while (tokens.hasMoreTokens ()) { String token = tokens.nextToken (); if (!notations.contains (token)) nDeferred.addElement (token); } } if (checkOne) { for (Enumeration e = info.attributes.keys (); e.hasMoreElements (); /* NOP */) { String name; AttributeInfo ainfo2; name = (String) e.nextElement (); ainfo2 = (AttributeInfo) info.attributes.get (name); if (type == ainfo2.type || !interned /* NOTATION */) { // VC: One ID per Element Type // VC: One Notation per Element TYpe error ("Element '" + eName + "' already has an attribute of type " + (interned ? "NOTATION" : type) + " ('" + name + "') so '" + aName + "' is a validity error"); } } } // VC: Attribute Default Legal if (value != null) { if ("CDATA" == type) { // event source rejected '<' } else if ("NMTOKEN" == type) { // VC: Name Token (is a nmtoken) isNmtoken (value, "attribute default", aName); } else if ("NMTOKENS" == type) { // VC: Name Token (is a nmtoken; at least one value) StringTokenizer tokens = new StringTokenizer (value); if (!tokens.hasMoreTokens ()) error ("Default for attribute '" + aName + "' must have at least one name token."); else do { String token = tokens.nextToken (); isNmtoken (token, "attribute default", aName); } while (tokens.hasMoreTokens ()); } else if ("IDREF" == type || "ENTITY" == type) { // VC: Entity Name (is a name) // VC: IDREF (is a name) (is declared) isName (value, "attribute default", aName); if ("ENTITY" == type && !unparsed.contains (value)) uDeferred.addElement (value); } else if ("IDREFS" == type || "ENTITIES" == type) { // VC: Entity Name (is a name; at least one value) // VC: IDREF (is a name; at least one value) StringTokenizer names = new StringTokenizer (value); if (!names.hasMoreTokens ()) error ("Default for attribute '" + aName + "' must have at least one name."); else do { String name = names.nextToken (); isName (name, "attribute default", aName); if ("ENTITIES" == type && !unparsed.contains (name)) uDeferred.addElement (value); } while (names.hasMoreTokens ()); } else if (type.charAt (0) == '(' /*)*/ ) { // VC: Enumeration (must match) checkEnumeration (value, type, aName); } else if (!interned && checkOne) { /* NOTATION */ // VC: Notation attributes (must be names) isName (value, "attribute default", aName); // VC: Notation attributes (must be declared) if (!notations.contains (value)) nDeferred.addElement (value); // VC: Enumeration (must match) checkEnumeration (value, type, aName); } else if ("ID" != type) throw new RuntimeException ("illegal attribute type: " + type); } if (info.attributes.get (aName) == null) info.attributes.put (aName, ainfo); /* else warning ("Element '" + eName + "' already has an attribute named '" + aName + "'"); */ if ("xml:space".equals (aName)) { if (!("(default|preserve)".equals (type) || "(preserve|default)".equals (type) // these next two are arguable; XHTML's DTD doesn't // deserve errors. After all, it's not like any // illegal _value_ could pass ... || "(preserve)".equals (type) || "(default)".equals (type) )) error ( "xml:space attribute type must be like '(default|preserve)'" + " not '" + type + "'" ); } super.attributeDecl (eName, aName, type, mode, value); } /** * <b>DecllHandler</b> Records the element declaration for later use * when checking document content, and checks validity constraints that * apply to element declarations. Passed to the next consumer, unless * this one was preloaded with a particular DTD. */ public void elementDecl (String name, String model) throws SAXException { if (disableDeclarations) return; ElementInfo info = (ElementInfo) elements.get (name); // we might have seen an attribute decl already if (info == null) { info = new ElementInfo (name); elements.put (name, info); } if (info.model != null) { // NOTE: not all parsers can report such duplicates. // VC: Unique Element Type Declaration error ("Element type '" + name + "' was already declared."); } else { info.model = model; // VC: No Duplicate Types (in mixed content models) if (model.charAt (1) == '#') // (#PCDATA... info.getRecognizer (this); } super.elementDecl (name, model); } /** * <b>DecllHandler</b> passed to the next consumer, unless this * one was preloaded with a particular DTD */ public void internalEntityDecl (String name, String value) throws SAXException { if (!disableDeclarations) super.internalEntityDecl (name, value); } /** * <b>DecllHandler</b> passed to the next consumer, unless this * one was preloaded with a particular DTD */ public void externalEntityDecl (String name, String publicId, String systemId) throws SAXException { if (!disableDeclarations) super.externalEntityDecl (name, publicId, systemId); } /** * <b>DTDHandler</b> Records the notation name, for checking * NOTATIONS attribute values and declararations of unparsed * entities. Passed to the next consumer, unless this one was * preloaded with a particular DTD. */ public void notationDecl (String name, String publicId, String systemId) throws SAXException { if (disableDeclarations) return; notations.addElement (name); super.notationDecl (name, publicId, systemId); } /** * <b>DTDHandler</b> Records the entity name, for checking * ENTITY and ENTITIES attribute values; records the notation * name if it hasn't yet been declared. Passed to the next consumer, * unless this one was preloaded with a particular DTD. */ public void unparsedEntityDecl ( String name, String publicId, String systemId, String notationName ) throws SAXException { if (disableDeclarations) return; unparsed.addElement (name); if (!notations.contains (notationName)) nDeferred.addElement (notationName); super.unparsedEntityDecl (name, publicId, systemId, notationName); } /** * <b>ContentHandler</b> Ensures that state from any previous parse * has been deleted. * Passed to the next consumer. */ public void startDocument () throws SAXException { resetState (); super.startDocument (); } private static boolean isAsciiLetter (char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } /** * <b>ContentHandler</b> Reports a fatal exception. Validating * XML processors may not skip any entities. */ public void skippedEntity (String name) throws SAXException { fatalError ("may not skip entities"); } /* * SAX2 doesn't expand non-PE refs in attribute defaults... */ private String expandDefaultRefs (String s) throws SAXException { if (s.indexOf ('&') < 0) return s; // FIXME: handle &#nn; &#xnn; &name; String message = "Can't expand refs in attribute default: " + s; warning (message); return s; } /** * <b>ContentHandler</b> Performs validity checks against element * (and document) content models, and attribute values. * Passed to the next consumer. */ public void startElement ( String uri, String localName, String qName, Attributes atts ) throws SAXException { // // First check content model for the enclosing scope. // if (contentStack.isEmpty ()) { // VC: Root Element Type if (!qName.equals (rootName)) { if (rootName == null) warning ("This document has no DTD, can't be valid"); else error ("Root element type '" + qName + "' was declared to be '" + rootName + "'"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -