Adding an Array from one JSON Object to another with UDO
January 12, 2023
Starting with UniVerse 11.1 and UniData 7.3, U2 Dynamic Objects (UDO) provides you with extended basic functions to create and consume JSON and/or XML documents. One question I’ve been asked numerous times is “how do I manage Arrays in UDO objects, and how do I combine properties from multiple objects.”
Before I discuss UDO Array manipulation and adding properties from one object to another, I’ll start with the basics.
In UDO the valid types are:
- Binary (UDO_FALSE and UDO_TRUE)
- Null (UDO_NULL)
- Numeric (UDO_NUMBER)
- String (UDO_STRING)
- Array (UDO_ARRAY)
- Object (UDO_OBJECT)
Here are the steps you’ll follow to create a simple JSON object that contains all of the above types:
Step 1: The UDO.H include file contains the parameter used in the UDO API
(for UniData the include file is INCLUDE, and for UniVerse it is UNIVERSE.INCLUDE)
*
$INCLUDE INCLUDE UDO.H
*
Step 2: Create the initial OBJECT
ST = UDOCreate(UDO_OBJECT, udoHandle); GOSUB TEST_AND_DISPLAY
A newly created UDO Object looks like:
{ }
Please note you cannot directly display the internal structure for a:
- UDO_OBJECT
- UDO_ARRAY
- UDO_TRUE
- UDO_FALSE or
- UDO_NULL
or you will get the following runtime error message:
In C:\U2\ud82\sys\CTLG\c\CREATE_SIMPLE_JSON at line 9 Illegal use of the file, select, cursor, BCI, Socket, HTTP, XML, UDO, SCTX ,MQS, SOAP, Python or database variable.
Side note: I will be using the internal subroutine TEST_AND_DISPLAY. It will display the string representation of the UDO_OBJECT ‘udoHandle’. I am adding this so we can see how the object changes throughout the program.
TEST_AND_DISPLAY:
IF ST = UDO_SUCCESS THEN
ST = UDOWrite(udoHandle, UDOFORMAT_JSON, outputString)
CRT outputString
END ELSE
S = UDOGetLastError(errorCode, errorMessage)
CRT "There was an issue: "
CRT errorCode, errorMessage
END
RETURN
Step 3: You can add simple types as name value pairs to the JSON Object
name = "myString"
value = "This is a string"
ST = UDOSetProperty(udoHandle, name, value); GOSUB TEST_AND_DISPLAY
name = "myNumber"
value = 1.25
ST = UDOSetProperty(udoHandle, name, value); GOSUB TEST_AND_DISPLAY
After adding the two properties the UDO Object now looks like:
{
"myString": "This is a string",
"myNumber": 1.250000
}
Step 4: Adding binary types and null Elements
Note that you need to create the binary object first, then add to the UDO Object
name = "myTrue"
ST = UDOCreate(UDO_TRUE, value);
ST = UDOSetProperty(udoHandle, name, value); GOSUB TEST_AND_DISPLAY
*
name = "myFalse"
ST = UDOCreate(UDO_FALSE, value)
ST = UDOSetProperty(udoHandle, name, value); GOSUB TEST_AND_DISPLAY
*
name = "myNull"
ST = UDOCreate(UDO_NULL, value);
ST = UDOSetProperty(udoHandle, name, value); GOSUB TEST_AND_DISPLAY
After you add the above properties, the UDO Object now looks like:
{
"myString": "This is a string",
"myNumber": 1.250000,
"myTrue": true,
"myFalse": false,
"myNull": null
}
Step 5. Creating and working with Arrays
Now that you know how to add the simple types, let’s get into something a little bit more complicated.
Working With Arrays:
When you create a new Array object, it is considered stand-alone. This is different than working with an Array that is part of another UDO object. For simplicity purposes, we will create a simple Array, and use several of the UDO Functions related to Arrays.
Step 5.1 Create the empty Array
ST = UDOCreate(UDO_ARRAY, theArray)
Step 5.2 Append items into the array
We can add items to the Array with either of the following two functions:
UDOArrayAppendItem(udoHandle, value)
UDOArrayInsertItem(udoHandle, index, value)
Appending items puts the next item at the end of the Array:
value = "A Rock"
ST = UDOArrayAppendItem(theArray, value)
value = "And a Hard Place"
ST = UDOArrayAppendItem(theArray, value)
After appending the two items the Array looks like:
["A Rock", "And a Hard Place"]
Step 5.3 Insert an item between the two Array elements
index = 2
value = "yourself"
ST = UDOArrayInsertItem(theArray, index, value)
Note that at any time, we can attach the array to a property of our original UDO Object.
Step 5.4 Add the Array to our original UDO object.
name = "myArray"
ST = UDOSetProperty(udoHandle, name, theArray); GOSUB TEST_AND_DISPLAY
After adding the Array, the UDO Object now looks like:
{
"myString": "This is a string",
"myNumber": 1.250000,
"myTrue": true,
"myFalse": false,
"myNull": null,
"myArray": ["A Rock", "yourself", "And a Hard Place"]
}
Step 6: Removing/Changing elements in theArray after setting it to a UOD Object Property
Since we added the stand-alone reference for the Array to the UDO Object, we can continue to work with the Array handle ‘theArray’, and changes will be applied to the original UDO object we added it to.
First let’s remove yourself from the array.
index = 2
ST = UDOArrayDeleteItem(theArray, index)
Then change the 2nd Element
index = 2
value = "beats scissors"
ST = UDOArraySetItem(theArray, index, value)
When we write out our final UDO Object to a JSON string it looks like:
{
"myString": "This is a string",
"myNumber": 1.250000,
"myTrue": true,
"myFalse": false,
"myNull": null,
"myArray": ["A Rock", "beats scissors"]
Step 7 Moving an Array from one UDO_OBJECT to another
If we get an Array element from another UDO object, it is not considered stand-alone. It is part of the original UDO_OBJECT, and cannot be added to the new object until we clone it ( make a copy that is stand-alone)
Step 7.1 Instantiating a new UDO Object from a JSON String.
To show the issue with non-stand-alone object handles, we will need to create a new UOD object from the JSON string:
{ "thisArray": [ 1, 2, 3, 4, 5, 6] }
JSON = ' { "thisArray": [ 1, 2, 3, 4, 5, 6] }'
ST = UDORead(JSON, UDOFORMAT_JSON, newObjectHandle)
Step 7.2 After instantiating the UDO Object, we can get the property
Since there is only one property in the UDO_OBJECT, we can use the UDOGetNextProperty function.
ST = UDOGetNextProperty(newObjectHandle, name, newArray, value_type)
We now have the 'thisArray' property in our newObjectHandle, and since it is tied to that object it is not stand-alone, and we cannot directly add it to our original UDO_OBJECT.
Step 7.3 Trying to add a non-stand-alone object
name = "newArray"
ST = UDOSetProperty(udoHandle, name, newArray); GOSUB
TEST_AND_DISPLAY
After running the above, you will see that ST is set to -1, which indicates an error.
Then, with the output from the UDOGetLastError function, you find that the error is that the object is not stand-alone.
S = UDOGetLastError(errorCode, errorMessage)
CRT errorCode, errorMessage
3 Not a stand-alone UDO object/array
Step 7.4 Cloning the handle to the Array so it can be added to the original UDO_OBJECT
ST = UDOClone(newArray, newArrayHandle)
ST = UDOSetProperty(udoHandle, name, newArrayHandle); GOSUB
TEST_AND_DISPLAY
The udoHandle now contains the new property from the other UDO object.
{
"myString": "This is a string",
"myNumber": 1.250000,
"myTrue": true,
"myFalse": false,
"myNull": null,
"myArray": ["A Rock", "beats scissors"],
"newArray": [1, 2, 3, 4, 5, 6]
No matter if you create your own JSON object from scratch, or start from an existing JSON ( or XML ) document, you now know how to manipulate the Array elements, and move properties from one UDO Object to another.