JOLT shift transformation: filter by the value of the property (not the name)

Viewed 49

I am trying to transform a JSON using Jolt transformation looking for some input here. I am trying to filter by the value of the attribute.

My goal is to get an array that contains only the items with the action 'remove'.

Here is my input and expected output:

Input:

{
  "id": 11,
  "item": [
    {
      "id": "11_1",
      "action": "add",
      "item": [
        {
          "id": "11_1_1",
          "action": "add",
          "item": [
            {
              "id": "11_1_1_1",
              "action": "remove"
            }
          ]
        },
        {
          "id": "11_1_2",
          "action": "remove",
          "item": [
            {
              "id": "11_1_2_1",
              "action": "remove"
            }
          ]
        }
      ]
    }
  ]
}

Expected output:

[
  {
    "id": "11_1_1_1",
    "action": "remove"
  },
  {
    "id": "11_1_2",
    "action": "remove"
  },
  {
    "id": "11_1_2_1",
    "action": "remove"
  }
]

Can you please help me to write a simple spec that will do this?

2 Answers
  • Let's flatten the JSON by determining the cases to be "item" vs. else case("*") while walking the tree within the first spec

  • and label the individual arrays by their action names

  • and then pick objects of the remove array the last spec

[
  {
    "operation": "shift",
    "spec": {
      "item": {
        "*": {
          "item": {
            "*": {
              "item": {
                "*": {
                  "*": "@(1,id)[&1].&"
                }
              },
              "*": "j[&1].&"
            }
          },
          "*": "i[&1].&"
        }
      }
    }
  },
  {
    "operation": "shift",
    "spec": {
      "*": {
        "*": "@(0,action)"
      }
    }
  },
  {
    "operation": "shift",
    "spec": {
      "remove": {
        "*": ""
      }
    }
  }
]

the demo on the playground site for jolt(http://jolt-demo.appspot.com/) is

enter image description here

You may consider another library Josson that a simple statement can do the job. And the function even supports unknown and unlimited number of path levels.

https://github.com/octomix/josson

Deserialization

Josson josson = Josson.fromJsonString(
    "{" +
    "  \"id\": 11," +
    "  \"item\": [" +
    "    {" +
    "      \"id\": \"11_1\"," +
    "      \"action\": \"add\"," +
    "      \"item\": [" +
    "        {" +
    "          \"id\": \"11_1_1\"," +
    "          \"action\": \"add\"," +
    "          \"item\": [" +
    "            {" +
    "              \"id\": \"11_1_1_1\"," +
    "              \"action\": \"remove\"" +
    "            }" +
    "          ]" +
    "        }," +
    "        {" +
    "          \"id\": \"11_1_2\"," +
    "          \"action\": \"remove\"," +
    "          \"item\": [" +
    "            {" +
    "              \"id\": \"11_1_2_1\"," +
    "              \"action\": \"remove\"" +
    "            }" +
    "          ]" +
    "        }" +
    "      ]" +
    "    }" +
    "  ]" +
    "}");
    

Transformation

JsonNode node = josson.getNode(
    "cumulateCollect(item[action='remove']*.field(item:), item).flatten(1)");
System.out.println(node.toPrettyString());

Output

[ {
  "id" : "11_1_2",
  "action" : "remove"
}, {
  "id" : "11_1_1_1",
  "action" : "remove"
}, {
  "id" : "11_1_2_1",
  "action" : "remove"
} ]
Related