validator/engine/dom-walker.js
/**
   * Given a SAX-like {@code amp.htmlparser.HtmlSaxHandler}, enumerates the
   * children of {@code rootDoc} and lets the {@code handler} know the
   * structure while visiting the nodes.
   *
   * @param {!amp.htmlparser.HtmlSaxHandler} handler
   * @param {!Document} rootDoc
   */
Given a SAX-like  amp.htmlparser.HtmlSaxHandler, enumerates the
children of  rootDoc and lets the  handler know the
structure while visiting the nodes.

@param {!amp.htmlparser.HtmlSaxHandler} handler
@param {!Document} rootDoc
Given a SAX - like amp . htmlparser . HtmlSaxHandler enumerates the children of rootDoc and lets the handler know the structure while visiting the nodes . @param { !amp . htmlparser . HtmlSaxHandler } handler @param { !Document } rootDoc
walktree(handler, rootDoc) {
    let locator = null;
    if (handler instanceof amp.htmlparser.HtmlSaxHandlerWithLocation) {
      locator = new amp.htmlparser.HtmlParser.DocLocatorImpl('');
      handler.setDocLocator(locator);
    }
    handler.startDoc();
    if (rootDoc.doctype !== null) {
      handler.startTag('!DOCTYPE', [rootDoc.doctype.name, '']);
    }
    const calls = [];
    const tagStack = [];
    tagStack.push(new amp.domwalker.NodeProcessingState_(rootDoc));
    while (tagStack.length > 0) {
      const curState = tagStack[tagStack.length - 1];
      const nextChild = curState.nextChild();
      if (nextChild !== undefined) {
        const tagName = nextChild.node().nodeName;
        calls.push([
          amp.domwalker.HandlerCalls.START_TAG, tagName,
          attrList(nextChild.node().attributes)
        ]);
        if (CdataTagsToValidate.hasOwnProperty(tagName)) {
          calls.push(
              [amp.domwalker.HandlerCalls.CDATA, nextChild.node().textContent]);
        }
        tagStack.push(nextChild);
      } else {
        if (tagStack.length > 1) {
          calls.push([
            amp.domwalker.HandlerCalls.END_TAG,
            curState.node().nodeName
          ]);
        }
        tagStack.pop();
      }
    }
    for (let i = 0; i < calls.length; ++i) {
      switch (calls[i][0]) {
        case amp.domwalker.HandlerCalls.START_TAG:
          handler.startTag(calls[i][1], calls[i][2]);
          break;
        case amp.domwalker.HandlerCalls.CDATA:
          handler.cdata(calls[i][1]);
          break;
        case amp.domwalker.HandlerCalls.END_TAG:
          handler.endTag(calls[i][1]);
          break;
        default:
          console.error(calls[i][0]);
          break;
      }
    }
    handler.endDoc();
  }
walktree ( handler , rootDoc ) { let locator = null ; if ( handler instanceof amp . htmlparser . HtmlSaxHandlerWithLocation ) { locator = new amp . htmlparser . HtmlParser . DocLocatorImpl ( '' ) ; handler . setDocLocator ( locator ) ; } handler . startDoc ( ) ; if ( rootDoc . doctype !== null ) { handler . startTag ( '!DOCTYPE' , [ rootDoc . doctype . name , '' ] ) ; } const calls = [ ] ; const tagStack = [ ] ; tagStack . push ( new amp . domwalker . NodeProcessingState_ ( rootDoc ) ) ; while ( tagStack . length > 0 ) { const curState = tagStack [ tagStack . length - 1 ] ; const nextChild = curState . nextChild ( ) ; if ( nextChild !== undefined ) { const tagName = nextChild . node ( ) . nodeName ; calls . push ( [ amp . domwalker . HandlerCalls . START_TAG , tagName , attrList ( nextChild . node ( ) . attributes ) ] ) ; if ( CdataTagsToValidate . hasOwnProperty ( tagName ) ) { calls . push ( [ amp . domwalker . HandlerCalls . CDATA , nextChild . node ( ) . textContent ] ) ; } tagStack . push ( nextChild ) ; } else { if ( tagStack . length > 1 ) { calls . push ( [ amp . domwalker . HandlerCalls . END_TAG , curState . node ( ) . nodeName ] ) ; } tagStack . pop ( ) ; } } for ( let i = 0 ; i < calls . length ; ++ i ) { switch ( calls [ i ] [ 0 ] ) { case amp . domwalker . HandlerCalls . START_TAG : handler . startTag ( calls [ i ] [ 1 ] , calls [ i ] [ 2 ] ) ; break ; case amp . domwalker . HandlerCalls . CDATA : handler . cdata ( calls [ i ] [ 1 ] ) ; break ; case amp . domwalker . HandlerCalls . END_TAG : handler . endTag ( calls [ i ] [ 1 ] ) ; break ; default : console . error ( calls [ i ] [ 0 ] ) ; break ; } } handler . endDoc ( ) ; }
Given a SAX-like {@code amp.htmlparser.HtmlSaxHandler}, enumerates the
 children of {@code rootDoc} and lets the {@code handler} know the
 structure while visiting the nodes.
Given a SAX - like { @code amp . htmlparser . HtmlSaxHandler } enumerates the children of { @code rootDoc } and lets the { @code handler } know the structure while visiting the nodes .
// TODO(gregable): Can we also implement // amp.htmlparser.HtmlSaxHandlerWithLocation easily? Not necessary give the // use case for this, but it might be nice to have if trivial. If we do, be // extra careful of the lower case conversions changing string lengths. // Apparently the !doctype 'tag' is not considered an element in the DOM, // so we can't see it naively. Unsure if there is a better approach here. // The approach here is to walk the DOM, generating handler calls which // we store but don't actually run. Then we make all of the handler calls // later in one go with no DOM accesses. This approach is hopefully cheaper // than DOM accesses interleaved with javascript calls. // Type of each array element is another array whose first element is a // amp.domwalker.HandlerCalls enum and whose later elements are arguments // to that Handlercall f'n. TODO(gregable): Make this a well-defined type. // The browser always returns upper case tag names. // Don't 'endTag' on the root element, which is a document fragment. // The browser always returns upper case tag names. /*OK*/