HTML 파싱
1. DTD
2. 토큰화
3. 트리 구축
HTML은 일반적인 파서로는 파싱이 불가능하다고 한다.
그렇다면 어떻게 파싱이 이루어질까.
HTML 파일에서 가장 많이 보이지만, 많은 IDE에서 구조를 자동 혹은 손쉽게 생성해주는 숏컷이 많아 생략하게 되는 내용이 있다. (현재 사용중인 vscode에서도 ! + tab
을 통해 기본적인 HTML 구조를 만들 수 있다.)
<!DOCTYPE html>
<html>
<head>
...
바로 <!DOCTYPE html>
.
너무 자연스럽게 자리잡고 있다보니 그동안 의식하지 않고 있던 부분이기도 하다.
<!DOCTYPE html>
은 HTML DTD라고 하며, 간단하게 말하자면 이 파일은 HTML 문서 형식을 따른다는 의미다.
HTML DTD는 SGML 계열 언어로 정의되어 있고, SGML은 문서용 마크업 언어를 정의하기 위한 메타 언어이다.위키백과-SGML
HTML 4.01 Strict
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
HTML 4.01 Transitional
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
HTML 4.01 Frameset
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" http://www.w3.org/TR/html4/frameset.dtd">
XHTML 1.0 Strict
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
XHTML 1.0 Transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
XHTML 1.0 Frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
XHTML 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
HTML5
<!DOCTYPE html>
HTML5 이전의 HTML은 Strict
, Frameset
, Transitional
의 3가지 모드가 있어, DTD URL을 포함해야 했지만 HTML5 부터는 간소화되어 단순히 <!DOCTYPE html>
만 입력하는 것으로 충분하다.
document.write()
)HTML 파싱은 크게 2가지의 과정으로 구성되어 있다.
통신 과정을 거쳐 받은 입력값(HTML)은 어휘 분석을 통해서 토큰으로 해석된다.
HTML에서의 토큰은 시작태그, 종료태그, 속성 이름과 값으로 구성된다.
각 문자를 순서대로 읽어오며, 읽어오는 문자에 따라 상태를 달리하면서 토큰을 생성하고 생성된 토큰은 트리를 구성하기 위해 사용된다.
<html>
<body>
<div><img src="https://velog.velcdn.com/images/milknsoda/post/c9f01db5-f4ae-4b13-8aa3-138ed4d60b69/image.png" /></div>
</body>
</html>
예를 들면 위 코드에서 첫 문자 <
문자를 만나면 태그 열림상태로 변경되면서 다음 >
문자를 만날 때까지 만난 모든 문자는 태그 이름 및 속성으로 감지하여 처리한다.
토큰화 알고리즘을 통해 생성된 토큰은 트리 구축을 위해 순차적으로 소비된다.
단, HTML의 '너그러운' 속성은 이 과정에서 교정을 포함한다.
위 HTML 코드를 예로 들면,
스택 | 토큰 | 상태 |
---|---|---|
<html> | html 내부 | |
<html> | <body> | ( head -> ) body 내부 (자동 교정) |
<html> <body> | <div> | body 내부 -> div 내부 |
<html> <body> <div> | div 내부 -> img | |
<html> <body> <div> | </div> | div 닫힘 |
<html> <body> | </body> | body 닫힘 |
<html> | </html> | html 닫힘 |
HTML의 구조에 따르면 html
태그 안에는 body
이전에 head
태그가 존재해야 하지만 자동 교정을 통해서 없는 태그를 지나쳐 body
태그를 진행한다.
태그의 열림, 닫힘 순서가 맞지 않아 중첩되는 경우는 어떻게 처리될까.
<html>
<body>
<div> <!-- div 태그 열림 -->
<p> <!-- p 태그 열림 -->
</div> <!-- div 태그 닫힘 -->
</p> <!-- p 태그 닫힘 -->
</body>
</html>
실제 브라우저는 이런 식으로 작성된 파일이더라도 별다른 오류없이 화면을 그려낸다.
스택 | 토큰 | 상태 |
---|---|---|
<html> | html 내부 | |
<html> | <body> | ( head -> ) body 내부 (자동 교정) |
<html> <body> | <div> | body 내부 -> div 내부 |
<html> <body> <div> | <p> | div 내부 -> p 내부 |
<html> <body> <div> <p> | </div> | ( p 닫힘 -> ) div 닫힘 (자동 교정) |
<html> <body> | </p> | ( p 열림 ) -> p 닫힘 (자동 교정) |
<html> <body> | </body> | body 닫힘 |
<html> | </html> | html 닫힘 |
실제로 브라우저에 위 코드를 적용시켜보면 자동으로 생성된 head
와 p
태그를 확인할 수 있다.
이러한 자동 교정은 다음과 같은 규칙을 따른다.
참고
브라우저는 어떻게 동작하는가?
(Web) DTD(Document Type Definition)란?
HTML - Living Standard