2

I've a method in groovy inside strategy.groovy file as shown below:

strategy.groovy file (snippets of code inside strategy,groovy file):

Element strategy = createStrategyElement(rootStrategy, ctx) 
println("strategy 31: "+strategy);
root.addNewNode(strategy)

private createStrategyElement(rootStrategy, ctx) {
    
    Element strategy = new DefaultElement("strategy")

    strategy.addElement("players_o.player_id_s").text = rootstrategy.players_o.item.component.player_id_s  != null ? rootstrategy.players_o.item.component.player_id_s : ""
    strategy.addElement("players_o.first_name_s").text = rootstrategy.players_o.item.component.first_name_s  != null ? rootstrategy.players_o.item.component.first_name_s : ""
    strategy.addElement("players_o.last_name_s").text = rootstrategy.players_o.item.component.last_name_s  != null ? rootstrategy.players_o.item.component.last_name_s : ""
    
    println("Value of strategy at line#146 "+strategy)
    return strategy
}

The above groovy code displays the o/p in the following fashion:

players_o.first_name_s: (2) ['[David, Lionel]', '[David, Lionel]']
players_o.player_id_s: (2) ['[5, 7]', '[5, 7]']
players_o.last_name_s: (2) ['[Beckham, Messi]', '[Beckham, Messi]']

Problem Statement:

I am wondering what changes I need to do in the Groovy code (strategy.groovy file) above so that it displays the result (in the form of array) in the following fashion (desired o/p):

{
    "item": [
        {
            "talent_id_s": "5",
            "first_name_s": "David",
            "last_name_s": "Beckham"
        },
        {
            "talent_id_s": "7",
            "first_name_s": "Lionel",
            "last_name_s": "Messi"
        }
    ]
}

This is what I have tried but more changes need to be done in order to achieve the desired o/p.

private createStrategyElement(rootStrategy, ctx) {

    Element strategy = new DefaultElement("strategy")
    def players = []
    players = rootStrategy.players_o
    
    for(Element current: players.item) {
        strategy.addElement("players_o.player_id_s").text = rootstrategy.players_o.item.component.player_id_s  != null ? rootstrategy.players_o.item.component.player_id_s : ""
        strategy.addElement("players_o.first_name_s").text = rootstrategy.players_o.item.component.first_name_s  != null ? rootstrategy.players_o.item.component.first_name_s : ""
        strategy.addElement("players_o.last_name_s").text = rootstrategy.players_o.item.component.last_name_s  != null ? rootstrategy.players_o.item.component.last_name_s : ""
    }
return strategy
}
flash
  • 1,455
  • 11
  • 61
  • 132
  • This doesn't appear to be a docker question. – BMitch Sep 26 '21 at 01:00
  • @flash, your question is incomplete. you have not provided a sample input data for corresponding output. what is it - `DefaultElement` ? sounds like the question is very specific to `crafter-cms`... – daggett Sep 29 '21 at 13:22

2 Answers2

1

Here is a short explanation on how Crafter CMS handles XML:

The XML descriptor of your content will look something like this

<players_o>
  <item>
    <component>
      <player_id_s>...</player_id_s>
      <first_name_s>...</first_name_s>
      <last_name_s>...</last_name_s>
    </component>
  <item>
  <item>
    ...
  </item>
</players_o>

and when you execute and expression like

rootstrategy.players_o.item.component.player_id_s

Groovy will actually evaluate it as an XPath selector, so it will return all nodes matching the path. This will flatten the structure and that is why the result doesn't look as you expect.

So to solve your issue you should navigate the structure using a for loop or Groovy collection methods, something like this:

// for every player item
for (player : rootstrategy.players_o.item) {
   // create an element
   def playerElement = new DefaultElement("player")

   // add the properties that you want
   playerElement.addElement("player_id").text = player.component.player_id_s

   // do something with the new playerElement ...
}

That way you will preserve the original structure of the XML.

Jose Ross
  • 190
  • 4
  • Thanks for the answer and proving me the pointers. I tried your code but unfortunately it didn't work as it was throwing errors. In order to get it work, I made minor changes in your code (as shown below) but I am still seeing the result in the same fashion which I don't want. – flash Sep 28 '21 at 20:48
  • `private createStrategyElement(rootStrategy, ctx) { Element strategy = new DefaultElement("strategy") for (Element player : rootstrategy.players_o.item) { strategy.addElement("player_id").text = player.component.player_id_s : "" } return strategy }` – flash Sep 28 '21 at 20:48
1

You are not using the loop variable at all. Try this if it works:

private createStrategyElement(rootStrategy, ctx) {

Element strategy = new DefaultElement("strategy")
def players = []
players = rootStrategy.players_o

for(Element current: players.item) {
    strategy.addElement("players_o.player_id_s").text = current.component.player_id_s ?: ""
    strategy.addElement("players_o.first_name_s").text = current.component.first_name_s ?: ""
    strategy.addElement("players_o.last_name_s").text = current.component.last_name_s ?: ""
}
return strategy
}

Note: I added the Elvis operator for simplification

Kaus2b
  • 747
  • 4
  • 12
  • I tried your code but there is no change in result. In the [fiddle](https://jsfiddle.net/t2vLouwh/) in the HTML section, I've added the heading **Desired o/p** with the result which I want. The heading **o/p** is the result which I am getting from your code. – flash Oct 01 '21 at 19:39
  • @flash ummm.... Are you sure you have it right in the fiddle? The desired o/p you have in the question in problem statement above is exactly like the o/p in the fiddle but desired o/p is different. – Kaus2b Oct 03 '21 at 01:23