HTMLParser { public Document parse() { Document document = new Document(); stack.push(document); end: while (true) { HTMLTokenType type = lexer.nextNodeToken(); switch (type) { case EOF: break end; case TEXT: stack.peek().add(new Text(lexer.currentToken())); break; case START_COMMENT: lexer.nextEndCommentToken(); stack.peek().add(new Comment(lexer.currentToken())); break; case START_TAG: String tagName = validateTagName(lexer.currentToken().substring(1)); parseElement(tagName); break; case END_TAG: String endTag = lexer.currentToken(); String endTagName = validateTagName(endTag.substring(2, endTag.length() - 1)); if (voidElements.contains(endTagName)) throw new Error(format("void element must not have close tag, tag={}, location={}", endTagName, lexer.currentLocation())); closeTag(endTagName); break; default: throw new Error(format("unexpected type, type={}, location={}", type, lexer.currentLocation())); } } return document; } HTMLParser(TemplateSource source); Document parse();  }
@Test void voidElements() { String content = "<html><div><img src= Document document = new HTMLParser(new StringTemplateSource("test", content)).parse(); assertEquals(1, document.nodes.size()); Element html = (Element) document.nodes.get(0); assertEquals("html", html.name); assertEquals(1, html.nodes.size()); Element div = (Element) html.nodes.get(0); assertEquals("div", div.name); assertEquals(2, div.nodes.size()); assertTrue(div.hasEndTag); Element img = (Element) div.nodes.get(0); assertEquals("img", img.name); assertFalse(img.hasEndTag); assertEquals(" Text text = (Text) div.nodes.get(1); assertEquals("text", text.content); }
@Test void emptyScript() { String content = "<script type=\"text/javascript\"></script>"; Document document = new HTMLParser(new StringTemplateSource("test", content)).parse(); assertEquals(1, document.nodes.size()); Element script = (Element) document.nodes.get(0); assertEquals("script", script.name); assertTrue(script.nodes.isEmpty()); }