Reputation: 13
I want to generate an Array, that represent the structure of an ordered list.
The list could be something like:
<ol class="list">
<li><p>1</p>
<ol>
<li><p>1.1</p></li>
<li><p>1.2</p></li>
<li><p>1.3</p>
<ol>
<li><p>1.3.1</p></li>
</ol>
</li>
<li><p>1.4</p></li>
</ol>
</li>
<li><p>2</p></li>
<li><p>3</p></li>
</ol>
I use the following Javascript/Jquery function to traverse this list (based on this answer: https://stackoverflow.com/a/18084008/11995425 )
var count = 0;
var pages = [];
var parentStack = [];
var result = {};
parentStack.push(0);
function createNewLevel(obj) {
var obj = obj || $('.list');
if (obj.prop('tagName') == 'P') {
++count;
pages.push({
pId: parentStack[parentStack.length - 1],
urlStr: obj.text(), myId: count
});
}
if(obj.children().length > 0 ) {
obj.find('> li').each(function(i){
$(this).children().each(function(j){
if($(this).prop('tagName') == 'OL') {
parentStack.push(count);
}
createNewLevel($(this));
if($(this).prop('tagName') == 'OL') {
parentStack.pop();
}
});
})
}
}
createNewLevel();
This generates an array:
0: Object { pId: 0, urlStr: "1", myId: 1 }
1: Object { pId: 1, urlStr: "1.1", myId: 2 }
2: Object { pId: 1, urlStr: "1.2", myId: 3 }
3: Object { pId: 1, urlStr: "1.3", myId: 4 }
4: Object { pId: 4, urlStr: "1.3.1", myId: 5 }
5: Object { pId: 1, urlStr: "1.4", myId: 6 }
6: Object { pId: 0, urlStr: "2", myId: 7 }
7: Object { pId: 0, urlStr: "3", myId: 8 }
pId references myId as parent.
I am not able to transform this to an multi array. At the end i pass this array (json.stringify) via ajax to PHP. Optimally this array should be generated while running "createNewLevel". But it is also possible to transform it afterwards in PHP. The result should look like:
array(5) {
[0]=>
array(2) {
["desc"]=>
string(1) "1"
["children"]=>
array(0) {
}
}
[1]=>
array(2) {
["desc"]=>
string(1) "2"
["children"]=>
array(4) {
[0]=>
array(2) {
["desc"]=>
string(3) "2.1"
["children"]=>
array(0) {
}
}
[1]=>
array(2) {
["desc"]=>
string(3) "2.2"
["children"]=>
array(0) {
}
}
[2]=>
array(2) {
["desc"]=>
string(3) "2.3"
["children"]=>
array(3) {
[0]=>
array(2) {
["desc"]=>
string(5) "2.3.1"
["children"]=>
array(0) {
}
}
[1]=>
array(2) {
["desc"]=>
string(5) "2.3.2"
["children"]=>
array(0) {
}
}
[2]=>
array(2) {
["desc"]=>
string(5) "2.3.3"
["children"]=>
array(0) {
}
}
}
}
[3]=>
array(2) {
["desc"]=>
string(3) "2.4"
["children"]=>
array(0) {
}
}
}
}
[2]=>
array(2) {
["desc"]=>
string(1) "3"
["children"]=>
array(0) {
}
}
[3]=>
array(2) {
["desc"]=>
string(1) "4"
["children"]=>
array(0) {
}
}
[4]=>
array(2) {
["desc"]=>
string(1) "5"
["children"]=>
array(0) {
}
}
}
Upvotes: 1
Views: 121
Reputation: 122047
You can use reduce
method and recursion to generate nested structure based on your html. If child element has ol
then you call generate function where the element parameter will be that ol
element.
function generate(element, pid = 0) {
return [...element.children].reduce((r, li) => {
const p = li.querySelector('p');
const ol = li.querySelector('ol');
const obj = {pid};
if (p) obj.text = p.textContent;
if (ol) obj.children = generate(ol, pid + 1);
r.push(obj);
return r;
}, [])
}
const result = generate(document.querySelector('.list'))
console.log(JSON.stringify(result, 0, 4))
<ol class="list">
<li><p>1</p>
<ol>
<li><p>1.1</p></li>
<li><p>1.2</p></li>
<li><p>1.3</p>
<ol>
<li><p>1.3.1</p></li>
</ol>
</li>
<li><p>1.4</p></li>
</ol>
</li>
<li><p>2</p></li>
<li><p>3</p></li>
</ol>
Upvotes: 1