[F-Lab 모각코 챌린지 6일차]

milknsoda·2023년 6월 6일
0

F-Lab

목록 보기
4/5

TIL

HTML 파싱
1. DTD
2. 토큰화
3. 트리 구축

1. HTML 파싱

HTML은 일반적인 파서로는 파싱이 불가능하다고 한다.
그렇다면 어떻게 파싱이 이루어질까.

1-1. DTD (Document Type Definition)

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>만 입력하는 것으로 충분하다.

1-2. HTML 파서

HTML 파싱이 어려운 이유

  1. 태그 생략이 가능해 일반적인 파서를 사용한 구문 규칙 적용이 어렵다.
  2. 스크립트를 통해 태그가 추가될 수 있어, 재파싱이 이루어지게 된다. ( document.write() )

HTML 파싱 과정

HTML 파싱은 크게 2가지의 과정으로 구성되어 있다.

1. 토큰화

통신 과정을 거쳐 받은 입력값(HTML)은 어휘 분석을 통해서 토큰으로 해석된다.

HTML에서의 토큰은 시작태그, 종료태그, 속성 이름과 값으로 구성된다.

각 문자를 순서대로 읽어오며, 읽어오는 문자에 따라 상태를 달리하면서 토큰을 생성하고 생성된 토큰은 트리를 구성하기 위해 사용된다.

<html>
  <body>
    <div><img src="https://velog.velcdn.com/images/milknsoda/post/c9f01db5-f4ae-4b13-8aa3-138ed4d60b69/image.png" /></div>
  </body>
</html>

예를 들면 위 코드에서 첫 문자 < 문자를 만나면 태그 열림상태로 변경되면서 다음 > 문자를 만날 때까지 만난 모든 문자는 태그 이름 및 속성으로 감지하여 처리한다.

2. 트리 구축

토큰화 알고리즘을 통해 생성된 토큰은 트리 구축을 위해 순차적으로 소비된다.

단, 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 닫힘

실제로 브라우저에 위 코드를 적용시켜보면 자동으로 생성된 headp 태그를 확인할 수 있다.

이러한 자동 교정은 다음과 같은 규칙을 따른다.

  1. 어떤 태그 안쪽에 추가하려는 태그가 허용되지 않을 때, 일단 가능한 태그를 닫은 후, 허용되지 않은 태그는 바깥으로 추가한다.
  2. 일부 요소는 파서를 통해 직접 추가되지 않고 생략 가능하다.
    ( HTML, HEAD, BODY, TBODY, TR, TD, LI )
  3. 인라인 요소 안에 블록 요소를 포함하는 경우, 블록인 부모 요소를 만날 때까지 인라인 요소를 닫는다.
  4. 위 규칙에 해당하지 않는 경우에는 태그를 추가하거나 무시할 수 있을 때까지 만나는 모든 태그를 닫는다.

참고
브라우저는 어떻게 동작하는가?
(Web) DTD(Document Type Definition)란?
HTML - Living Standard

0개의 댓글