A couple of little refinements to suggest here:
1. Using 'applyXPath' can simplify the process of extracting objects and attributes, and protects you against unexpected data being returned due to later edits - e.g. if you ever add an attribute, or change the order of the attribute list in the 'select'.
2. The Javascript 'sort' facility makes sorting arrays - including arrays of objects - easy.
Here's an example where 'applyXPath' first extracts out the 'UDSObject' elements, and then from each UDSObject extracts the 'sequence' and 'handle' attributes, builds a 'Task' object for each pair and adds it to an array, then uses the sort function to sort the array of Task objects into sequence number order. This is the Post-execution code for a 'doSelect' that pulls all of the 'Group Start' tasks for a change.
//
// Find the insertion point for implementation tasks in the new change.
// The insertion point is the last GRPSTART in the change.
//
var myUDSOs = [];
var myGRPSTARTh = "";
var myGRPSTARTs = 0;
//
// Task 'object' declaration
//
function Task(sequence, handle)
{
this.sequence = sequence;
this.handle = handle;
}
if (typeof Process[OpName].SoapResponseData.doSelectReturn == "undefined")
{
// No GRPSTARTs. This would be very surprising!
Process.myTrace.unshift("New change has no GRPSTARTS");
}
else
{
// Extract the GRPSTART task details:
var myText = Process[OpName].SoapResponseData.doSelectReturn[0].text_;
myUDSOs = applyXPath(myText, "//UDSObject", false, true);
Process.myTrace.unshift("myUDSOs length " + myUDSOs.length);
if (myUDSOs.length > 0)
{
// Sort them in sequence order
var sortTasks = [];
var mySeq = 0;
var myHandle = "";
// Extract sequence and handle from each UDSO.
for (i=0; i < myUDSOs.length; i++)
{
// Within the UDSO, 'sequence' is formatted as
// an <AttrName>sequence</AttrName><AttrValue>4055</AttrValue> pair,
// but Handle is an element in its own right: <Handle>wf:401005</Handle>
//
mySeq = applyXPath(myUDSOs[i], "//AttrName[text() = 'sequence']/../AttrValue/text()" );
myHandle = applyXPath(myUDSOs[i], "//Handle/text()" );
Process.myTrace.unshift("GRPSTART sequence "+mySeq+", handle "+myHandle+" extracted.");
sortTasks[i] = new Task(mySeq, myHandle);
}
// Sort the tasks by sequence, ascending.
sortTasks.sort(function(a,b) { return a.sequence - b.sequence } );
if (sortTasks.length > 1)
{
//
// Insertion point for Implementation tasks is the last GRPSTART.
//
myGRPSTARTh = sortTasks[sortTasks.length - 1].handle;
myGRPSTARTs = sortTasks[sortTasks.length - 1].sequence;
}
}
}
Process.impTaskGRPSTARTHandle = myGRPSTARTh;
Process.impTaskGRPSTARTSeq = myGRPSTARTs;
//
// From this point, if impTaskGRPSTARTSeq is 0, can proceeed no further.
//