# DataWeave programming challenge #7: Modify certain values from a JSON structure

> Create a DataWeave script that will update all the values to uppercase, except the ones in which the field equals thisname.

- **Author:** Alex Martinez
- **Published:** Jun 13, 2023
- **Category:** Challenges
- **Tags:** MuleSoft, DataWeave
- **Source:** https://prostdev.com/post/dataweave-programming-challenge-7

---
## Series: DataWeave Programming Challenges (Part 7 of 8)

1. [DataWeave programming challenge #1: Add numbers separated by paragraphs and get the max number](https://prostdev.com/post/dataweave-programming-challenge-1)
2. [DataWeave programming challenge #2: Rock Paper Scissors game score system](https://prostdev.com/post/dataweave-programming-challenge-2)
3. [DataWeave programming challenge #3: Count palindrome phrases using the Strings module](https://prostdev.com/post/dataweave-programming-challenge-3)
4. [DataWeave programming challenge #4: Solve the Tower of Hanoi mathematical puzzle](https://prostdev.com/post/dataweave-programming-challenge-4)
5. [DataWeave programming challenge #5: Reverse a phrase's words, but keep the punctuation](https://prostdev.com/post/dataweave-programming-challenge-5)
6. [DataWeave programming challenge #6: Using tail-recursion to get the factorial of a number](https://prostdev.com/post/dataweave-programming-challenge-6)
7. DataWeave programming challenge #7: Modify certain values from a JSON structure (this post)
8. [DataWeave programming challenge #8: Sum all digits to get a 1-digit number](https://prostdev.com/post/dataweave-programming-challenge-8)

---

Try to solve this challenge on your own to maximize learning. We recommend you refer to the [DataWeave documentation](https://docs.mulesoft.com/dataweave/latest/) **only**. Try to avoid using Google or asking others so you can learn on your own and become a DataWeave expert!

> [!PLAYGROUND]
> [Solve on the Playground](https://dataweave.mulesoft.com/learn/playground?projectMethod=GHRepo&repo=alexandramartinez%2Fdataweave-challenges&path=challenges%2F7)

> [!TIP]
> Instead of trying to write the whole code yourself, browse in the documentation for any function that would do the work for you 👀

## Input

Consider the following JSON input payload:

```
{
    "name": "a",
    "object": {
      "name": "b",
      "l": [
        {
          "other": "c",
          "list": [
            
          ]
        },
        {
          "thisname": "def",
          "list": [
            {
              "this": "500e",
              "l": [
                {
                  "finalname": "f"
                },
                {
                  "finalname": "ghijk"
                }
              ]
            }
          ]
        }
      ]
    },
    "array": [
      {
        "thisname": "h"
      },
      {
        "xyz": "abc123"
      }
    ]
  }
```

## Explanation of the problem

Create a DataWeave script that will update all the values to uppercase, **except** the ones in which the field equals **thisname**.

For example, the first field **name** with the value **"a"** has to be transformed to **"A"**. However, the field **thisname** with the value of **"def"** should stay the same.

## Expected output

In this case, the expected output would be:

```
{
  "name": "A",
  "object": {
    "name": "B",
    "l": [
      {
        "other": "C",
        "list": [
          
        ]
      },
      {
        "thisname": "def",
        "list": [
          {
            "this": "500E",
            "l": [
              {
                "finalname": "F"
              },
              {
                "finalname": "GHIJK"
              }
            ]
          }
        ]
      }
    ]
  },
  "array": [
    {
      "thisname": "h"
    },
    {
      "xyz": "ABC123"
    }
  ]
}
```

## Clues

If you're stuck with your solution, feel free to check out some of these clues to give you ideas on how to solve it!

### Clue #1

Check out the [Tree](https://docs.mulesoft.com/dataweave/latest/dw-tree) module to see if any of those functions is useful for this case.

### Clue #2

Check out the [mapLeafValues](https://docs.mulesoft.com/dataweave/latest/dw-tree-functions-mapleafvalues) function.

### Clue #3

Use the [upper](https://docs.mulesoft.com/dataweave/latest/dw-core-functions-upper) function to transform the strings to uppercase.

### Clue #4

Use **path[-1].selector** to retrieve the name of each value's field and compare it with a given string value.

## Answer

If you haven't solved this challenge yet, we encourage you to keep trying! It's ok if it's taking longer than you thought. We all have to start somewhere ✨ Check out the clues and read the docs before giving up. You got this!! 💙

There are many ways to solve this challenge, but you can find here some solutions we are providing so you can compare your result with us.

### Solution #1

```dataweave
%dw 2.0
import mapLeafValues from dw::util::Tree
output application/json
---
payload mapLeafValues ((value, path) -> 
    if (path[-1].selector == "thisname") value
    else upper(value)
)
```

### Solution #2

```dataweave
%dw 2.0
import mapLeafValues from dw::util::Tree
output application/json
---
payload mapLeafValues
    if ($$[-1].selector == "thisname") $
    else upper($)
```

Subscribe to receive notifications as soon as new content is published ✨

---

## Reader notes

**Sudiptaa** (Jun 13, 2023): Used tree:

```dataweave
%dw 2.0
output application/json
import * from dw::util::Tree
---
payload mapLeafValues ((value, path) ->

if(path.selector contains 'thisname') value else upper(value)

 )
```

**Kenneth Brennan** (Jun 13, 2023): I went with a recursive solution:

```dataweave
%dw 2.0
output application/json
fun capitalizeObject(item: Object) = do{
  fun matchItem(item) = item match{
    case item is Object -> item mapObject ((value, key, index) -> if(key as String == 'thisname') {(key): value} else {(key): matchItem(value)})
    case item is Array -> item map ((item, index) -> matchItem(item))
    case item is String -> upper(item)
  }
  ---
  matchItem(item)
}
---
capitalizeObject(payload)
```

↳ Reply to Kenneth Brennan — **Alex Martinez** (Jun 13, 2023): I love love love that you're using the `do` keyword to create a local context. This function's structure can be used for any number of modifications in a recursive way. I love it!

The only downside being that if there are more than 255 fields (or recursive calls), you will reach the StackOverflow error. But if it's a small payload like this one, you're all good!

Thanks for sharing :D


↳ Reply to Alex Martinez — **Kenneth Brennan** (Jun 13, 2023): That pesky stack overflow, I'm not sure how to rewrite this in the same format using tail recursion and match, hard to conceptualize. Might give it another go when I get some free time. Thanks for posting these challenges, I enjoyed this one!

**Shyam Raj Prasad** (Jun 13, 2023): My solution is similar to yours with extra type check of string.

```dataweave
%dw 2.0
output application/json
import * from dw::util::Tree
---
payload mapLeafValues ((value, path) ->
  if(!(path[-1].selector == "thisname") and value is String) upper(value) else value
)
```

---

## FAQs

### What is the goal of DataWeave programming challenge #7?

The challenge is to create a DataWeave script that updates all the values in a JSON structure to uppercase, except the ones whose field equals `thisname`. For example, the field `name` with value "a" becomes "A", but the field `thisname` with value "def" stays the same.

### Which DataWeave function does this challenge use to walk the JSON structure?

It uses the `mapLeafValues` function from the `dw::util::Tree` module, which lets you transform each leaf value in the structure. Both provided solutions import `mapLeafValues from dw::util::Tree` and call it on the payload.

### How do I skip the `thisname` field while uppercasing everything else?

Inside `mapLeafValues`, you check the field name of each value with `path[-1].selector` and compare it to the string `"thisname"`; if it matches you return the value unchanged, otherwise you apply the `upper` function to convert it to uppercase.

### What does `path[-1].selector` do in the solution?

As described in Clue #4, `path[-1].selector` retrieves the name of each value's field so you can compare it with a given string value, which is how the script decides whether a value belongs to the `thisname` field and should be left alone.

### What's the difference between the two provided solutions?

Solution #1 uses the explicit lambda form `mapLeafValues ((value, path) -> ...)` and references the field name with `path[-1].selector`, while Solution #2 uses the shorthand anonymous-parameter form, referencing the value with `$` and the field name with `$$[-1].selector`; both produce the same result.