Skip to content

Instantly share code, notes, and snippets.

@hohoonlee
Created January 18, 2018 08:25
Show Gist options
  • Select an option

  • Save hohoonlee/51cebf479f674be61624e371f84efee6 to your computer and use it in GitHub Desktop.

Select an option

Save hohoonlee/51cebf479f674be61624e371f84efee6 to your computer and use it in GitHub Desktop.
코드스피츠 3회차
const addNode = (node, target) => {
if(!target.tag.children) target.tag.children = []
target.tag.children.push(node)
}
const makeNode = (type, text) => {
let result = {tag:{type}}
if (!text) return result
if(typeof text === 'string') {
result.tag.text = text
}else {
for (var key in text) {
result.tag[key] = text[key]
}
}
return result
}
const parsingTag = (html, cursor) => {
let result = {}
let tagName = html.substring(++cursor, cursor = html.indexOf('>', cursor)) //<다음 부터 >전까지 ...
result.cursor = cursor +1
if(tagName[tagName.length-1] === '/') { //자체종료태그 <img/>
tagName = tagName.substring(0, tagName.length -1)
result.isSingle = true
}
if(tagName[0] === '/') { //종료태그 </div>
tagName = tagName.substring(1)
result.isClose = true
}
if(tagName.indexOf(' ') > 0) { //attr가 있다면
let attr = {}
for (var s of tagName.split(' ') ) {
if(!result.name) {
result.name = s
}else {
if(s.indexOf('=') > 0) {
let ss = s.split('=', 2)
attr[ss[0]] = ss[1].replace(/"/g, '')
}else {
attr[s] = s
}
}
}
result.attr = attr;
}
if(!result.name) result.name = tagName
return result
}
const processTagNode = (html, cursor, currentNode, stacks) => {
let tag = parsingTag(html, cursor)
if(tag.isSingle) { //스스로 닫힌 태그는 현재 스택에 추가한다.
addNode(makeNode(tag.name, tag.attr), currentNode)
}else if(tag.isClose) { //끝나는 태그인 경우 부모에게 현재 스택을 추가한다.
let parent = stacks.pop()
addNode(currentNode, parent)
currentNode = parent
}else { //열린태그인 경우 현재 node를 stack에 추가하고 현재 노드에 작업을 시작한다.
stacks.push(currentNode)
currentNode = makeNode(tag.name, tag.attr)
}
return {cursor:tag.cursor, currentNode, stacks} //>까지 이동
}
const precessTextNode = (html, cursor, stack) => {
addNode(
makeNode('text', html.substring(cursor, cursor = html.indexOf('<', cursor))),
stack
)
return cursor++
}
const parser = html => {
const result = {tag:{type:'root'}}
let cursor = 0
let currentNode = result, stacks = []
while(cursor < html.length) {
if(html[cursor] === '<') { //태그시작 && text Node 종료
({cursor, currentNode, stacks} = processTagNode(html, cursor, currentNode, stacks))
}else { //text node
cursor = precessTextNode(html, cursor, currentNode)
}
}
return result
}
[
// 01234567890123456789012
'<div name="123">a</div>',
'<div>a<img src="abcd"/><a>b</a></div>',
'<div>test<img/></div>',
'<div>test<span><a href="#" diabled>aa</a></span>bb</div>',
'<ul><li>test 1</li><li>test 2</li><li>test 3</li></ul>'
].forEach(str=>{
console.log(str)
console.log(JSON.stringify(parser(str)))
console.log('----------------------')
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment