xmlparser.java
来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· Java 代码 · 共 2,494 行 · 第 1/5 页
JAVA
2,494 行
if (tryRead ('>')) { break; } else { expandPE = true; parseMarkupdecl (); expandPE = false; } } // the ">" string isn't popped yet if (inputStack.size () != 1) error ("external subset has unmatched '>'"); handler.endDoctype (); } } // Determine the current content type. currentElement = gi; element = (Object []) elementInfo.get (gi); currentElementContent = getContentType (element, CONTENT_ANY); // Read the attributes, if any. // After this loop, "c" is the closing delimiter. boolean white = tryWhitespace (); c = readCh (); while (c != '/' && c != '>') { unread (c); if (!white) error ("need whitespace between attributes"); parseAttribute (gi); white = tryWhitespace (); c = readCh (); } // Supply any defaulted attributes. Enumeration atts = declaredAttributes (element); if (atts != null) { String aname;loop: while (atts.hasMoreElements ()) { aname = (String) atts.nextElement (); // See if it was specified. for (int i = 0; i < tagAttributePos; i++) { if (tagAttributes [i] == aname) { continue loop; } } // ... or has a default String value = getAttributeDefaultValue (gi, aname); if (value == null) continue; handler.attribute (aname, value, false); } } // Figure out if this is a start tag // or an empty element, and dispatch an // event accordingly. switch (c) { case '>': handler.startElement (gi); parseContent (); break; case '/': require ('>'); handler.startElement (gi); handler.endElement (gi); break; } // Restore the previous state. currentElement = oldElement; currentElementContent = oldElementContent; } /** * Parse an attribute assignment. * <pre> * [41] Attribute ::= Name Eq AttValue * </pre> * @param name The name of the attribute's element. * @see SAXDriver#attribute */ private void parseAttribute (String name) throws Exception { String aname; String type; String value; int flags = LIT_ATTRIBUTE | LIT_ENTITY_REF; // Read the attribute name. aname = readNmtoken (true); type = getAttributeType (name, aname); // Parse '=' parseEq (); // Read the value, normalizing whitespace // unless it is CDATA. if (type == "CDATA" || type == null) { value = readLiteral (flags); } else { value = readLiteral (flags | LIT_NORMALIZE); } // WFC: no duplicate attributes for (int i = 0; i < tagAttributePos; i++) if (aname.equals (tagAttributes [i])) error ("duplicate attribute", aname, null); // Inform the handler about the // attribute. handler.attribute (aname, value, true); dataBufferPos = 0; // Note that the attribute has been // specified. if (tagAttributePos == tagAttributes.length) { String newAttrib[] = new String [tagAttributes.length * 2]; System.arraycopy (tagAttributes, 0, newAttrib, 0, tagAttributePos); tagAttributes = newAttrib; } tagAttributes [tagAttributePos++] = aname; } /** * Parse an equals sign surrounded by optional whitespace. * <pre> * [25] Eq ::= S? '=' S? * </pre> */ private void parseEq () throws SAXException, IOException { skipWhitespace (); require ('='); skipWhitespace (); } /** * Parse an end tag. * <pre> * [42] ETag ::= '</' Name S? '>' * </pre> * <p>NOTE: parseContent () chains to here, we already read the * "</". */ private void parseETag () throws Exception { require (currentElement); skipWhitespace (); require ('>'); handler.endElement (currentElement); // not re-reporting any SAXException re bogus end tags, // even though that diagnostic might be clearer ... } /** * Parse the content of an element. * <pre> * [43] content ::= (element | CharData | Reference * | CDSect | PI | Comment)* * [67] Reference ::= EntityRef | CharRef * </pre> * <p> NOTE: consumes ETtag. */ private void parseContent () throws Exception { char c; while (true) { // consume characters (or ignorable whitspace) until delimiter parseCharData (); // Handle delimiters c = readCh (); switch (c) { case '&': // Found "&" c = readCh (); if (c == '#') { parseCharRef (); } else { unread (c); parseEntityRef (true); } break; case '<': // Found "<" dataBufferFlush (); c = readCh (); switch (c) { case '!': // Found "<!" c = readCh (); switch (c) { case '-': // Found "<!-" require ('-'); parseComment (); break; case '[': // Found "<![" require ("CDATA["); handler.startCDATA (); inCDATA = true; parseCDSect (); inCDATA = false; handler.endCDATA (); break; default: error ("expected comment or CDATA section", c, null); break; } break; case '?': // Found "<?" parsePI (); break; case '/': // Found "</" parseETag (); return; default: // Found "<" followed by something else unread (c); parseElement (false); break; } } } } /** * Parse an element type declaration. * <pre> * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' * </pre> * <p> NOTE: the '<!ELEMENT' has already been read. */ private void parseElementDecl () throws Exception { String name; requireWhitespace (); // Read the element type name. name = readNmtoken (true); requireWhitespace (); // Read the content model. parseContentspec (name); skipWhitespace (); require ('>'); } /** * Content specification. * <pre> * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | elements * </pre> */ private void parseContentspec (String name) throws Exception {// FIXME: move elementDecl() into setElement(), pass EMTPY/ANY ... if (tryRead ("EMPTY")) { setElement (name, CONTENT_EMPTY, null, null); if (!skippedPE) handler.getDeclHandler ().elementDecl (name, "EMPTY"); return; } else if (tryRead ("ANY")) { setElement (name, CONTENT_ANY, null, null); if (!skippedPE) handler.getDeclHandler ().elementDecl (name, "ANY"); return; } else { String model; char saved []; require ('('); saved = readBuffer; dataBufferAppend ('('); skipWhitespace (); if (tryRead ("#PCDATA")) { dataBufferAppend ("#PCDATA"); parseMixed (saved); model = dataBufferToString (); setElement (name, CONTENT_MIXED, model, null); } else { parseElements (saved); model = dataBufferToString (); setElement (name, CONTENT_ELEMENTS, model, null); } if (!skippedPE) handler.getDeclHandler ().elementDecl (name, model); } } /** * Parse an element-content model. * <pre> * [47] elements ::= (choice | seq) ('?' | '*' | '+')? * [49] choice ::= '(' S? cp (S? '|' S? cp)+ S? ')' * [50] seq ::= '(' S? cp (S? ',' S? cp)* S? ')' * </pre> * * <p> NOTE: the opening '(' and S have already been read. * * @param saved Buffer for entity that should have the terminal ')' */ private void parseElements (char saved []) throws Exception { char c; char sep; // Parse the first content particle skipWhitespace (); parseCp (); // Check for end or for a separator. skipWhitespace (); c = readCh (); switch (c) { case ')': // VC: Proper Group/PE Nesting if (readBuffer != saved) handler.verror ("Illegal Group/PE nesting"); dataBufferAppend (')'); c = readCh (); switch (c) { case '*': case '+': case '?': dataBufferAppend (c); break; default: unread (c); } return; case ',': // Register the separator. case '|': sep = c; dataBufferAppend (c); break; default: error ("bad separator in content model", c, null); return; } // Parse the rest of the content model. while (true) { skipWhitespace (); parseCp (); skipWhitespace (); c = readCh (); if (c == ')') { // VC: Proper Group/PE Nesting if (readBuffer != saved) handler.verror ("Illegal Group/PE nesting"); dataBufferAppend (')'); break; } else if (c != sep) { error ("bad separator in content model", c, null); return; } else { dataBufferAppend (c); } } // Check for the occurrence indicator. c = readCh (); switch (c) { case '?': case '*': case '+': dataBufferAppend (c); return; default: unread (c); return; } } /** * Parse a content particle. * <pre> * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')? * </pre> */ private void parseCp () throws Exception { if (tryRead ('(')) { dataBufferAppend ('('); parseElements (readBuffer); } else { dataBufferAppend (readNmtoken (true)); char c = readCh (); switch (c) { case '?': case '*': case '+': dataBufferAppend (c); break; default: unread (c); break; } } } /** * Parse mixed content. * <pre> * [51] Mixed ::= '(' S? ( '#PCDATA' (S? '|' S? Name)*) S? ')*' * | '(' S? ('#PCDATA') S? ')' * </pre> * * @param saved Buffer for entity that should have the terminal ')' */ private void parseMixed (char saved []) throws Exception { // Check for PCDATA alone. skipWhitespace (); if (tryRead (')')) { // VC: Proper Group/PE Nesting if (readBuffer != saved) handler.verror ("Illegal Group/PE nesting"); dataBufferAppend (")*"); tryRead ('*'); return; } // Parse mixed content. skipWhitespace (); while (!tryRead (")")) { require ('|'); dataBufferAppend ('|'); skipWhitespace (); dataBufferAppend (readNmtoken (true)); skipWhitespace (); } // VC: Proper Group/PE Nesting if (readBuffer != saved) handler.verror ("Illegal Group/PE nesting"); require ('*'); dataBufferAppend (")*"); } /** * Parse an attribute list declaration. * <pre> * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>' * </pre> * <p>NOTE: the '<!ATTLIST' has already been read. */ private void parseAttlistDecl () throws Exception { String elementName; requireWhitespace (); elementName = readNmtoken (true); boolean white = tryWhitespace (); while (!tryRead ('>')) { if (!white) error ("whitespace required before attribute definition"); parseAttDef (elementName); white = tryWhitespace (); } } /** * Parse a single attribute definition. * <pre> * [53] AttDef ::= S Name S AttType S DefaultDecl * </pre> */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?