简体   繁体   English

Javascript 将 Json 转换为数组字符串格式

[英]Javascript convert Json to an array string format

I would like to convert json to a string "filter" format and visa versa.我想将 json 转换为字符串“过滤器”格式,反之亦然。

Json Format Json 格式

{
  "condition": "and",
  "rules": [
    {
      "field": "Name",
      "operator": "=",
      "value": "Jack"
    },
    {
      "field": "UserId",
      "operator": "=",
      "value": 2
    },
    {
      "field": "Surname",
      "operator": "=",
      "value": "Rose"
    },
    {
      "condition": "or",
      "rules": [
        {
          "field": "Code",
          "operator": "=",
          "value": "X"
        },
        {
          "field": "Type",
          "operator": "=",
          "value": "Z"
        }
      ]
    }
  ]
};

String Filter Format字符串过滤器格式

[
  ["Name","=", "Jack"],
  ["and"],
  ["UserId", "=", 2],
  ["and"],
  ["Surname","=", "Rose"]
,
["and"],
(
["Code","=","X"],
["or"],
["Type","=","Z"]
)
]

At the moment I have the following js code which outputs something that is halfway there, but I'm missing the "and" and "or" conditions which need to come between the respective fields as well as the "(" ")" brackets around to group the fields.目前,我有以下 js 代码,它输出了一半的内容,但我缺少需要在各个字段之间以及“(”“)”括号之间的“and”和“or”条件周围对字段进行分组。

I need to be able to convert from json to the "filter" format and back again.我需要能够从 json 转换为“过滤器”格式,然后再转换回来。

This is the code I have so far: query in this case is the json I posted above.这是我到目前为止的代码:在这种情况下,查询是我在上面发布的 json。

 const query={condition:"and",rules:[{field:"Name",operator:"=",value:"Jack"},{field:"UserId",operator:"=",value:2},{field:"Surname",operator:"=",value:"Rose"},{condition:"or",rules:[{field:"Code",operator:"=",value:"X"},{field:"Type",operator:"=",value:"Z"}]}]}; const parseRule = (rule) => { if (rule.rules) { return rule.rules.map(r=> parseRule(r)); } return [rule.field, rule.operator, rule.value]; }; let filterFormat = parseRule(query); console.log(filterFormat);

I'm stuck here.我被困在这里。 I almost need something like a join for arrays where the condition can be added as an array between the other arrays, without losing the arrays like you would with a normal join.我几乎需要类似数组的连接,其中条件可以作为数组添加到其他数组之间,而不会像使用普通连接那样丢失数组。

The part I think you already succeeded at is going from the rule object tree to the nested array format.我认为您已经成功的部分是从规则对象树到嵌套数组格式。 I wrote it using 3 main functions:我使用 3 个主要函数编写它:

  • childToArray only checks whether a node is a condition or a rule and forwards to the right parser function childToArray只检查节点是condition还是rule并转发到正确的解析器函数
  • ruleToArray takes the object and transforms it in to a tuple-like array ruleToArray获取对象并将其转换为类似元组的数组
  • conditionToArray maps all nested children and interweaves them with the operator conditionToArray映射所有嵌套的子项并将它们与operator交织在一起

For interweaving, I use a utility method that basically does this:对于交织,我使用了一种实用方法,它基本上可以做到这一点:

  (a, [1, 2, 3]) -> [1, a, 2, a, 3]
const childToArray = child => "condition" in child 
  ? conditionToArray(child)
  : ruleToArray(child);

const ruleToArray = ({ field, operator, value }) => [field, operator, value];
const conditionToArray = ({ condition, rules }) =>
  interweave(
    [ condition ],
    rules.map(childToArray)
  )

This array format might be slightly different from your requirement, but it is "lossless", which means we can translate it back in to the tree-like object!这种数组格式可能与您的要求略有不同,但它是“无损的”,这意味着我们可以将其转换回树状对象!

A similar approach:类似的方法:

  • Check if an array represents a rule (values will be strings), or a condition (values will be arrays)检查数组是否代表rule (值将是字符串)或condition (值将是数组)
  • If it's a rule, transform the tuple to an object with named keys如果是规则,则将元组转换为具有命名键的对象
  • If it's a condition, extract the condition and parse the nested arrays如果是条件,则提取condition并解析嵌套数组

To untangle our [1, a, 2, a, 3] type arrays, I wrote a utility that does:为了解开我们的[1, a, 2, a, 3]类型数组,我编写了一个实用程序,它可以:

([1, a, 2, a, 3]) -> [ a, [ 1, 2, 3] ]
const buildTree = arr => {
  const isCondition = Array.isArray(arr[0]);
  
  return isCondition
    ? conditionToObject(untangle(arr))
    : ruleToObject(arr);
}

const conditionToObject = ([ [ condition ], children ]) => ({
  condition,
  rules: children.map(buildTree)
});
const ruleToObject = ([ field, operator, value ]) => ({
  field, operator, value
});

Putting it all together with your test data:将它们与您的测试数据放在一起:

 // Transforming object trees to nested arrays const childToArray = child => "condition" in child ? conditionToArray(child) : ruleToArray(child); const ruleToArray = ({ field, operator, value }) => [field, operator, value] const conditionToArray = ({ condition, rules }) => interweave( [ condition ], rules.map(childToArray) ) // Transforming nested arrays to object trees const buildTree = arr => { const isCondition = Array.isArray(arr[0]); return isCondition ? conditionToObject(untangle(arr)) : ruleToObject(arr); } const conditionToObject = ([ [ condition ], children ]) => ({ condition, rules: children.map(buildTree) }); const ruleToObject = ([ field, operator, value ]) => ({ field, operator, value }); // App: // 1) To array const arrayOutput = childToArray(getInput()); // 2) Back to object const objectOutput = buildTree(arrayOutput); // 3) Log output console.log("Array output"); console.log(JSON.stringify(arrayOutput)); console.log("Object output"); console.log(objectOutput); // 4) Verify equality console.log( "inp obj -> arr -> out obj == inp obj:", JSON.stringify(objectOutput) === JSON.stringify(getInput()) ); // 5) arrayOutput with custom toString const arrayOutputToString = arr => { const isCond = Array.isArray(arr[0]); return isCond ? `(${arr.map(arrayOutputToString)})` : JSON.stringify(arr) } console.log( arrayOutputToString(arrayOutput) ) function getInput() { return { "condition": "and", "rules": [{ "field": "Name", "operator": "=", "value": "Jack" }, { "field": "UserId", "operator": "=", "value": 2 }, { "field": "Surname", "operator": "=", "value": "Rose" }, { "condition": "or", "rules": [{ "field": "Code", "operator": "=", "value": "X" }, { "field": "Type", "operator": "=", "value": "Z" } ] } ] } };
 <script> // Utils const interweave = (y, xs) => xs.flatMap( (x, i) => i === xs.length - 1 ? [x] : [x, y] ); const untangle = xs => { const wovenEl = xs[1]; const els = []; for (let i = 0; i < xs.length; i += 2) { els.push(xs[i]); } return [ wovenEl, els ]; } </script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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