2014-01-10 5 views
1

Javascript의 UL 요소에서 JSON 개체를 작성하려고합니다.정렬되지 않은 목록을 JSON으로 변환

<ul id="trainingmenu"> 
    <li class="tmnode"><span id="M5lx9n" class="tmname">menu 1</span> 
     <ul> 
      <li class="tmnode"><span id="M66p48" class="tmname">menu 2</span> 
       <ul> 
        <li class="tmnode"><span class="tmname" id="Mschr">menu 3</span> 
        </li> 
       </ul> 
      </li> 
      <li class="tmnode"><span id="Mu03e0" class="tmname">menu 4</span></li> 
     </ul> 
    </li> 
</ul> 

이것은 JS입니다 :

var treeObject = {}; 

    function treeHTML(element, object) { 
     if (element.tagName=="UL") { element=element.firstChild; } 
     object["id"] = element.firstChild.id; 
     object["name"] = element.firstChild.innerHTML; 
     var nodeList = element.getElementsByTagName('LI'); 
     if (nodeList[0]) { 
      object["nodes"] = []; 
      for (var i = 0; i < nodeList.length; i++) { 
       object["nodes"].push({}); 
       treeHTML(nodeList[i], object["nodes"][object["nodes"].length - 1]); 
      } 
     } 
    } 
    treeHTML(document.getElementById("trainingmenu"), treeObject); 
    alert(JSON.stringify(treeObject)); 

.. 그리고 이것은 내가 갖는 출력입니다 :

{"id":"M5lx9n","name":"menu 1","nodes":[{"id":"M66p48","name":"menu 2","nodes":[{"id":"Mschr","name":"menu 3"}]},{"id":"Mschr","name":"menu 3"},{"id":"Mu03e0","name":"menu 4"}]} 

그것은 일부

나는이 목록의 구조 -working 그리고 이것은 내가 원하는 형식이다 - 각 LI 요소의 childNode에서 id와 name 필드를 고른다. 그러나 노드를 반복입니다 - 메뉴 3은 여기에 두 번

을 표시 아마 재귀를 망쳐했지만 2 일 동안 그것을 응시 한 fiddle

A는 방법을 근무 한 적이없는입니다. 누구든지 도와 줄 수 있습니까?

+1

FWIW, 나는 약간 코드가 전혀 작동 놀라게 해요 :

function treeHTML(element) { var o = {}; o.id = element.firstElementChild.id; o.name = element.firstElementChild.innerHTML; o.nodes = []; [].slice.call(element.children).filter(function(e) { return e.tagName.toLowerCase() === 'ul'; }).forEach(function(ul) { [].slice.call(ul.children).forEach(function(li) { o.nodes.push(treeHTML(li)); }); }); return o; } var treeObj = treeHTML(document.getElementById("trainingmenu") .firstElementChild); 

여기에 또한 IE의 이전 버전에서 작동합니다 대안 솔루션입니다. HTML 코드가 실제로 쓰여졌을 경우 바깥 쪽'ul'에서'element.firstChild'는'ul'과'li' 사이의 공백 텍스트 노드를 반환해야합니다. 새로운 브라우저에서는'.FirstElementChild'를 사용하여 텍스트 노드를 무시합니다. – Alnitak

+0

참 - 이는 읽기 쉽도록하기위한 것입니다. 나는 바이올린에서 휴식을 제거했습니다. 그러나, 나는 .firstElementChild (!)에 대해 몰랐다. 그래서 나는 거기에서 뭔가를 배웠다. 고마워. – WindsorAndy

+0

@WindsorAndy는 'firstElementChild'가 DOM 사양에 적당히 추가되었음을 잊지 않습니다. 이전 버전의 브라우저에는 존재하지 않을 수도 있습니다. – Alnitak

답변

1

Alnitak은 .getElementsByTagName() 메서드 대신 .children 또는 .childNodes 속성을 사용해야합니다. 다음 스 니펫은 ul 자식을 필터링하고 .forEach() 반복을 위해 Array 프로토 타입의 .filter() 메서드를 사용합니다.

function children(node, selector) { 
    var res = [], nodes = node.childNodes, l = nodes.length; 
    for (var i = 0; i < l; i++) { 
     if (nodes[i].nodeType === 1) { 
      if (selector && nodes[i].tagName.toLowerCase() === selector) { 
       res.push(nodes[i]); 
      } else if (!selector) { 
       res.push(nodes[i]); 
      } 
     } 
    } 
    return res; 
} 

function treeHTML(element) { 
    var o = {}; 
    var span = children(element, 'span'); 
    o.id = span[0].id; 
    o.name = span[0].innerHTML; 
    o.nodes = []; 
    var ul = children(element, 'ul'), n = ul.length; 
    for (var i = 0; i < n; i++) { 
     var li = children(ul[i]), l = li.length; 
     for (var j = 0; j < l; j++) { 
      o.nodes.push(treeHTML(li[j])); 
     } 
    } 

    return o;  
} 

var root = document.getElementById("trainingmenu"); 
var treeObj = treeHTML(children(root)[0]); 

http://jsfiddle.net/XZ54G/

+0

매우 우아한 해결 (BlackSheep). 이 질문은 나에게 JS 마스터 클래스로 바뀌고있다. – WindsorAndy

+0

@WindsorAndy 감사합니다. 도움이 되었기 때문에 기쁩니다. – undefined

+0

ES5 배열 함수를 shim 할 수는 있지만'firstElementChild'와'children'을 shim 할 수는 없습니다. – Alnitak

1

element.getElementsByTagName은 자식뿐만 아니라 모두이라는 후손이기 때문에 노드가 반복됩니다. 그걸 nodeList[i].parentNode == element으로 테스트하고 싶을 수도 있습니다.

또는 요소의 모든 하위 노드 (element.childNodes 또는 element.children)를 직접 반복하고 tagName == 'li' 인 노드를 찾으십시오. 올바른 형식의 HTML에서는 ul 요소의 하위 목록에서 (공백) 텍스트 노드와 li 요소 만 찾아야합니다.

+0

그 덕분에 .. 그 약속 유망. 그것을 테스트해라. – WindsorAndy

+0

... 그리고 주석 노드. –

+0

@JanDvorak 예, 그렇습니다! – Alnitak

관련 문제