Velocity: Dereferencing a variable with a concatinated name - velocity

I'm new to Velocity and couldn't find something that addressed this problem, so I apologize if it's trivial. Say I have the following 200 variables.
#set( $a1 = "apple", $b1 = "red", $a2 = "banana", $b2 = "yellow" ....
.... $a100 = "plum", $b100 = "purple)
I want to output the fruit followed by its color. Is there a way to concatenate "a" and "b" with each of the numbers in the range(1,100) and then dereference the variable? Something like
#foreach( $i in [1..100])
#set( $fruit = "a{$i}")
#set( $color = "b{$i}")
The fruit $fruit is the color $color.
#end
I've tried many things, but can ever only manage to output $a1 $b1 as strings rather than what they refer to.
Thanks!

#set ($d = '$')
#set ($h = '#')
#foreach ($i in [1..100])
#evaluate("${h}set(${d}fruit = ${d}a${i})")
#evaluate("${h}set(${d}color = ${d}b${i})")
The fruit ${fruit} is the color ${color}.
#end

Related

Velocity loop through JSON

I am using Velocity to try and loop through some JSON data I have in a field in Marketo. I have used the tutorial here to change the JSON into a Velocity Map but have an issue trying to loop through the data which is now a map.
#set( $items = ${abandonedBasket_cList} )
###if( $items.get(7).basketJSON.isEmpty() )
###set( $items.get(7).basketJSON = '[]' )
###end
#foreach ($item in $items)
#if( $foreach.last )
#set( $lastitem = $item.basketJSON )
#end
#end
#set( $ClientReferrals = '#set( $ClientReferrals = ' + $lastitem + ' ) ' )
#evaluate( $ClientReferrals )
${ClientReferrals[0].itemDesc} ## outputs "Season Pass Holders"
<br>
${ClientReferrals[1].customerID} ## outputs "jill#example2.com"
<br>
I have managed output values from the "map" when using a specific static index like in the example.
The bit I am stuck on is trying to get it to loop through each object using the foreach tool in Velocity as I don't know how to iterate the [index] key as part of the loop.
Update
I have tried to use the code suggested but there is nothing displaying.
#foreach($key in $ClientReferrals.keySet())
#set($item = $ClientReferrals[$key])
$item.itemDesc
${item.itemDesc}
$item
${item}
#end
If I output what $ClientReferrals looks like this is what I get. Does this look like a Hashmap to you?
[{id=29071940, itemDesc=1.33ct AA Tanzanite 9K Gold Earrings, itemImage=https://cdn.gemporia.com/images/products/300/NJPS19.jpg, itemQuantity=1, itemPrice=£151.00, customerID=1132399, basketURL=https://secure.gemporia.com/basket.aspx, isAuction=false, stock=10, dateAdded=2017-02-15}, {id=29071946, itemDesc=Size J to K AA Tanzanite & White Zircon 9K Gold Ring ATGW 1.08cts, itemImage=https://cdn.gemporia.com/images/products/300/OZVJ80.5.jpg, itemQuantity=1, itemPrice=£89.99, customerID=1132399, basketURL=https://secure.gemporia.com/basket.aspx, isAuction=true, stock=1, dateAdded=2017-02-15}]
If $ClientReferrals is a map, then you can do:
#foreach($key in $ClientReferrals.keySet())
#set($item = $ClientReferrals[$key])
...
#end
Items won't be sorted by key for an HashMap, they will for a TreeMap.
By the way, to get the last item of an array, you can do:
#set($last_index = $items.size() - 1)
#set($last = $items[$last_index])

How to cast query string to int in Integration Request Body Mapping template?

#set($a = 10)
#set($b = 123)
#set($c = 456)
// If query string "q1" is not available then set $q1,$q2 to default values
#if($!input.params('q1') && $input.params('q1').empty)
#set($q1 = $b)
#set($q2 = $c)
// If query string "q1" available but not "q2" then add some value to $q1 and set it as $q2
#elseif($!input.params('q2') && $input.params('q2').empty)
#set($q1 = $input.params('q1'))
#set($q2 = $a + $q1 )
// If both query strings available then set them
#else
#set($q1 = $input.params('q1'))
#set($q2 = $input.params('q2'))
#end
I'm triying the above code in Integration request body mapping template. In second case where only q1 is specified as some number (let's say 10) then $q2 should be 22( 12 + 10) but it's becoming as 1210, I assume this is because those $q1 and $q2 are strings and they are getting combined.
So I tried to cast them using this answer, but I'm getting internal server error.
How can I cast string to int and them as integers?
The solution given in the other question works for me. Try this (just the second part of if-else):
#set($a = 10)
#set($q1 = $input.params('q1'))
#set($Integer = 0)
#set($q2 = $Integer.parseInt($q1) + $a)
{
"params" : {
"a" : "$a",
"q1" : "$q1",
"q2" : "$q2"
}
}

How to create and access a multi level map in Velocity?

I want to create a dynamic map with multiple values for each entry, and then be able to run over that map and match up values with another list. Here is what I mean:
#set($map = {})
#foreach( $Item in $someQuery.getResults() )
#set( $day = "Monday") ## This would be a dynamic value.. just example here
#set( $startTimeHour = "8")
#set( $startTimeMinute = "00")
#set( $endTimeHour = "17")
#set( $endTimeMinute = "30")
## Now I need here to put this into a map...
$!map.put("${foreach.count}", "dayValue": $day, "startTimeHourValue": $startTimeHour, "startTimeMinuteValue": $startTimeMinute, "endTimeHourValue": $endTimeHour, "endTimeMinuteValue": $endTimeMinute)
#end
With this, I want to be able to do this in another for each loop
#foreach($newItem in $someList)
#if($newItem.DayValue IS IN MAP DAY VALUE $map.dayValue????)
## Print everything associated with this map entry
$map.dayValue
$map.startTimeHourValue
$map.startTimeMinuteValue
$map.endTimeHourValue
$map.endTimeMinuteValue
#end
#end
I am very new to velocity and have no Java knowledge, so any help would be greatly appreciated. Thanks!

Easiest way of defining and using of Global Variable

"first part" &&&& fun _ ->
let ident
"second part" &&&& fun _ ->
ident ....
I need to use variable "ident".
I just need to pass value of variable from first part of test to second one...
I want to ask you if there is any easy way how to define and use global variable or even if you have better (and easy) idea of doing that
Keep in mind, please, that I am a beginner, so I would prefer easier ones.
Global variables will often make your code difficult to work with - particularly if they are mutable.
Instead, consider returning the values you need to keep track of as composite values. An easy data type to start with would be a tuple:
let ``first part`` id =
let someOtherValue = "Foo"
someOtherValue, id + 1
This function takes an int (the current ID) as input, and returns string * int (a tuple where the first element is a string, and the second element and int) as output.
You can call it like this:
> let other, newId = ``first part`` 42;;
val other : string = "Foo"
val newId : int = 43
Notice that you can use pattern matching to immediately destructure the values into two named symbols: other and newId.
Your second function could also take an ID as input:
let ``second part`` id otherArgument =
// use id here, if you need it
"Bar"
You can call it like this, with the newId value from above:
> let result = ``second part`` newId "Baz";;
val result : string = "Bar"
If you find yourself doing this a lot, you can define a record for the purpose:
type Identifiable<'a> = { Id : int; Value : 'a }
Now you can begin to define higher-order functions to deal with such a type, such as e.g. a map function:
module Identifiable =
let map f x = { Id = x.Id; Value = f x.Value }
// Other functions go here...
This is a function that maps the Value of an Identifiable from one value to another, but preserves the identity.
Here's a simple example of using it:
> let original = { Id = 42; Value = "1337" };;
val original : Identifiable<string> = {Id = 42;
Value = "1337";}
> let result' = original |> Identifiable.map System.Int32.Parse;;
val result' : Identifiable<int> = {Id = 42;
Value = 1337;}
As you can see, it preserves the value 42, but changes the Value from a string to an int.
You can still change the ID explicitly, if you want to do that:
> let result'' = { result' with Id = 7 };;
val result'' : Identifiable<int> = {Id = 7;
Value = 1337;}
Since this was getting out of hand for comments this is how I would do it for an example
let mutable t = 0
let first =
t <- 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2
In some cases you have to use a ref:
let t = ref 0
let first =
t := 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2 -
// you use "!t" to get the value
If you define ident at the top of your file like this :
let ident = "foo"
// rest of your code using ident
ident are global and you can use in the next part of your file.
EDIT :
If ident wil change in the next part of your code, use this :
let ident = ref "foo"

construct variable names dynamically in velocity

I would like to know if it is possible to construct name of variable into velocity dynamically.
i.e. lets say I've 6 variables into velocity template [name1, name2, name3 .. name6] I would like to output them.
So I'm looking in something like:
#foreach ( $counter in [1..6] )
${name${counter}}
#end
is it possible somehow?
It is possible using the #evaluate directive:
#evaluate ('$name1')
#set ($d = '$')
#foreach ($i in [1..6])
#set ($varName = "${d}name${i}")
#evaluate($varName)
#end
You could construct a map and build the names of the keys to retrieve the values you want:
#set( $map = {"${name}1":'value1', "${name}2":'value2'} )
#foreach ( $counter in [1..6] )
#set( $key = "${name}$counter" )
$map.get(${key})
#end
Here is a trick to set velocity variable with dynamic name.
If you manage to tune velocity context beforehand in java code like this:
VelocityContext context = new VelocityContext(paramsMap);
context.put("all", paramsMap);
then it would be possible to define dynamic vars in template like this:
#set($dynamicDef = "varName=varValue")
#set($dynamicName = $dynamicDef.substring(0, $dynamicDef.indexOf('=')))
#set($dynamicValue = $dynamicDef.substring($dynamicDef.indexOf('=')).substring(1))
## create var with dynamic name
$all.put($dynamicName, $dynamicValue)
and use them later like this:
#if ($varName)
varName=$varName ## prints varName=varValue
#end