Entendendo a recursividade no JSONata

A seguir, apresentaremos um exemplo que define a recursividade para navegar e transformar uma estrutura JSON. Este artigo irá detalhar o exemplo inicial e expandi-lo com explicações adicionais, exemplos práticos e casos de uso, proporcionando uma compreensão abrangente da aplicação de recursividade no JSONata.

(
   $person := function($node) { $node.{"n": Name, "p":$person(Parent.Person)}};


   {
       "Person": Person ~> $person($)
   }
)

Explicação

1. Definição da Função:

$person := function($node) { $node.{"n": Name, "p":$person(Parent.Person)}};

A linha acima define uma função recursiva chamada $person. A função recebe um nó ($node) como argumento. Ela retorna um objeto contendo:

  • "n": Name - A propriedade Name do nó atual.

  • "p": $person(Parent.Person) - O resultado da chamada da função $person na propriedade Parent.Person do nó atual, permitindo a navegação recursiva.

2. Aplicação da Função:

 {
    "Person": Person ~> $person($)
}

Esta parte aplica a função $person ao campo "Person" do contexto atual (denotado por $). O operador ~> canaliza o campo "Person" através da função $person.

Incrementando o Exemplo

Vamos aprimorar o exemplo adicionando mais campos para transformação e navegando em estruturas JSON mais profundamente aninhadas. Considere a seguinte estrutura JSON mais complexa:

Exemplo de JSON de Entrada

{
 "Person": {
   "Name": "João",
   "Age": 30,
   "Parent": {
     "Person": {
       "Name": "Maria",
       "Age": 55,
       "Parent": {
         "Person": {
           "Name": "Roberto",
           "Age": 80
         }
       }
     }
   }
 }
}

Função Expandida e Consulta

Vamos modificar a função para incluir a propriedade "Age" e tratar casos em que "Parent" pode estar ausente.

(
   $person := function($node) {
   $node.{
           "n": Name,
           "a": Age,
           "p": $exists($person(Parent.Person)) ? $person(Parent.Person) : null
       }
   };


   {
       "Person": Person ~> $person($)
   }
)

Explicação

  • A função modificada agora inclui "a": Age para capturar a idade de cada pessoa.

  • O operador ternário ($exists($person(Parent.Person)) ? ... : null) garante que a função retorne "null" se o nó não estiver presente, evitando erros ao navegar na hierarquia.

Exemplo de Saída

Aplicar a consulta expandida ao exemplo de entrada JSON resultará em:

{
"Person": {
  "n": "João",
  "a": 30,
  "p": {
    "n": "Maria",
    "a": 55,
    "p": {
      "n": "Roberto",
      "a": 80,
      "p": null
    }
  }
}
}

Exemplos Adicionais e Casos de Uso

Exemplo com Irmãos

Vamos considerar um exemplo onde cada pessoa pode ter irmãos.

JSON de Entrada

{
 "Person": {
   "Name": "João",
   "Age": 30,
   "Siblings": [
     {
       "Name": "Ana",
       "Age": 25
     },
     {
       "Name": "Alex",
       "Age": 28
     }
   ],
   "Parent": {
     "Person": {
       "Name": "Maria",
       "Age": 55,
       "Parent": {
         "Person": {
           "Name": "Roberto",
           "Age": 80
         }
       }
     }
   }
 }
}

Função Expandida e Consulta para Tratar Irmãos

Podemos expandir ainda mais nossa função para incluir irmãos:

(
   $person := function($node) {
   $node.{
           "n": Name,
           "a": Age,
           "s": $exists($person(Siblings)) ? $person(Siblings) : null,
           "p": $exists($person(Parent.Person)) ? $person(Parent.Person) : null
       }
   };


   {
       "Person": Person ~> $person($)
   }
)

Explicação

  • A linha"s": $exists($person(Siblings)) ? $person(Siblings) : null mapeia o array Siblings e transforma cada irmão em um objeto.

Exemplo de Saída

Aplicar a consulta expandida ao exemplo de entrada JSON resultará em:

{
 "Person": {
   "n": "João",
   "a": 30,
   "s": [
     {
       "n": "Ana",
       "a": 25,
       "s": null,
       "p": null
     },
     {
       "n": "Alex",
       "a": 28,
       "s": null,
       "p": null
     }
   ],
   "p": {
     "n": "Maria",
     "a": 55,
     "s": null,
     "p": {
       "n": "Roberto",
       "a": 80,
       "s": null,
       "p": null
     }
   }
 }
}

Conclusão

A função recursiva no JSONata fornece uma maneira poderosa de navegar e transformar estruturas JSON aninhadas. Ao definir e aplicar tais funções, você pode percorrer dados hierárquicos, tratar campos opcionais e até mesmo mapear arrays para produzir transformações complexas e automatizadas.