22-04-22 10:41 AM
{
"value": [
{
"id": "2",
"fields": {
"Name": "Gadget",
"Color": "Red",
"Quantity": 503
}
},
{
"id": "4",
"fields": {
"Name": "Widget",
"Color": "Blue",
"Quantity": 2357
}
},
{
"id": "7",
"fields": {
"Name": "Gizmo",
"Color": "Green",
"Quantity": 92
}
}
]
}
What my current issue is, I'm pulling around 3900 SharePoint items from a SharePoint List, then looping through the collection, and merging each line to a new collection becomes a very long task.
I've tried a couple different methods, following the Blue Prism 6.4 - Web API User Guide, however I'm unable to get past the "Internal : Unexpected error Path returned multiple tokens."
At the moment my main method has been to set the type to collection, JSONPath, and setting the path to $..fields
or $.value['fields']
I believe this may be because each "Value" has its own "Fields" collection, which means I need some form of a ForEach loop using custom code to extract this information.
If possible, could somebody point me in the right direction to lookup what's needed to do this, or even better have some previous examples of others with a similar issue?
I've found these examples on community so far:
However I've been struggling to adapt the code to meet the needs of this work.
Any help appreciated
Answered! Go to Answer.
25-04-22 12:53 PM
@ewilson Thank you very much for explaining it. That helped massively.
Given I could not use the JSON Pathing I've gone down the custom code route, and put together some work that has thankfully worked. I'm now pulling together around 4000 items in a completed detailed list in less than 30 seconds!
For anybody with a similar issue, wanting to pull SPO List item details from a large SharePoint list, here are a few pointers.
You will need to create an additional API to pull the column headers. I recommend reading here List columnDefinitions in a list - Microsoft Graph v1.0 | Microsoft Docs and adding this to Blue Prism existing SPO GRAPH API on DX.
Name:
Parameters:
Request:
Headers:
Response:
If you have over 200 columns in SharePoint I recommend not using Json Path $.value and instead just $, and then getting the remaining headers with GRAPHs "NextLink" which is returned on the top level.
Now that the API was completed and working I could now get the headers. I stored these in a collection, then wrote these out to a CSV (for use later in some code) then added additional fields that are not a header to the csv. (For example the eTag for referencing the items)
This resulted in a long csv with all my headers.
Now using the "Get Items in List by Fields" Web API Action, return the "Response Content" to a text data item. (This is the JSON we will be using)
I then created a custom code object, added "Response_Content" and "columnHeaders" as the inputs, and "sharePointListItems" as the output.
Then the secret sauce, the code. (I'll include a copy at the bottom)
What we are doing is loading the response back into a JSON, and then moving up a level to "Value".
We then split the CSV headers we got from SharePoint into an array to loop through.
Then we create all our headers for the data in SharePoint by looping through all items in the CSV creating a new column for each one.
Now we loop through all the objects from the JSON, taking the fields data (This is where all the SharePoint list data is stored)
Now again, for each field in the csv from earlier, we call the fields value for that column. and store it in the row, before adding the completed row to the table
Then finally we output the table
Running this code resolved my issue, as I can now pull thousands of records in around 30 seconds. I hope what I found may help some other people out there with a similar issue.
@ewilson Thanks again for your help on understanding Json structure!
Here is the code for compiling the headers and response together:
// Load Response
JObject responseObject = JObject.Parse(Response_Content);
JArray topLevel = (JArray)responseObject["value"];
//Get Headers CSV and create table
string[] headers = columnHeaders.Split(',');
//Create Headers for dataTable
var dataTable = new DataTable();
foreach (string header in headers)
{
dataTable.Columns.Add(header);
}
//Loops each JSON Object and gets the "Fields" data
foreach (JObject Item in topLevel)
{
DataRow row = dataTable.NewRow();
JObject fields = (JObject) Item["fields"];
// Cycles each column header in headers, and polls fields for that information
foreach (var header in headers)
{
row[header] = (string) fields[header];
}
dataTable.Rows.Add(row);
}
sharePointListItems = dataTable;
22-04-22 12:20 PM
22-04-22 12:24 PM
Thanks for your response!
I've just tried this. Sadly still getting
"Internal : Unexpected error Path returned multiple tokens."
22-04-22 12:35 PM
22-04-22 12:40 PM
No problem, I've already tested this far, and yes thankfully this works.
We're getting all of the fields collections through, no problem. and these fields have the data within them.
22-04-22 12:52 PM
@AndrewWilson,
That’s good. You at least have a path forward.
The previous expression is the standard way to iterate a JSON array to pull out child fields. Are there cases where the fields object has more or different children within it than just the Name, Color, and Quantity values shown in your example?
Cheers,
Eric
22-04-22 12:57 PM
{
"value": [
{
"id": "2",
"fields": {
"Name": "Gadget",
"Type": "App"
"Color": "Red",
"Quantity": 503
}
},
{
"id": "4",
"fields": {
"Name": "Widget",
"Color": "Blue",
}
},
{
"id": "7",
"fields": {
"Name": "Gizmo",
"Type: "Item"
"Quantity": 92
}
}
]
}
There are around 50 headers in total, with each returning around 46 headers, give or take a few, due to missing information.
Edit: Just to confirm, "value", "id", and "fields" will always be present
22-04-22 01:38 PM
22-04-22 02:29 PM
22-04-22 02:44 PM
$.staff-database["employee"]
NOTE: The JSON Path expression above returns the same output at $.staff-database
$.value
You'll get the following output:
This is a JSON array of JSON objects. So we have a slightly different JSON definition: JSON Array, JSON Array, JSON Objects vs JSON Array, JSON Objects
If you wanted to get a similar a result from the Web API example JSON, you would need to use a JSON Path expression like this:
$.staff-database["employee"]
This would give you the following output:
If Blue Prism is parsing a JSON array of objects it looks at the very first object in the array (assumption that arrays always contain items that are same type/definition) and uses that as the blue print of the DataTable it creates in memory to contain a row for each item in the array. It performs this interpretation exactly 1 time. If Blue Prism is parsing an array of objects within another array, it's interpreting the JSON object definition every time it sees a new row in the contained array. In that case, the blue print of the DataTable can actually change from one row to the next.
Does that help?
Cheers,
Eric