简体   繁体   中英

How can I create a JSON object that can handle conditionals?

I would like to create a JSON object that can handle conditionals/branching. Specifically, I have a workflow like the following:

在此输入图像描述

For step 1, the user has three choices, and depending on what choice they make, they are presented with a different set of choices for step 2. That same logic extends to step 3, etc.

Ideally, I'd like to have all this data in JSON format so that I can loop through it and based on a user's choice, figure out what choices I need to present to them next.

Is there a way to structure a JSON object (or perhaps just an array) in a way that will allow me to do this?

I should mention that I would like this to be flexible enough so that if I decided at a later time to change the number of choices for a step, then all I'd have to do is modify the JSON object/array (the model) without having to modify the logic that loops through the object/array.

Thank you very much.

What you are building is essentially a tree data structure. I would suggest building it from primitive node objects , than can contain recursive references to child objects of the same type. The tree can be implemented fully using only this one type of object, where the "topmost" object is called the root object , where all users start making their selections. Starting from the root, users select child nodes until they reach a leaf node that has no children, ie from where no further selections can be made.

All nodes are objects like this:

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

Where label is the name / label you want to give to this option, question is next question users must answer to select the next child node, and children is an array of more of nodes of the same type, where each children's label is one possible answer to this node's question .

To demonstrate by example, let us assume the following selection tree, that could be asked in an imaginary online retailing store, that only sells two main types of products: clothing and food. In the clothing section, there are jeans, t-shirts and hoodies of different colors (for simplicity, let us assume we already know the customer's size.) The shop also carries a small selection of types of hats. In the food section, there are available ramen noodles, different flavors of soda, and bananas. In the clothing section, customers can have a logo of a TV show or a rock band printed on their black T-shirt, or just buy a plain black T-shirt without a logo. The logo of the TV-show can additionally be printed on a blue hoodie, or customers can choose to buy the blue hoodie without a logo.

So, the decision tree of answer/question pairs facing the customer is as follows:

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>

Customers begin at the "answer" <start> and select multiple-choice questions until they reach a node with the special "question" <end> .

When we map this tree to JSON, the root question ( <start> above) that asks the product category the user is interested in (clothes/foods) can have the label value of null , since it is not an answer (child) to any other question. It is the first object of the whole structure, and all other nodes are its children. The leaf nodes, where no further selections can be made ( <end> above), are indicated by having null in place of the question string and the children array. All other nodes specify a label string (the top-level question the node "answers"), the next question, and an array of possible answers to the question:

{
 "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
    }
   ]
  }
 ]
}

The above is 100% valid JSON: you can copy&paste it to JSONtree to investigate its structure level-by-level.

The morale of the story is, that this kind of a possibly quite complex system of available user selections and paths, can be implemented with a surprisingly simple data structure at its core (a node with leaves). The complexity arises from the relations that you define between the nodes.

It's trivial to express your tree structure in JSON. The set of path choices in each question node is an array of question nodes. This is a classic recursive data structure.

Do that in your JSON, then add another branch alongside it, which is a series of decision-point choices in an array: [3, 1, 2], representing a path through the tree, from the root of the tree to a leaf: At the root, choose option 3; at the node you reach by following option 3, choose option 1; at that node, choose option 2. You're there. This is a simple loop through the choices array. The meaning of each integer in the choices array is dependent on which path segment the previous one sent you down. It's a state machine expressed as a data structure: When you're traversing the tree, the the current node is your state and the next number in the choice-path array is your input.

I started numbering at 1 because you did -- but bear in mind that arrays in JavaScript start indexing at ZERO, not 1. The first item in array a is a[0], not a[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]];
}

But add lots of range checking, of course!

It gains nothing, and adds confusion, to try to express both the tree, and the path through the tree, in the same data structure -- if that's even what you're contemplating.

There are many ways to do what you need and the most appropriate depends on your data. One example follows:

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" }          
      ]
    }
  ]
}

NOTE: I wrote it by hand, the example is just to give you a general idea, i haven't validated the JSON.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM