참고 사이트 : https://d2.naver.com/helloworld/59361
위 사이트의 파싱 알고리즘 부터 읽어봤다.
http://htmlcxx.sourceforge.net/ > c++ html 파서
HTML 은 일반적인 하향식 또는 상향식 파서로 파싱이 안되는데 이유는 다음과 같다.
https://html.spec.whatwg.org/multipage/parsing.html > 파싱 알고리즘 설명 페이지
초기 상태는 "자료 상태" 이다. < 문자를 만나면 상태는 "태그 열림 상태"로 변한다. a 부터 z까지의 문자를 만나면 "시작
태그 토큰"을 생성하고 상태는 "태그 이름 상태"로 변하는데 이 상태는 > 문자를 만날 때까지 유지한다. 각 문자에는 새로운 토큰 이름이 붙는데 이 경우 생성된 토큰은 html 토큰이다.
문자에 도달하면 현재 토큰이 발행되고 상태는 다시 "자료 상태"로 바뀐다.
태그는 동일한 절차에 따라 처리된다. 지금까지 html 태그와 body 태그를 발행했고 다시 "자료 상태"로 돌아왔다.
Hello World의 H 문자를 만나면 문자 토큰이 생성되고 발행될 것이다. 이것은 종료 태그의 < 문자를 만날 때까지 진행된다. Hello World의 각 문자를 위한 문자 토큰을 발행할 것이다.
다시 "태그 열림 상태"가 되었다. / 문자는 종료 태그 토큰을 생성하고 "태그 이름 상태"로 변경 될 것이다. 이 상태는 > 문자를 만날 때까지 유지된다. 그리고 새로운 태그 토큰이 발행되고 다시 "자료 상태"가 된다. 또한 동일하게 처리될 것이다.
<html>
<mytag></mytag>
<div>
<p>
</div>
Really lousy HTML
</p>
</html>
mytag 는 표준 태그가 아니고 "p" 태그와 "div" 태그는 중첩 오류가 있다. 그러나 브라우저는 투덜거리지 않고 올바르게 표시한다.
이는 파서가 HTML 제작자의 실수를 수정했기 때문이다.
파서는 적어도 다음과 같은 오류를 처리해야 한다.
어떤 사이트는
대신
을 사용한다. 인터넷 익스플로러, 파이어폭스와 호환성을 갖기 위해 웹킷은 이것을
으로 간주한다.
if(t->isCloseTag(brTag) && m_document->inCompatMode()) {
reportError(MalformedBRError);
t->beginTag = true;
}
오류는 내부적으로 처리하고 사용자에게는 표시하지 않는다.
어긋난 표는 표 안에 또 다른 표가 th 또는 td 셀 내부에 있지 않은 것을 의미한다. 아래 예제와 같은 경우를 말한다.
<table>
<table>
<tr><td>inner table</td></tr>
</table>
<tr><td>outer table</td></tr>
</table>
이런 경우 웹킷은 표의 중첩을 분해하여 형제 요소가 되도록 처리한다.
<table>
<tr><td>outer table</td></tr>
</table>
<table>
<tr><td>inner table</td></tr>
</table>
코드는 다음과 같다.
if(m_inStrayTableContent && localName == tableTag)
popBlock(tableTag);
웹킷은 이런 오류를 처리하는데 스택을 사용한다. 안쪽의 표는 바깥쪽 표의 외부로 옮겨져서 형제 요소가 된다.
폼 안에 또 다른 폼을 넣은 경우 안쪽의 폼을 무시된다.
www.liceo.edu.mx 사이트는 약 1,500 개 수준의 태그 중첩이 되어 있는 예제인데 모든 요소가 로 되어있다.
최대 20개의 중첩만 허용하고 나머지는 무시한다.
bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName)
{
unsigned i = 0;
for (HTMLStackElem* curr = m_blockStack;
i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;
curr = curr->next, i++) { }
return i != cMaxRedundantTagDepth;
}
깨진 html 을 지원한다. 일부 바보 같은 페이지는 문서가 끝나기 전에 body 를 닫아버리기 때문에 브라우저는 body 태그를 닫지 않는다. 대신 종료를 위해 end() 를 호출한다.
if (t->tagName == htmlTag || t->tagName == bodyTag )
return;
unexpected-character-in-unquoted-attribute-value
This error occurs if the parser encounters a U+0022 ("), U+0027 ('), U+003C (<), U+003D (=), or U+0060 (`) code point in an unquoted attribute value.
The parser includes such code points in the attribute value.
Code points that trigger this error are usually a part of another syntactic construct and can be a sign of a typo around the attribute value.
U+0060 (`) is in the list of code points that trigger this error because certain legacy user agents treat it as a quote.
For example, consider the following markup:
<div foo=b'ar'>
Due to a misplaced U+0027 (') code point the parser sets the value of the "foo" attribute to "b'ar'".
태그의 의미를 존중하는 html 필터 만들기 - streaming 방식...
// This is a direct transcription of step 4 from:
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
static HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElement, bool reportErrors, const HTMLParserOptions& options)
{
if (!contextElement)
return HTMLTokenizer::DataState;
const QualifiedName& contextTag = contextElement->tagQName();
if (contextTag.matches(titleTag) || contextTag.matches(textareaTag))
return HTMLTokenizer::RCDATAState;
if (contextTag.matches(styleTag)
|| contextTag.matches(xmpTag)
|| contextTag.matches(iframeTag)
|| (contextTag.matches(noembedTag) && options.pluginsEnabled)
|| (contextTag.matches(noscriptTag) && options.scriptEnabled)
|| contextTag.matches(noframesTag))
return reportErrors ? HTMLTokenizer::RAWTEXTState : HTMLTokenizer::PLAINTEXTState;
if (contextTag.matches(scriptTag))
return reportErrors ? HTMLTokenizer::ScriptDataState : HTMLTokenizer::PLAINTEXTState;
if (contextTag.matches(plaintextTag))
return HTMLTokenizer::PLAINTEXTState;
return HTMLTokenizer::DataState;
}
<input class="download_button" onClick="javascript:urchinTracker('/downloads/314375');" type="submit" name="download" value="--> Stáhnout soubor <--" >