Рекурсивный поиск в объекте JSON или Javascript

Например:

[{
    id:'our-purpose',
    title:'Our Purpose',
    slug:'/our-purpose',
    backgroundImage:'images/bg-our-purpose.jpg',
    showInNav:1
  },
  {
    id:'our-people',
    title:'Our People',
    slug:'/our-people',
    backgroundImage:'images/bg-our-people.jpg',
    showInNav:1,
    subpages:[
      {
        id:'attorneys',
        title:'Attorneys',
        slug:'/our-people/attorneys',
        subpages:[
          {
            id:'attorneys-cdb',
            title:'Attorneys - Carla DeLoach Bryant',
            slug:'/our-people/attorneys/carla'
          },
          {
            id:'attorneys-jad',
            title:'Attorneys - Jordan A. DeLoach',
            slug:'/our-people/attorneys/jordan'
          },
          {
            id:'attorneys-shh',
            title:'Attorneys - Sarah H. Hayford',
            slug:'/our-people/attorneys/sarah'
          },
          {
            id:'attorneys-jsp',
            title:'Attorneys - Jason S. Palmisano',
            slug:'/our-people/attorneys/jason'
          },
          {
            id:'attorneys-ldw',
            title:'Attorneys - Lindsey DeLoach Wagner',
            slug:'/our-people/attorneys/carla'
          },
        ]
      },
      {
        id:'legal-support',
        title:'Legal Support',
        slug:'/our-people/legal-support',
        subpages:[
          {
            id:'legal-support-tb',
            title:'Legal Support - Theolyn Brock',
            slug:'/our-people/attorneys/theolyn'
          },
          {
            id:'legal-support-cd',
            title:'Legal Support - Cheri DeFries',
            slug:'/our-people/attorneys/cheri'
          },
        ]
      },
 //...and so on

Вы заметите, что можете сделать json[1].subpages[0].subpages[0], но я не знаю, насколько глубоко это будет. Это написано моим клиентом-дизайнером для сайта AJAX, который он создает для клиента. Я пытаюсь создать навигацию среди прочего и должен иметь возможность:

A. Разберите это рекурсивно, чтобы построить навигацию (<ul><li><a>...)

B. Найдите соответствующий идентификатор. Вот так (но это не рекурсивно) [и игнорируйте for...in, просто для примера)

var matchId(id,json){
  for(x in json){
    if(json[x].id == id){ var theMatch = json[x]; break; }
  }
}

person Oscar Godson    schedule 10.07.2011    source источник
comment
Я не вижу здесь вопроса. Вы, кажется, понимаете, как вам нужно это сделать.   -  person icktoofay    schedule 10.07.2011
comment
...? да, я понятия не имею, как сделать это рекурсивным   -  person Oscar Godson    schedule 10.07.2011


Ответы (5)


Этот код создает навигацию для вас:

function buildNavForNode(node) {
  var result = "<li id='" + node.id + "'><a href='" + node.slug + "'>" + node.title + "</a>";
  if(node.subpages == undefined) {
    return result + "</li>";
  } else {
    return result + buildNavForNodes(node.subpages) + "</li>";
  }
}


function buildNavForNodes(nodes) {
  var result = "<ul>";
  var i = 0;
  var len = nodes.length;
  for(; i < len; i++) {
    result += buildNavForNode(nodes[i]);
  }
  return result + "</ul>";
}

Вот как вы можете его использовать:

var testData = [
  {
    id:'our-purpose',
    title:'Our Purpose',
    slug:'/our-purpose',
    backgroundImage:'images/bg-our-purpose.jpg',
    showInNav:1
  },
  {
    id:'our-people',
    title:'Our People',
    slug:'/our-people',
    backgroundImage:'images/bg-our-people.jpg',
    showInNav:1,
    subpages:[
      {
        id:'attorneys',
        title:'Attorneys',
        slug:'/our-people/attorneys',
        subpages:[
          {
            id:'attorneys-cdb',
            title:'Attorneys - Carla DeLoach Bryant',
            slug:'/our-people/attorneys/carla'
          },
          {
            id:'attorneys-jad',
            title:'Attorneys - Jordan A. DeLoach',
            slug:'/our-people/attorneys/jordan'
          },
          {
            id:'attorneys-shh',
            title:'Attorneys - Sarah H. Hayford',
            slug:'/our-people/attorneys/sarah'
          },
          {
            id:'attorneys-jsp',
            title:'Attorneys - Jason S. Palmisano',
            slug:'/our-people/attorneys/jason'
          },
          {
            id:'attorneys-ldw',
            title:'Attorneys - Lindsey DeLoach Wagner',
            slug:'/our-people/attorneys/carla'
          },
        ]
      },
      {
        id:'legal-support',
        title:'Legal Support',
        slug:'/our-people/legal-support',
        subpages:[
          {
            id:'legal-support-tb',
            title:'Legal Support - Theolyn Brock',
            slug:'/our-people/attorneys/theolyn'
          },
          {
            id:'legal-support-cd',
            title:'Legal Support - Cheri DeFries',
            slug:'/our-people/attorneys/cheri'
          },
        ]
      }
    ]
  }
];

$(function(){
  htmlToInsert = buildNavForNodes(testData);
  console.log(htmlToInsert);
  $('body').html(htmlToInsert);
});

Вы можете легко сделать это с помощью рекурсивной функции, но я думаю, что это хорошо разграничивает обязанности между выяснением того, что делать с набором страниц, и обработкой одной страницы.

person Joseph Jaramillo    schedule 10.07.2011
comment
Кажется, близко, но вот мой полный фид: gist.github.com/8a9a80f8bccbb0a8136e, и код останавливается после OurPeople и перечисление его подстраниц - person Oscar Godson; 11.07.2011

Вот начало (в некотором сочетании JavaScript и псевдокода):

function createMenu(data) {
    create UL
    for each item in data {
        create LI for item in UL
        if the item has subpages {
            append createMenu(item.subpages) to the LI
        }
    }
    return UL
}

function findByID(data, id) {
    for each item in data {
        if(item.id==id) {
            return the item
        }
        if item has subpages {
            if findByID(item.subpages, id) is not null, return the result
        }
    }
    return null;
}
person icktoofay    schedule 10.07.2011
comment
Просто имейте в виду, что for each...in — это только Mozilla. Это не часть ECMAScript. - person user113716; 10.07.2011
comment
@patrick: я даже не знал, что это действительный JavaScript. Я сказал, что это псевдокод... - person icktoofay; 10.07.2011
comment
А, я думал, вы ссылаетесь на: developer.mozilla.org/ ru/JavaScript/Reference/Statements/ - person user113716; 10.07.2011

Я бы попробовал JSONPath, вы можете найти код здесь.

person KARASZI István    schedule 10.07.2011
comment
JSONPath возвращает только массив совпадающих элементов, а не совпадающие объекты? Я мог бы использовать это неправильно, хотя. - person Oscar Godson; 11.07.2011

Я сгенерировал навигацию с помощью этого кода, так как мне нужен был только первый уровень:

$('#sidebar').append('<ul></ul>');

for(x in PAGES){
  if(PAGES[x].showInNav == 1){
    $('#sidebar > ul').append('<li data-id="'+PAGES[x].id+'"><a href="#!'+PAGES[x].slug+'">'+PAGES[x].title+'</a></li>');
    if(PAGES[x].subpages){
      $('#sidebar > ul > li:last').append('<ul></ul>');
      for(y in PAGES[x].subpages){
        $('#sidebar > ul > li:last > ul').append('<li data-id="'+PAGES[x].subpages[y].id+'"><a href="#!'+PAGES[x].subpages[y].slug+'">'+PAGES[x].subpages[y].title+'</a></li>');
      }
    }
  }
}

Затем для рекурсивной функции сопоставления я получил этот код:

var matchKey = function(k,v,j){  
  k = k || 'id';  //key
  v = v || '';    //value
  j = j || PAGES; //json
  for(x in j){
    if(j[x][k] == v){
      return j[x];
    }
    if(j[x].subpages){
      var result = matchKey(k,v,j[x].subpages);
      if(result !== undefined){
        return result;
      }
    }
  }
}
person Oscar Godson    schedule 10.07.2011

person    schedule
comment
@icktoofay, правда, но эта функция должна работать независимо. Выполнение JSON.stringify(matchId('foo', [{ x: { id: 'foo', arr: [1, 2, 3] } }])) в squarefree.com/shell/shell.html дает мне {"id":"foo","arr":[1,2,3]} - person Mike Samuel; 10.07.2011
comment
О, я забыл typeof [] === "object". Извиняюсь. - person icktoofay; 10.07.2011
comment
@icktoofay, да. typeof сбивает с толку. Есть несколько предложений по новым версиям языка, чтобы сделать его более понятным: wiki.ecmascript.org/, но IIRC ни один из них не обращается к массивам. - person Mike Samuel; 10.07.2011
comment
моя лента: gist.github.com/8a9a80f8bccbb0a8136e -- Спасибо, я на правильном пути и В итоге я написал это до сих пор, у меня есть это: gist.github.com/ec6929feaaa65bc3a245, но когда я это делаю , допустим: var thePage = matchId('id','attorneys-cdb'); console.log(thePage.slug); я получаю Uncaught TypeError: Cannot read property 'slug' of undefined - person Oscar Godson; 10.07.2011
comment
Не берите в голову. Глупая ошибка. Забыл .subpages внутри рекурсивной части :) - person Oscar Godson; 10.07.2011