如何创建可以处理条件的JSON对象?

时间:2013-11-18 16:23:01

标签: javascript json

我想创建一个可以处理条件/分支的JSON对象。具体来说,我有如下工作流程:

enter image description here

对于第1步,用户有三个选择,根据他们的选择,他们会在步骤2中看到不同的选择。同样的逻辑延伸到第3步等。

理想情况下,我希望以JSON格式获取所有这些数据,以便我可以根据用户的选择进行循环,找出接下来要向他们提出的选择。

有没有办法以允许我这样做的方式构造JSON对象(或者可能只是一个数组)?

我应该提一下,我希望它足够灵活,以便如果我稍后决定改变一个步骤的选择数量,那么我所要做的就是修改JSON对象/数组(模型),而不必修改循环通过对象/数组的逻辑。

非常感谢。

3 个答案:

答案 0 :(得分:8)

您正在构建的内容本质上是一种树数据结构。我建议从原始的节点对象构建它,而不是包含对同一类型的子对象的递归引用。只使用这种类型的对象就可以实现完全树,其中“最顶层”对象称为根对象,其中所有用户都开始进行选择。从根开始,用户选择子节点,直到它们到达没有子节点的叶节点,即从那里无法进一步选择。

所有节点都是这样的对象:

{
    "label": "Choice A",
    "question": "Choose subselection?",
    "children": [ (array of more objects of the same type) ]
}

如果label是您要为此选项指定的名称/标签,question是用户必须回答以选择下一个子节点的下一个问题,children是一个数组更多相同类型的节点,其中每个子节点label是该节点question的一个可能答案。

为了举例说明,让我们假设以下选择树,可以在想象中的在线零售商店中询问,它只销售两种主要类型的产品:服装和食品。在服装部分,有牛仔裤,T恤和不同颜色的连帽衫(为简单起见,我们假设我们已经知道客户的尺寸。)商店还提供少量类型的帽子。在食品部分,有拉面,不同口味的苏打水和香蕉。在服装部分,顾客可以在他们的黑色T恤上印上电视节目或摇滚乐队的标志,或者只买一件没有标志的黑色T恤。电视节目的标志还可以印在蓝色连帽衫上,或者顾客可以选择购买没有标志的蓝色连帽衫。

因此,面向客户的答案/问题对的决策树如下:

A: <start>
Q: What product category?
|
|--A: Clothes
|  Q: What type of clothing?
|  |    
|  |--A: Jeans
|  |  Q: Color of jeans?
|  |  |
|  |  |--A: Blue
|  |  |  Q: <end>
|  |  |
|  |  |--A: Black
|  |  |  Q: <end>
|  |  |
|  |  \--A: White
|  |     Q: <end>
|  | 
|  |--A: Shirt
|  |  Q: Type of shirt?
|  |  |
|  |  |--A: T-shirt
|  |  |  Q: Color of T-shirt?
|  |  |  |
|  |  |  |--A: Red
|  |  |  |  Q: <end>
|  |  |  |
|  |  |  |--A: Green
|  |  |  |  Q: <end>
|  |  |  |
|  |  |  |--A: Black
|  |  |  |  Q: Logo?
|  |  |  |  |
|  |  |  |  |--A: Rock band
|  |  |  |  |  Q: <end>
|  |  |  |  |
|  |  |  |  |--A: TV show
|  |  |  |  |  Q: <end>
|  |  |  |  |
|  |  |  |  \--A: No logo
|  |  |  |     Q: <end>
|  |  |  |
|  |  |  \--A: Orange
|  |  |     Q: <end>
|  |  |
|  |  \--A: Hoodie
|  |     Q: Color of hoodie?
|  |     |
|  |     |--A: Gray
|  |     |  Q: <end>
|  |     |
|  |     |--A: Blue
|  |     |  Q: Logo for hoodie?
|  |     |  |
|  |     |  |--A: TV show
|  |     |  |  Q: <end>
|  |     |  |
|  |     |  \--A: No logo
|  |     |     Q: <end>
|  |     |
|  |     |--A: Green
|  |     |  Q: <end>
|  |     |
|  |     |--A: Pink
|  |     |  Q: <end>
|  |     |
|  |     |--A: Brown
|  |     |  Q: <end>
|  |     |
|  |     |--A: Black
|  |     |  Q: <end>
|  |     |
|  |     \--A: Red
|  |        Q: <end>
|  |
|  \--A: Hat
|     Q: Type of hat?
|     |
|     |--A: Stetson
|     |  Q: <end>
|     |
|     \--A: Sombrero
|        Q: <end>
|
\--A: Food
   Q: Type of food?
   |
   |--A: Ramen noodles
   |  Q: <end>
   |
   |--A: Soda pop
   |  Q: Flavor
   |  |
   |  |--A: Cola
   |  |--Q: <end>
   |  |
   |  |--A: Lemon
   |  |--Q: <end>
   |  |
   |  |--A: Orange
   |  |--Q: <end>
   |  |
   |  |--A: Apple
   |  \--Q: <end>
   |
   \--A: Bananas
      Q: <end>

客户从“回答”<start>开始,选择多项选择题,直到他们到达具有特殊“问题”<end>的节点。

当我们将此树映射到JSON时,询问用户感兴趣的产品类别(衣服/食品)的根问题(上面的<start>)可以具有标签值null,因为它不是任何其他问题的答案(孩子)。它是整个结构的第一个对象,所有其他节点都是它的子节点。通过使用<end>代替null字符串和question数组,可以指示无法进一步选择(上面children)的叶节点。所有其他节点指定标签字符串(节点“回答”的顶级问题),下一个问题以及问题的可能答案数组:

{
 "label": null,
 "question": "What product category?",
 "children": [
  {
   "label": "Clothes",
   "question": "What type of clothing?",
   "children": [
    {
     "label": "Jeans",
     "question": "Color of jeans?",
     "children": [
      {
       "label": "Blue",
       "question": null,
       "children": null
      },
      {
       "label": "Black",
       "question": null,
       "children": null
      },
      {
       "label": "White",
       "question": null,
       "children": null
      }
     ]
    },
    {
     "label": "Shirt",
     "question": "Type of shirt?",
     "children": [
      {
       "label": "T-Shirt",
       "question": "Color of T-shirt?",
       "children": [
        {
         "label": "Red",
         "question": null,
         "children": null
        },
        {
         "label": "Green",
         "question": null,
         "children": null
        },
        {
         "label": "Black",
         "question": "Logo?",
         "children": [
          {
           "label": "Rock band",
           "question": null,
           "children": null
          },
          {
           "label": "TV show",
           "question": null,
           "children": null
          },
          {
           "label": "No logo",
           "question": null,
           "children": null
          }
         ]
        },
        {
         "label": "Orange",
         "question": null,
         "children": null
        }
       ]
      },
      {
       "label": "Hoodie",
       "question": "Color of hoodie?",
       "children": [
        {
         "label": "Gray",
         "question": null,
         "children": null
        },
        {
         "label": "Blue",
         "question": null,
         "children": [
          {
           "label": "TV show",
           "question": null,
           "children": null
          },
          {
           "label": "No logo",
           "question": null,
           "children": null
          }
         ]
        },
        {
         "label": "Green",
         "question": null,
         "children": null
        },
        {
         "label": "Pink",
         "question": null,
         "children": null
        },
        {
         "label": "Brown",
         "question": null,
         "children": null
        },
        {
         "label": "Black",
         "question": null,
         "children": null
        },
        {
         "label": "Red",
         "question": null,
         "children": null
        }
       ]
      },
      {
       "label": "White",
       "question": null,
       "children": null
      }
     ]
    },
    {
     "label": "Hat",
     "question": "Type of hat?",
     "children": [
      {
       "label": "Stetson",
       "question": null,
       "children": null
      },
      {
       "label": "Sombrero",
       "question": null,
       "children": null
      }
     ]
    }
   ]
  },
  {
   "label": "Food",
   "question": "Type of food?",
   "children": [
    {
     "label": "Ramen noodles",
     "question": null,
     "children": null
    },
    {
     "label": "Soda pop",
     "question": null,
     "children": [
      {
       "label": "Cola",
       "question": null,
       "children": null
      },
      {
       "label": "Lemon",
       "question": null,
       "children": null
      },
      {
       "label": "Orange",
       "question": null,
       "children": null
      },
      {
       "label": "Apple",
       "question": null,
       "children": null
      }
     ]
    },
    {
     "label": "Bananas",
     "question": null,
     "children": null
    }
   ]
  }
 ]
}

以上是100%有效的JSON:您可以将其复制并粘贴到JSONtree以逐级调查其结构。

故事的士气是,这种可能非常复杂的可用用户选择和路径系统,可以在其核心(带有叶子的节点)上以令人惊讶的简单数据结构实现。复杂性源于您在节点之间定义的 relationship

答案 1 :(得分:0)

用JSON表达你的树结构是微不足道的。每个问题节点中的路径选择集是一个问题节点数组。这是一种经典的递归数据结构。

在您的JSON中执行此操作,然后在其旁边添加另一个分支,这是数组中的一系列决策点选择:[3,1,2],表示树中的路径,来自树的根到叶子:在根目录,选择选项3;在您通过以下选项3到达的节点处,选择选项1;在该节点,选择选项2.你在那里。这是一个通过选择数组的简单循环。 choices数组中每个整数的含义取决于前一个发送给您的路径段。它是一个表示为数据结构的状态机:当您遍历树时,当前节点是您的状态,而choice-path数组中的下一个数字是您的输入。

我开始编号为1,因为你做了 - 但请记住,JavaScript中的数组开始在ZERO索引,而不是1.数组a中的第一项是[0],而不是[1]。

var json = JSON.parse(thingy);
var choices = json.Choices;  // array of user choices
var curNode = json.Tree;  // root of the tree

for ( var i = 0; i < choices.length; ++i ) {
    //  Do whatever you need to with the current node
    curNode = curNode.Children[choices[i]];
}

但是当然要添加大量的范围检查!

它没有任何收获,并且增加了混淆,试图在相同的数据结构中表达树和通过树的路径 - 如果这甚至是你正在考虑的事情。

答案 2 :(得分:0)

有很多方法可以满足您的需求,最合适的方法取决于您的数据。一个例子如下:

var obj = {
  "data" : "First question, two options",
  "options" : [
    {
      "data" : "Option1, Second question, three options",
      "options" : [
        { "data" : "Fail" },          
        { "data" : "Success" },          
        { "data" : "Fail" }          
      ]
    },    {
      "data" : "Option2, Second question, four options",
      "options" : [
        { "data" : "Fail" },          
        { 
          "data" : "Option2.2, Third question, two options",
          "options" : [
            { "data" : "Fail" },          
            { "data" : "Success" }   
          ]
        },     
        { "data" : "Success" },             
        { "data" : "Fail" }          
      ]
    }
  ]
}

注意:我是手工编写的,这个例子只是为了给你一个大概,我还没有验证JSON。