I can not figure out how to build json from ul .
There is a list of this type:

 <ul> <li data-id="1"><a>Родительский элемент списка 1</a> <ul> <li data-id="2">дочерний элемент списка 1</li> <li data-id="3">дочерний элемент списка 2</li> </ul> </li> <li data-id="4">Родительский элемент списка 2</li> <li data-id="5">Родительский элемент списка 3</li> </ul> 

Task: get from this json hierarchical :

 [{"id":1,"children":[{"id":2},{"id":3}]},{"id":4},{"id":5}] 
  • How have you tried to decide what did not work out? - Arnial

3 answers 3

Elements have a children property that allows you to access descendants.
It is worth using it.

 /** * Рекурсивно собираем все data-id с потомками * * @param {HTMLUListElement} ul UL-Контейнер с данными * @param {Boolean} json Вернуть собранный массив или его JSON-представление? * * @return {Array|String} */ function transform(ul, json = true) { let tree = []; /** * Наполнение дерева значениями * * @param {HTMLLIElement} e LI-элемент с data-id * @param {Array} ref Ссылка на дерево, куда добавлять свойства */ function push(e, ref) { let pointer = { // Берём атрибут id элемента id: +e.dataset.id }; if (e.childElementCount) { // Если есть потомки pointer.children = []; // Создаём свойство для них Array.from(e.children).forEach(i => { // Перебираем... хм... детей (по косточкам!) if (i.nodeName === 'UL') { // Если есть ещё один контейнер UL, перебираем его Array.from(i.children).forEach(e => { push(e, pointer.children); // Вызываем push на новых li, но ссылка на древо теперь - это массив children указателя }); } }); } ref.push(pointer); } // Проходимся по всем li переданного ul Array.from(ul.children).forEach(e => { push(e, tree); }); return json ? JSON.stringify(tree) : tree; } console.info(transform(document.querySelector('ul'))); 
 <ul> <li data-id="1"><a>Родительский элемент списка 1</a> <ul> <li data-id="2">дочерний элемент списка 1</li> <li data-id="3">дочерний элемент списка 2</li> <li data-id="8"> <ul> <li data-id="7">дочерний элемент списка 1</li> <li data-id="9">дочерний элемент списка 2</li> </ul> </li> </ul> </li> <li data-id="4">Родительский элемент списка 2</li> <li data-id="5">Родительский элемент списка 3</li> </ul> 

  • Everything is good and the correct json is obtained, but the extra children []. if (e.childElementCount>1) - Vladislav
  • @ Vladislav, no, descendants have only those where there is nesting, just now looked carefully. If e.childElementCount returns at least one descendant, there will be an array of children . Your pull request will not find a child if it is alone. Or do you need it? - user207618

For example, you can sometimes look towards the http://json2html.com/ service.

For example, they offer to do this in this form:

 {"<>":"ul","html":[ {"<>":"li","data-id":"1","html":[ {"<>":"a","html":"Родительский элемент списка 1"}, {"<>":"ul","html":[ {"<>":"li","data-id":"2","html":"дочерний элемент списка 1"}, {"<>":"li","data-id":"3","html":"дочерний элемент списка 2"} ]} ]}, {"<>":"li","data-id":"4","html":"Родительский элемент списка 2"}, {"<>":"li","data-id":"5","html":"Родительский элемент списка 3"} ]} 

    Another option using the map function and recursion.

     function transform(ul) { return [].map.call(ul.children, function(el) { var li = { id: el.dataset.id, }; var ul = el.querySelector('ul'); if (ul) { li.children = transform(ul); } return li; }); } console.log(transform(document.querySelector('ul'))); 
     <ul> <li data-id="1"><a>Родительский элемент списка 1</a> <ul> <li data-id="2">дочерний элемент списка 1</li> <li data-id="3">дочерний элемент списка 2</li> <li data-id="8"> <ul> <li data-id="7">дочерний элемент списка 1</li> <li data-id="9">дочерний элемент списка 2</li> </ul> </li> </ul> </li> <li data-id="4">Родительский элемент списка 2</li> <li data-id="5">Родительский элемент списка 3</li> </ul> 

    • Thank. Used your option. Only at the end of the function return JSON.stringify(li); - Vladislav
    • @ Vladislav, yes, you can, and so, if you need a line - Grundy