You are viewing limited content. For full access, please sign in.

Discussion

Discussion

Feature Request: Encode Forms Data as JSON

posted on February 25, 2021 Show version history

We regularly work on projects that consist of multiple Forms BPs, and need to ferry data from one to the other. To do this, we use Workflow to first encode the data of the original process as JSON, then we stick it into a database table, then retrieve it later and parse it with Read JSON activity.

The encoding is something we have to do by hand, which gets very very cumbersome and annoying when you deal with table rows especially.

It would be very helpful if Workflow could do it out of the box. 

(I think since Forms passes its data to Workflow as JSON anyway, it might just be a matter of Workflow exposing that entire dataset as a token.)

1 0
replied on March 1, 2021 Show version history

As another use case, rather than just storing the values for later use by another BP, I'm using JSON to pass values to a SQL proc that performs extensive validation on the form data. Trying to use Retrieve Business Process Variables to pass table values to SQL did not end well.

An activity that, given the Forms server and Instance, simply outputs JSON of all current variable values would be ideal. Especially if it would work without having to select a BP.

I ended up writing a SQL proc to build the JSON from the Forms database, which is probably a terrible idea. It's working well for me so far, but I'm sure there are things not being handled correctly (e.g. collections? I haven't used those much).

-- ================================================================================================
-- Author:		Scott Minar
-- Create date:	2018-08-10
-- Description:	Constructs JSON with all values from an instance
-- /*==============================================================================================
ALTER PROC [forms].[VariableValues_json] (
	@instance INT
	) AS
SET NOCOUNT ON
--*/
/*
DECLARE @instance INT = 44983;
--*/
DROP TABLE IF EXISTS #members;
SELECT
	*
	INTO #members
	FROM (
		SELECT
			mi.bp_instance_id
			,s.submission_id
			,f.form_id
			,ds.attribute_type
			,ds.member_id
			,m.parent_entity_id
			,m.entity_associated_id
			,m.[name]
			,d.[value]
			,d.member_path
			,rn = ROW_NUMBER() OVER(PARTITION BY d.member_path ORDER BY s.date_created DESC)
			FROM LF_Forms.dbo.cf_bp_main_instances mi
			INNER JOIN LF_Forms.dbo.cf_submissions s
				ON mi.bp_instance_id = s.bp_instance_id
			INNER JOIN LF_Forms.dbo.cf_form_submissions fs
				ON s.submission_id = fs.submission_id
			INNER JOIN LF_Forms.dbo.cf_bp_step_form_mapping sfm
				ON mi.process_id = sfm.process_id
				AND fs.step_id = sfm.step_id
			INNER JOIN LF_Forms.dbo.cf_fields f
				ON sfm.form_id = f.form_id
				AND f.[type] <> 'table-end'
			INNER JOIN LF_Forms.dbo.cf_bp_dataset ds
				ON f.attribute_id = ds.attribute_id
			INNER JOIN LF_Forms.dbo.members m
				ON ds.member_id = m.id
			INNER JOIN LF_Forms.dbo.cf_bp_data d
				ON fs.submission_id = d.submission_id
				AND f.attribute_id = d.attribute_id
			WHERE mi.bp_instance_id = @instance
		) x
	WHERE rn = 1
	;
INSERT INTO #members (bp_instance_id,submission_id,form_id,parent_entity_id,[name],[value]) VALUES (@instance,0,0,0,'Instance',@instance);
SELECT [json] = '{' + STUFF((
	SELECT
		',"' + [name] + '":' + CASE attribute_type
			WHEN 'table' THEN 
				'[' + stuff((
					SELECT
						',{' + stuff((
							SELECT
								',"' + [name] + '":"' + STRING_ESCAPE([value],'json') + '"'
								FROM (
									SELECT
										[name]
										,[value]
										,member_path
										FROM #members
									UNION ALL
									SELECT
										'Entry'
										,x.[entry]
										,p.member_path + x.[entry] + '.0'
									) d
								WHERE member_path LIKE p.member_path + x.[entry] + '.%'
									AND NULLIF([value],'') IS NOT NULL
								FOR XML PATH(''), TYPE
							).value('.','VARCHAR(MAX)'),1,1,'') + '}'
						FROM #members m
						INNER JOIN #members p
							ON m.parent_entity_id = p.entity_associated_id
						CROSS APPLY (VALUES
							(LEFT(REPLACE(m.member_path,p.member_path,''),CHARINDEX('.',REPLACE(m.member_path,p.member_path,'')) - 1))
							) x ([entry])
						WHERE p.member_path = o.member_path
						GROUP BY p.member_path
							,x.[entry]
						FOR XML PATH(''), TYPE
					).value('.','VARCHAR(MAX)'),1,1,'') + ']'
			ELSE '"' + STRING_ESCAPE([value],'json') + '"' END
		FROM #members o
		WHERE NULLIF([value],'') IS NOT NULL
			AND NOT EXISTS (
				SELECT 1 FROM #members
					WHERE entity_associated_id = o.parent_entity_id
				)
		FOR XML PATH(''), TYPE
	).value('.','VARCHAR(MAX)'),1,1,'') + '}'
	;

 

0 0
replied on February 25, 2021

Have you considered just storing the Instance Id and Submission Id values in the table and then reading them back later for use in the Retrieve Business Process Variables activity?

Rather than storing data in multiple places, I just store the reference to the instance/submission and retrieve the data later by plugging those values into the advanced properties for the RBPV activity.

For one process I have multiple business processes involved, so I also track the "source" process, then have a branch in the workflow that decides which BP to look at based on that column.

2 0
replied on February 25, 2021

Yeah, this is a good idea. We already store the Instance ID and Submission ID, so I'll test it out.

1 0
You are not allowed to follow up in this post.

Sign in to reply to this post.