Created
January 18, 2018 08:25
-
-
Save hohoonlee/51cebf479f674be61624e371f84efee6 to your computer and use it in GitHub Desktop.
코드스피츠 3회차
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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