FeelEx
FeelEx

Introduction
A friendly expression language helps users define decision logic without needing deep technical expertise. This language is based on the FEEL(Friendly Enough Expression Language). For more information regarding FEEL, please take a look at the official OMG specification at https://www.omg.org/dmn/.
Installation
Add feel_ex to the list of dependencies in mix.exs:
def deps do
[
{:feel_ex, "~> 0.2.0"}
]
end
Data types
Null
A null value is represented simply by null.
iex> FeelEx.evaluate("null")
%FeelEx.Value{value: nil, type: :null}
Number
Allows for integers and decimal numbers. The numbers can be negative, and leading zero may be omitted.
iex> FeelEx.evaluate("1")
%FeelEx.Value{value: 1, type: :number}
iex> %FeelEx.Value{value: 2.4, type: :number}
FeelEx.evaluate("2.4")
iex> FeelEx.evaluate(".4")
%FeelEx.Value{value: 0.4, type: :number}
iex> FeelEx.evaluate("-5")
%FeelEx.Value{value: -5, type: :number}
Strings
Strings are wrapped around in ".
iex> FeelEx.evaluate("\"Aw dinja\"")
%FeelEx.Value{value: "Aw dinja", type: :string}
Boolean
Either true or false.
iex> FeelEx.evaluate("true")
%FeelEx.Value{value: true, type: :boolean}
iex> FeelEx.evaluate("false")
%FeelEx.Value{value: false, type: :boolean}
Date
Format: yyyy-MM-dd.
iex> FeelEx.evaluate("date(\"2017-03-10\")")
%FeelEx.Value{value: ~D[2017-03-10], type: :date}
iex> FeelEx.evaluate("@\"2017-03-10\"")
%FeelEx.Value{value: ~D[2017-03-10], type: :date}
Time
Format: HH:mm:ss / HH:mm:ss+/-HH:mm / HH:mm:ss@ZoneId.
iex> FeelEx.evaluate("time(\"11:45:30\")")
%FeelEx.Value{value: ~T[11:45:30], type: :time}
iex> FeelEx.evaluate("time(\"13:30\")")
%FeelEx.Value{value: ~T[13:30:00], type: :time}
iex> FeelEx.evaluate("time(\"11:45:30+02:00\")")
%FeelEx.Value{value: {~T[11:45:30], "+02:00"}, type: :time}
iex> FeelEx.evaluate("time(\"10:31:10@Europe/Paris\")")
%FeelEx.Value{value: {~T[10:31:10], "+01:00", "Europe/Paris"}, type: :time}
iex> FeelEx.evaluate("@\"11:45:30\"")
%FeelEx.Value{value: ~T[11:45:30], type: :time}
iex> FeelEx.evaluate("@\"13:30\"")
%FeelEx.Value{value: ~T[13:30:00], type: :time}
iex> FeelEx.evaluate("@\"11:45:30+02:00\"")
%FeelEx.Value{value: {~T[11:45:30], "+02:00"}, type: :time}
iex> FeelEx.evaluate("@\"10:31:10@Europe/Paris\"")
%FeelEx.Value{value: {~T[10:31:10], "+01:00", "Europe/Paris"}, type: :time}
Date-time
Format: yyyy-MM-dd'T'HH:mm:ss / yyyy-MM-dd'T'HH:mm:ss+/-HH:mm / yyyy-MM-dd'T'HH:mm:ss@ZoneId.
iex> FeelEx.evaluate("date and time(\"2015-09-18T10:31:10\")")
%FeelEx.Value{value: ~N[2015-09-18 10:31:10], type: :datetime}
iex> FeelEx.evaluate("date and time(\"2015-09-18T10:31:10+01:00\")")
%FeelEx.Value{value: {~N[2015-09-18 10:31:10], "+01:00"}, type: :datetime}
iex> FeelEx.evaluate("date and time(\"2015-09-18T10:31:10@Europe/Paris\")")
%FeelEx.Value{
value: {~N[2015-09-18 10:31:10], "+01:00", "Europe/Paris"},
type: :datetime
}
iex> FeelEx.evaluate("@\"2015-09-18T10:31:10\"")
%FeelEx.Value{value: ~N[2015-09-18 10:31:10], type: :datetime}
iex> FeelEx.evaluate("@\"2015-09-18T10:31:10+01:00\"")
%FeelEx.Value{value: {~N[2015-09-18 10:31:10], "+01:00"}, type: :datetime}
iex> FeelEx.evaluate("@\"2015-09-18T10:31:10@Europe/Paris\"")
%FeelEx.Value{
value: {~N[2015-09-18 10:31:10], "+01:00", "Europe/Paris"},
type: :datetime
}
Days-time-duration
Format: PxDTxHxMxS.
iex> FeelEx.evaluate("duration(\"P4D\")")
%FeelEx.Value{value: %Duration{day: 4}, type: :days_time_duration}
iex> FeelEx.evaluate("duration(\"PT2H\")")
%FeelEx.Value{value: %Duration{hour: 2}, type: :days_time_duration}
iex> FeelEx.evaluate("duration(\"PT30M\")")
%FeelEx.Value{value: %Duration{minute: 30}, type: :days_time_duration}
iex> FeelEx.evaluate("duration(\" P1DT6H\")")
%FeelEx.Value{value: %Duration{day: 1, hour: 6}, type: :days_time_duration}
iex> FeelEx.evaluate("@\"P4D\"")
%FeelEx.Value{value: %Duration{day: 4}, type: :days_time_duration}
iex> FeelEx.evaluate("@\"PT2H\"")
%FeelEx.Value{value: %Duration{hour: 2}, type: :days_time_duration}
iex> FeelEx.evaluate("@\"PT30M\"")
%FeelEx.Value{value: %Duration{minute: 30}, type: :days_time_duration}
iex> FeelEx.evaluate("@\"P1DT6H\"")
%FeelEx.Value{value: %Duration{day: 1, hour: 6}, type: :days_time_duration}
Years-months-duration
Format: PxYxM.
iex> FeelEx.evaluate("duration(\"P2Y\")")
%FeelEx.Value{value: %Duration{year: 2}, type: :years_months_duration}
iex> FeelEx.evaluate("duration(\"P6M\")")
%FeelEx.Value{value: %Duration{month: 6}, type: :years_months_duration}
iex> FeelEx.evaluate("duration(\"P1Y6M\")")
%FeelEx.Value{value: %Duration{year: 1, month: 6}, type: :years_months_duration}
iex> FeelEx.evaluate("@\"P2Y\"")
%FeelEx.Value{value: %Duration{year: 2}, type: :years_months_duration}
iex> FeelEx.evaluate("@\"P6M\"")
%FeelEx.Value{value: %Duration{month: 6}, type: :years_months_duration}
iex> FeelEx.evaluate("@\"P1Y6M\"")
%FeelEx.Value{value: %Duration{year: 1, month: 6}, type: :years_months_duration}
List
A list of elements. Lists may contain lists or may be empty.
iex> FeelEx.evaluate("[]")
[]
iex> FeelEx.evaluate("[1,2,3]")
[
%FeelEx.Value{value: 1, type: :number},
%FeelEx.Value{value: 2, type: :number},
%FeelEx.Value{value: 3, type: :number}
]
iex> FeelEx.evaluate("[\"a\",\"b\"]")
[
%FeelEx.Value{value: "a", type: :string},
%FeelEx.Value{value: "b", type: :string}
]
Context
Key-value data structure. It may be empty or nested (value being a context). The key may be a name or a string.
iex> FeelEx.evaluate("{}")
%FeelEx.Value{value: %{}, type: :context}
iex> FeelEx.evaluate("{a:1}")
%FeelEx.Value{
value: %{a: %FeelEx.Value{value: 1, type: :number}},
type: :context
}
iex> FeelEx.evaluate("{b:1, c: \"wow\"}")
%FeelEx.Value{
value: %{
c: %FeelEx.Value{value: "wow", type: :string},
b: %FeelEx.Value{value: 1, type: :number}
},
type: :context
}
iex> FeelEx.evaluate("{nested: {d: 3}}")
%FeelEx.Value{
value: %{
nested: %FeelEx.Value{
value: %{d: %FeelEx.Value{value: 3, type: :number}},
type: :context
}
},
type: :context
}
iex> FeelEx.evaluate("{\"a\": 1}")
%FeelEx.Value{
value: %{a: %FeelEx.Value{value: 1, type: :number}},
type: :context
}
iex> FeelEx.evaluate("{\"b\": 2, \"c\": \"valid\"}")
%FeelEx.Value{
value: %{
c: %FeelEx.Value{value: "valid", type: :string},
b: %FeelEx.Value{value: 2, type: :number}
},
type: :context
}
Expressions
Introduction
Comments
An expression can contain comments to explain it and give it more context. // is used for single line comments and /**/ is used for multiline comments.
iex> program =
"""
// returns the last item
[1,2,3,4][-1]
"""
iex> FeelEx.evaluate(program)
%FeelEx.Value{value: 4, type: :number}
program =
"""
/*
* returns the last item
*/
[1,2,3,4][-1]
"""
iex> FeelEx.evaluate(program)
%FeelEx.Value{value: 4, type: :number}
Parenthesis
Parenthesis are used to group expressions or effect precedence of operators.
iex> FeelEx.evaluate("(5 - 3) * (4 / 2)")
%FeelEx.Value{value: 4, type: :number}
iex> FeelEx.evaluate("if (5 < 10) then \"low\" else \"high\"")
%FeelEx.Value{value: "low", type: :string}
Strings
Creating a new string value.
iex> FeelEx.evaluate("\"Aw dinja\"")
%FeelEx.Value{value: "Aw dinja", type: :string}
String concatenation
iex> FeelEx.evaluate("\"Aw\"+\" Dinja\"")
%FeelEx.Value{value: "Aw Dinja", type: :string}
string()
Converting datatypes to string
Examples
null
iex> FeelEx.evaluate("string(null)")
%FeelEx.Value{value: "null", type: :string}
string (idempotent)
iex> FeelEx.evaluate("string(\"Aw Dinja\")")
%FeelEx.Value{value: "Aw Dinja", type: :string}
number
iex> FeelEx.evaluate("string(12)")
%FeelEx.Value{value: "12", type: :string}
iex> FeelEx.evaluate("string(.22)")
%FeelEx.Value{value: "0.22", type: :string}
iex> FeelEx.evaluate("string(-2.22)")
%FeelEx.Value{value: "-2.22", type: :string}
iex> FeelEx.evaluate("string(-.22)")
%FeelEx.Value{value: "-0.22", type: :string}
boolean
iex> FeelEx.evaluate("string(true)")
%FeelEx.Value{value: "true", type: :string}
iex> FeelEx.evaluate("string(false)")
%FeelEx.Value{value: "false", type: :string}
date
iex> FeelEx.evaluate("string(@\"2024-01-01\")")
%FeelEx.Value{value: "2024-01-01", type: :string}
iex> FeelEx.evaluate("string(date(\"2024-01-01\"))")
%FeelEx.Value{value: "2024-01-01", type: :string}
time
iex> FeelEx.evaluate("string(time(\"11:45:30\"))")
%FeelEx.Value{value: "11:45:30", type: :string}
iex> FeelEx.evaluate("string(time(\"11:45\"))")
%FeelEx.Value{value: "11:45:00", type: :string}
iex> FeelEx.evaluate("string(time(\"11:45:30+02:00\"))")
%FeelEx.Value{value: "11:45:30+02:00", type: :string}
iex> FeelEx.evaluate("string(@\"11:45:30\")")
%FeelEx.Value{value: "11:45:30",type: :string}
iex> FeelEx.evaluate("string(@\"13:30\")")
%FeelEx.Value{value: "13:30:00", type: :string}
iex> FeelEx.evaluate("string(@\"10:45:30+02:00\")")
%FeelEx.Value{value: "10:45:30+02:00", type: :string}
iex> FeelEx.evaluate("string(@\"10:31:10@Europe/Paris\")")
%FeelEx.Value{value: "10:31:10@Europe/Paris", type: :string}
date-time
iex> FeelEx.evaluate("string(date and time(\"2015-09-18T10:31:10\"))")
%FeelEx.Value{value: "2015-09-18T10:31:10", type: :string}
iex> FeelEx.evaluate("string(date and time(\"2015-09-18T10:31:10+01:00\"))")
%FeelEx.Value{value: "2015-09-18T10:31:10+01:00", type: :string}
iex> FeelEx.evaluate("string(date and time(\"2015-09-18T10:31:10@Europe/Paris\"))")
%FeelEx.Value{value: "2015-09-18T10:31:10@Europe/Paris", type: :string}
iex> FeelEx.evaluate("string(@\"2015-09-18T10:31:10\")")
%FeelEx.Value{value: "2015-09-18T10:31:10", type: :string}
iex> FeelEx.evaluate("string(@\"2015-09-18T10:31:10+01:00\")")
%FeelEx.Value{value: "2015-09-18T10:31:10+01:00", type: :string}
iex> FeelEx.evaluate("string(@\"2015-09-18T10:31:10@Europe/Paris\")")
%FeelEx.Value{value: "2015-09-18T10:31:10@Europe/Paris", type: :string}
days-time duration
iex> FeelEx.evaluate("string(duration(\"P4D\"))")
%FeelEx.Value{value: "P4D", type: :string}
iex> FeelEx.evaluate("string(duration(\"PT2H\"))")
%FeelEx.Value{value: "PT2H", type: :string}
iex> FeelEx.evaluate("string(duration(\"PT30M\"))")
%FeelEx.Value{value: "PT30M", type: :string}
iex> FeelEx.evaluate("string(duration(\"P1DT6H\"))")
%FeelEx.Value{value: "P1DT6H", type: :string}
iex> FeelEx.evaluate("string(@\"P4D\")")
%FeelEx.Value{value: "P4D",type: :string}
iex> FeelEx.evaluate("string(@\"PT2H\")")
%FeelEx.Value{value: "PT2H", type: :string}
iex> FeelEx.evaluate("string(@\"PT30M\")")
%FeelEx.Value{value: "PT30M", type: :string}
iex> FeelEx.evaluate("string(@\"P1DT6H\")")
%FeelEx.Value{value: "P1DT6H", type: :string}
years-month-duration
iex> FeelEx.evaluate("string(duration(\"P2Y\"))")
%FeelEx.Value{value: "P2Y", type: :string}
iex> FeelEx.evaluate("string(duration(\"P6M\"))")
%FeelEx.Value{value: "P6M", type: :string}
iex> FeelEx.evaluate("string(duration(\"P1Y6M\"))")
%FeelEx.Value{value: "P1Y6M", type: :string}
iex> FeelEx.evaluate("string(@\"P2Y\")")
%FeelEx.Value{value: "P2Y", type: :string}
iex> FeelEx.evaluate("string(@\"P6M\")")
%FeelEx.Value{value: "P6M", type: :string}
iex> FeelEx.evaluate("string(@\"P1Y6M\")")
%FeelEx.Value{value: "P1Y6M", type: :string}
Numbers
Leading 0’s are valid
iex> FeelEx.evaluate("-000002")
%FeelEx.Value{value: -2, type: :number}
iex> FeelEx.evaluate("0001.5")
%FeelEx.Value{value: 1.5, type: :number}
Addition, Subtraction, Multiplication, Division, Exponentiation
We can carry out the usual arithmetic operators with exponentiation having the highest precedence, division and multiplication the second highest and addition and subtraction the least precedence.
Examples:
2+3*2 is not 10 but 8 since the multiplicative operator * has more precedence than +
iex> FeelEx.evaluate("2+3*2")
%FeelEx.Value{value: 8, type: :number}
iex> FeelEx.evaluate("2/3")
%FeelEx.Value{value: 0.6666666666666666, type: :number}
Lists
Getting element list[i]
Access element using 1-based indexing. When index is out of bounds, null is returned.
iex> FeelEx.evaluate("[1, \"a\", 3][1]")
%FeelEx.Value{value: 1, type: :number}
iex> FeelEx.evaluate("[1, \"a\", 3][2]")
%FeelEx.Value{value: "a", type: :string}
iex> FeelEx.evaluate("[1, \"a\", 3][3]")
%FeelEx.Value{value: 3, type: :number}
iex> FeelEx.evaluate("[1, \"a\", 3][4]")
%FeelEx.Value{value: nil, type: :null}
Using negative indexing we can access elements from the back of the list. The last element of the list is at index -1.
iex> FeelEx.evaluate("[1, \"a\", 3][-1]")
%FeelEx.Value{value: 3, type: :number}
iex> FeelEx.evaluate("[1, \"a\", 3][-2]")
%FeelEx.Value{value: "a", type: :string}
iex> FeelEx.evaluate("[1, \"a\", 3][-3]")
%FeelEx.Value{value: 1, type: :number}
Filtering
We can filter a list by a condition. The current element of the list is assigned to variable item.
iex> FeelEx.evaluate("[1,2,4, 3][even(item)]")
[%FeelEx.Value{value: 2, type: :number}, %FeelEx.Value{value: 4, type: :number}]
iex> FeelEx.evaluate("[1,2,4, 3][item>2]")
[%FeelEx.Value{value: 4, type: :number}, %FeelEx.Value{value: 3, type: :number}]
Quantified expression
some a in b satisfies c: iterates over list b, assigning current element in list to a, and evaluating c. If some of the elements evaluates to true then the statement is true else it is false.
every a in b satisfies c: iterates over list b, assigning current element in list to a, and evaluating c. If all of the elements evaluates to true then the statement is true else it is false.
iex> FeelEx.evaluate("some x in [1,2,3] satisfies x > 2")
%FeelEx.Value{value: true, type: :boolean}
iex> FeelEx.evaluate("some x in [1,2,3] satisfies x > 5")
%FeelEx.Value{value: false, type: :boolean}
iex> FeelEx.evaluate("every x in [1,2,3] satisfies x >= 1")
%FeelEx.Value{value: true, type: :boolean}
iex> FeelEx.evaluate("every x in [1,2,3] satisfies x >= 2")
%FeelEx.Value{value: false, type: :boolean}
Contexts
Allows for previous element access
iex> FeelEx.evaluate("{a: 2, b: a*2}")
%FeelEx.Value{
value: %{
a: %FeelEx.Value{value: 2, type: :number},
b: %FeelEx.Value{value: 4, type: :number}
},
type: :context
}
Get entry path a.b
We may use dot notation to access elements of a context.
iex> FeelEx.evaluate("{a: 2}.a")
%FeelEx.Value{value: 2, type: :number}
iex> FeelEx.evaluate("{a: 2, b: {b: 3}}.b")
%FeelEx.Value{
value: %{b: %FeelEx.Value{value: 3, type: :number}},
type: :context
}
If the name we are accessing does not exist in the context than we simply return null.
iex> FeelEx.evaluate("{}.a")
%FeelEx.Value{value: nil, type: :null}
iex> FeelEx.evaluate("{b: 1}.a")
%FeelEx.Value{value: nil, type: :null}
Functions
Numerical Functions
decimal
iex> FeelEx.evaluate("1/3")
%FeelEx.Value{value: 0.3333333333333333, type: :number}
iex> FeelEx.evaluate("decimal(1/3,2)")
%FeelEx.Value{value: 0.33, type: :number}
floor
iex> FeelEx.evaluate("floor(1)")
%FeelEx.Value{value: 1, type: :number}
floor with scale
iex> FeelEx.evaluate("floor(1.56,1)")
%FeelEx.Value{value: 1.5, type: :number}
ceiling
iex> FeelEx.evaluate("ceiling(1.54)")
%FeelEx.Value{value: 2, type: :number}
ceiling with scale
iex> FeelEx.evaluate("ceiling(1.5432,2)")
%FeelEx.Value{value: 1.55, type: :number}
round up
iex> FeelEx.evaluate("round up(1.123,3)")
%FeelEx.Value{value: 1.123, type: :number}
iex> FeelEx.evaluate("round up(1.1234,3)")
%FeelEx.Value{value: 1.124, type: :number}
iex> FeelEx.evaluate("round up(-1.1234,3)")
%FeelEx.Value{value: -1.124, type: :number}
round down
iex> FeelEx.evaluate("round down(-5.5,0)")
%FeelEx.Value{value: -5, type: :number}
iex> FeelEx.evaluate("round down(1.121,2)")
%FeelEx.Value{value: 1.12, type: :number}
round half up
iex> FeelEx.evaluate("round half up(1.126,2)")
%FeelEx.Value{value: 1.13, type: :number}
iex> FeelEx.evaluate("round half up(1.125,2)")
%FeelEx.Value{value: 1.13, type: :number}
iex> FeelEx.evaluate("round half up(1.124,2)")
%FeelEx.Value{value: 1.12, type: :number}
Temporal Expressions
Addition
<date>+<duration>=<date>
iex> FeelEx.evaluate("date(\"2020-04-06\") + duration(\"P1D\")")
%FeelEx.Value{value: ~D[2020-04-07], type: :date}
<time>+<duration>=<time>
iex> FeelEx.evaluate("time(\"08:00:00\") + duration(\"PT1H\")")
%FeelEx.Value{value: ~T[09:00:00], type: :time}
<date-time>+<duration>=<date-time>
iex> FeelEx.evaluate("date and time(\"2020-04-06T08:00:00\") + duration(\"P7D\")")
%FeelEx.Value{value: ~N[2020-04-13 08:00:00], type: :datetime}
<duration>+<duration>=<duration>
iex> FeelEx.evaluate("duration(\"P1D\") + duration(\"PT1H\")")
%FeelEx.Value{value: %Duration{day: 1, hour: 1}, type: :days_time_duration}
Subtraction
<date>-<date>=<duration>
iex> FeelEx.evaluate("date(\"2020-04-06\") - date(\"2020-04-01\")")
%FeelEx.Value{value: %Duration{day: 5}, type: :days_time_duration}
<date>-<duration>=<date>
iex> FeelEx.evaluate("date(\"2020-04-06\") - duration(\"P5D\")")
%FeelEx.Value{value: ~D[2020-04-01], type: :date}
<date-time>-<date-time>=<days-time-duration>
iex> FeelEx.evaluate("date and time(\"2025-01-01T08:00:00\") - date and time(\"2024-01-01T06:00:01\")")
%FeelEx.Value{
value: %Duration{hour: 8785, minute: 59, second: 59},
type: :days_time_duration
}
<date-time>-<duration>=<date-time>
iex> FeelEx.evaluate("date and time(\"2021-01-01T08:00:00\") - duration(\"PT2H\")")
%FeelEx.Value{value: ~N[2021-01-01 06:00:00], type: :datetime}
<years-months-duration>-<years-months-duration>=<years-months-duration>
iex> FeelEx.evaluate("duration(\"P1Y\") - duration(\"P3M\")")
%FeelEx.Value{value: %Duration{month: 9}, type: :years_months_duration}
Multiplication
iex> FeelEx.evaluate("5*duration(\"P1D\")")
%FeelEx.Value{value: %Duration{day: 5}, type: :days_time_duration}
iex> FeelEx.evaluate("13 * duration(\"P1M\")")
%FeelEx.Value{value: %Duration{year: 1, month: 1}, type: :years_months_duration}
Division
iex> FeelEx.evaluate("duration(\"P5D\") / duration(\"P1D\")")
%FeelEx.Value{value: 5, type: :number}
iex> FeelEx.evaluate("duration(\"P1Y\") / duration(\"P2M\")")
%FeelEx.Value{value: 6, type: :number}
iex> FeelEx.evaluate("duration(\"P1Y\") / 12")
%FeelEx.Value{value: %Duration{month: 1}, type: :years_months_duration}
Temporal Properties
Accessing year
iex> FeelEx.evaluate("@\"2021-01-01\".year")
%FeelEx.Value{value: 2021, type: :number}
iex> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05\").year")
%FeelEx.Value{value: 2021, type: :number}
Accessing month
iex> FeelEx.evaluate("@\"2021-01-01\".month")
%FeelEx.Value{value: 1, type: :number}
Accessing day
iex> FeelEx.evaluate("@\"2021-01-01\".day")
%FeelEx.Value{value: 1, type: :number}
Accessing weekday in [1-7] where 1 is Monday
iex> FeelEx.evaluate("@\"2021-01-01\".weekday")
%FeelEx.Value{value: 5, type: :number}
Accessing hour, minute, second
iex> FeelEx.evaluate("time(\"08:01:05\").hour")
%FeelEx.Value{value: 8, type: :number}
iex> FeelEx.evaluate("time(\"08:01:05\").minute")
%FeelEx.Value{value: 1, type: :number}
iex> FeelEx.evaluate("time(\"08:01:05\").second")
%FeelEx.Value{value: 5, type: :number}
Accessing timezone
iex> FeelEx.evaluate("time(\"08:01:05@Europe/Malta\").timezone")
%FeelEx.Value{value: "Europe/Malta", type: :string}
iex> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05@Europe/Malta\").timezone")
%FeelEx.Value{value: "Europe/Malta", type: :string}