Integration Toolkit Solutions Wiki

Storing IPv4 addresses as integers (rather than strings)

String IP addresses displayed in tables don't sort naturally. e.g., x.x.x.1, x.x.x.10, x.x.x.11, x.x.x.2.
Storing the IP addresses in the database as a 32-bit integer (which is what they are supposed to represent), and returning those to a table column but rendering them with a view to convert to four-decimal octet format solves the sorting problem.

From IP address to integer

With the built-in expression language the job can be done in two stages (to simplify the expression):

Initial expression

split({path.to.IP.as.string}, '\\.')

Expression transform
// Doing this in two steps allows the use of {value} rather than multiple splits.
  ({value}[0, 0] << 24)
+ ({value}[1, 0] << 16)
+ ({value}[2, 0] << 8)
+ ({value}[3, 0] << 0)

With the Integration Toolkit it can be done in one go.

Integration Toolkit solution
transform(
	split({path.to.IP.as.string}, '\\.'),
	(value()[0, 0] << 24) +
	(value()[1, 0] << 16) +
	(value()[2, 0] << 8) +
	(value()[3, 0] << 0)
)

These expressions assume that the incoming IP β‰₯ 1.x.x.x.

From integer to IP address

With the built-in expression language the job can be done in two stages (to simplify the expression):

Initial expression

toInt({../lblIp2IntExpression.props.text})

Expression transform
// Doing this in two steps allows the use of {value} rather than multiple splits.
stringFormat(
	"%d.%d.%d.%d",
	({value} >> 24) & 0xff,
	({value} >> 16) & 0xff,
	({value} >> 8) & 0xff,
	{value} & 0xff
)

With the Integration Toolkit it can be done in one go.

Integration Toolkit solution
// This was my original attempt.
// See Phil's improved solution below.
transform(
	right('0' + toHex({path.to.IP.as.integer}), 8),
	fromHex(subString(value(), 0, 2)) + '.' +
	fromHex(subString(value(), 2, 4)) + '.' +
	fromHex(subString(value(), 4, 6)) + '.' +
	fromHex(subString(value(), 6, 8))
)

These expressions assume that the incoming integer represents an IP β‰₯ 1.x.x.x.

Edit by Phil: I would do the conversion to display without using hex strings.

Better Integration Toolkit Solution
transform(
	toInt({path.to.IP.as.integer}),
	stringFormat(
		"%d.%d.%d.%d",
		(value() >> 24) & 0xff,
		(value() >> 16) & 0xff,
		(value() >> 8) & 0xff,
		value() & 0xff
	)
)

Does not require the leading octet to be β‰₯1.

IPv6 is not addressed by these functions.

1 Like

Iterating through an array-tag to determine if value is present

Casus: A camera is selected on a video-wall if it’s ID (UDT-parameter) is present in a tag of the type Integer array (external system). So I want to use an expression-tag to determine if the camera is selected (boolean).

Approach: Iterate through the array with forEach (or where?) and compare each value to the integer ID-value. If found -> true, else false

Initial expression

forEach returns a list if expression is met?
Then check if this list has one or more entries.

if(
	len(
		forEach( 
			{[~]MSBS/SLKRS1_I1/CCTV/Pnl/STS/CameraNr.value}, 
			it() = {ArrayID}
		)
	) > 0,
	true,
	false
)

Status: Error in the tag (Error Config)? What do I do wrong?
Tips:
forEach() always returns a list. But per my previous reply, use where() instead of forEach(). Do not wrap an if() around the whole thing, as a comparison with len() yields a boolean directly.

Improved expression

Note: I've moved the source (array) tag to be in the same folder as the expression-tag in order to supply an export-file (attached) if anybody is interested in reproducing/solving the issue.

len(
	where( 
		{[.]CameraNr.value}, 
		it() = {ArrayID}
	)
) > 0

Previous improvements applied, still an Error_Configuration (Error writing to Geselecteerd.value: Bad_Unsupported)

ExpressionTagAndSource.json (784 Bytes)

Creating a list of Months in format YYYY-MM between a start and end date

Note: forEach(10, it()) is equivalent to range(10) in Python.

Expression Structure Binding:

start: 2025-06-01 0:00:00
end: 2025-10-01 00:00:00
forEach(
	forEach(monthsBetween({value}['start'], {value}['end'])+1, it()),
	dateFormat(addMonths({value}['start'], it()), 'YYYY-MM')
)

Returns:

[
  "2025-06",
  "2025-07",
  "2025-08",
  "2025-09",
   "2025-10"
]

One of the forEach() loops is unneeded. forEach() returns a list, so your outer loop is actually forEach(asList(0,1,2,3,4),it())

forEach(
    monthsBetween({value}['start'],{value['end']) + 1,
    dateFormat(addMonths({value}['start'],it()),'YYYY-MM')
)

Will yeild the same result.

Features employed
  • Iterables General behavior of all iterators.
  • forEach() Loops through the dataset, calling the nested expression with one row at a time.
  • it() Delivers the one row in dataset format (same column names and types as the source).
  • monthsBetween() Calculates the number of whole months between two dates.
  • addMonths() Add or subtract an amount of months to a given date and time.
  • dateFormat() Returns the given date as a string, formatted according to a pattern.

Pssst! Use yyyy-MM to avoid year-end confusion over week-years.

4 Likes