DOM 노드 및 탐색


이번 포스트에서는 공백버그에 대한 내용과 유사한 DOM 노드에 대해 간단히 설명하고 노트 탐색에 필요한 속성값을 알아 보도록 하겠습니다.
 

먼저 DOM에 대해 간단히 정리하자면, XML 구조를 탐색 가능한 트리 형태로 표현하며, 그 최상위 객체로는 문서 엘리먼트
(document documentElement)라고 부르는 단일 노드가 있습니다.
 

또한, 각 노드에는 타입을 반환하는 속성인 node.nodeType이 존재하며, 대표적인 타입으로는 Element, #text, document Element 가 있습니다.

그리고 자신의 직접적인 관계를(부모, 자식, 형제) 가리키는 포인터들과 또 그에 대해 접근할 수 있는 속성들은 아래와 그림과 같이 존재 합니다.





#DOM 트리 구조 관계도




#노드들에 직접 접근할 수 있는 속성들입니다.


  1. document: 문서 자체
  2.  
  3. document.documentElement: 문서의 최상위 루트 엘리먼트 (HTML)
  4.  
  5. parentNode: 부모 엘리먼트
  6.  
  7. previousSibling: 이전 형제 엘리먼트
  8.  
  9. nextSibling: 다음 형제 엘리먼트
  10.  
  11. firstChild: 첫번째 자식 엘리먼트
  12.  
  13. lastChild: 마지막 자식 엘리먼트
  14.  
  15. childNodes: 자식 엘리먼트 집합



그럼 위에 내용을 바탕으로 아래 HTML 코드에 대한 브라우져별 생성 노드에 대해 알아보도록 하겠습니다.

  1. <div>hello<span><strong>wolrd</strong></span></div>



#IE 기준
[body --> div --> #text --> span --> strong --> #text]




#표준 브라우저(FF, Chrome, Safari)
body --> #text(공백버그) --> div --> #text --> span --> strong --> #text --> #text(공백버그)


#Chrome








#FF






위에서도 알 수 있듯이 비표준브라우저와 표준브라우저의 차이점으로는 명백히 공백 버그가 존재하며, 다른점 또한 아래와 같이 존재합니다.


다른점을 알아보기 위해 각 엘리먼트를 nodeType으로 분류한 표를 보시겠습니다.

 

위에서도 볼 수 있듯이 엘리먼트에 대한 계산 여부 또한 브라우저별로 다르다는 것을 한눈에 알 수 있습니다.

또한, 노드타입은 총 12가지로 나뉘지만 실제로 HTML 상에서 다룰 수 있는 타입은 몇 개 되지 않으며, 그중에서도
보통 1번 타입인 Element 노드와 3번 타입인 #text 노드를 노드 탐색 시 주로 다루게 됩니다.








아래 작성된 코드는 노드 탐색에 필요한 함수를 모듈화한 소스입니다.



  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <TITLE> New Document </TITLE>
  5. <META NAME="Generator" CONTENT="EditPlus">
  6. <META NAME="Author" CONTENT="">
  7. <META NAME="Keywords" CONTENT="">
  8. <META NAME="Description" CONTENT="">
  9. </HEAD>
  10. <BODY>
  11. <script>
  12. var nodes = (function(){
  13.    
  14.     return new (function()
  15.     {  
  16.         function t(){
  17.             return this;
  18.         }
  19.         t.prototype = {
  20.             first: first,
  21.             last: last,
  22.             prev: prev,
  23.             next: next,
  24.             chlid: chlid,
  25.             parent: parent,
  26.             get: get
  27.         }
  28.             return t;
  29.         }());
  30.  
  31.  
  32.         function first(elem){
  33.             elem = elem && elem.firstChild || document.documentElement.firstChild;
  34.             this[0] = elem && elem.nodeType !== 1 ? this.next(elem).get(0) : elem;
  35.             return this;
  36.         };
  37.  
  38.         function last(elem){
  39.             elem = elem && elem.lastChild || document.documentElement.lastChild;
  40.             this[0] = elem && elem.nodeType !== 1 ? this.prev(elem).get(0) : elem;
  41.             return this;
  42.         };
  43.  
  44.         function prev(elem){
  45.             elem = elem || document.documentElement;
  46.             do{
  47.             elem = elem.previousSibling;
  48.             }
  49.             while(elem && elem.nodeType !== 1)
  50.             this[0] = elem;
  51.             return this;
  52.         };
  53.  
  54.         function next(elem){
  55.             elem = elem || document.documentElement;
  56.             do{
  57.             elem = elem.nextSibling;
  58.             }
  59.             while(elem && elem.nodeType !== 1)
  60.  
  61.             this[0] = elem;
  62.             return this;
  63.         };
  64.        
  65.         function chlid(elem){
  66.             elem = elem || document.documentElement;
  67.             var childs = [];
  68.             for (var i = 0, length = elem.childNodes.length; i < length; i++){
  69.             var child = elem.childNodes[i];
  70.             if (child && child.nodeType === 1) childs.push(child);
  71.             }
  72.             this[0] = childs;
  73.             return this;
  74.         };
  75.  
  76.         function parent(elem){
  77.             elem = elem || document.documentElement;
  78.             var parents = [];
  79.             do{
  80.             elem = elem.parentNode;
  81.             if (elem.nodeType === 1) parents.push(elem);
  82.             }
  83.             while(elem && elem.nodeType === 1)
  84.             this[0] = parents;
  85.             return this;
  86.         };
  87.  
  88.         function get(index){
  89.             index = index || 0;
  90.             return this[0] && this[0].length > 0 ? this[0][index] : this[0];
  91.         };
  92. }());
  93. window.onload = function()
  94. {
  95.     alert(nodes.first(document.body).get(0).nodeName); // script
  96.     alert(nodes.last(document.body).get(1).nodeName); // div
  97.     alert(nodes.prev().get()) // null
  98.     alert(nodes.prev(document.body).get(0).nodeName); // head
  99.     alert(nodes.next(document.getElementById('test1')).get(0).nodeName); // div
  100.     alert(nodes.last(document.body).get(2).nodeName); // div
  101.     alert(nodes.chlid().get(1).nodeName); // body
  102.     alert(nodes.parent(document.getElementById('test3')).get(1).nodeName); // html
  103. };
  104. </script>
  105. <div id="test1">
  106. <div id="test2">test2</div>
  107. </div>
  108. <div id="test3">test3</div>
  109. </BODY>
  110. </HTML>



Node 모듈의 각 함수들의 기능은 아래와 같습니다.

  1. #first: 해당 엘리먼트의 첫번째 엘리먼트 반환
  2.  
  3. #last: 해당 엘리먼트의 마지막 엘리먼트 반환
  4.  
  5. #prev: 해당 엘리먼트의 이전 형제 엘리먼트 반환
  6.  
  7. #next: 해당 엘리먼트의 다음 형제 엘리먼트 반환
  8.  
  9. #chlid: 해당 엘리먼트의 자식 엘리먼트 집합 반환
  10.  
  11. #parent: 해당 엘리먼트의 부모 엘리먼트 집합 반환