docs: private void parseElement(boolean maybeGetSubset) throws Exception {
          String gi;
          char c;
          int oldElementContent = currentElementContent;
          String oldElement = currentElement;
          ElementDecl element;
  
          // This is the (global) counter for the
          // array of specified attributes.
          tagAttributePos = 0;
  
          // Read the element type name.
          gi = readNmtoken(true);
  
          // If we saw no DTD, and this is the document root element,
          // let the application modify the input stream by providing one.
          if (maybeGetSubset) {
              InputSource subset = handler.getExternalSubset(gi,
                      handler.getSystemId());
              if (subset != null) {
                  String publicId = subset.getPublicId();
                  String systemId = subset.getSystemId();
  
                  handler.warn("modifying document by adding DTD");
                  handler.doctypeDecl(gi, publicId, systemId);
                  pushString(null, ">");
  
                  // NOTE: [dtd] is so we say what SAX2 expects,
                  // though it's misleading (subset, not entire dtd)
                  pushURL(true, "[dtd]", new ExternalIdentifiers(publicId,
                          systemId, null), subset.getCharacterStream(),
                          subset.getByteStream(), subset.getEncoding(), false);
  
                  // Loop until we end up back at '>'
                  while (true) {
                      doReport = expandPE = true;
                      skipWhitespace();
                      doReport = expandPE = false;
                      if (tryRead('>')) {
                          break;
                      } else {
                          expandPE = true;
                          parseMarkupdecl();
                          expandPE = false;
                      }
                  }
  
                  // the ">" string isn't popped yet
                  if (inputStack.size() != 1) {
                      fatal("external subset has unmatched '>'");
                  }
  
                  handler.endDoctype();
              }
          }
  
          // Determine the current content type.
          currentElement = gi;
          element = 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) {
                  fatal("need whitespace between attributes");
              }
              parseAttribute(gi);
              white = tryWhitespace();
              c = readCh();
          }
  
          // Supply any defaulted attributes.
          Iterator<String> atts = declaredAttributes(element);
          if (atts != null) {
              String aname;
              loop: while (atts.hasNext()) {
                  aname = atts.next();
                  // 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;
      }