how to loop over a document list that has a dynamic name?

hello

i have a requirement in which i have to loop over below structure to retrieve shift details, 1 machine having 3 shift everyday -

shifts (doc) /machineName (doc list)* / ShiftAdetails [0]
shifts (doc) /machineName (doc list)* / ShiftBdetails [1]
shifts (doc) /machineName (doc list)* / ShiftCdetails [2]

machineName → dynamic value, will be a 3 digit numeric value. Example “001_10”,“233_10”

Any means to have the dynamic name in loop i/p array? If not loop how else this can be handled?

Regards,
Shreyus

Loop input array you must specify a variable in the pipeline that is an array data type (that is, String list, String table, document list, or Object list).

Can you share your IS document structure or even a screen shot?

IMO dynamic names as the loop input is not possible. You will have to map the list to a temp list with a fixed name (to do this, you’ll probably have to create a java service; I don’t rememeber whether WmPublic does contain a service for this purpose). The mapping will not duplicate the list, just make it available in the pipeline under a fixed name. Then you can use that var as the input in a loop statement.

hello,

The document structure is as per the attachment.

I need to loop over the 123 - machine A (ShiftDetails/machineNames/123 (machineA)) to fetch corresponding shift A,B,C details. In run time the machine name will be a numeric value so i am thinking how we can pass these dynamic numeric values to loop i/p array.

Tried having the possible machine names in a config file and perform value substitution in loop i/p array in runtime (ShiftDetails/machineNames/%machineName%), but does’nt work!, it seems loop i/p array accepts only static namespace.

Any ideas?

Thank you.
DocStructure_ShiftDetails.PNG

I don’t think it is possible to pass dynamic name as per your requirement. You should give some name to loop over.

Thanks,

Shreyus,

How is the attached IS document created? Manually created or through XSD…

I assume for your requirement the services in WmPublic/pub.document**** might help please read the BIS guide for more details.

If it does not help we must think of another approach either java code or mapping the doc list to a temp doc list and check if the name of the document list is what you are interested in and so on.

hi Mahesh,

The document is created from a JSON i/p, thats why it has so many arrays. Managed to parse it in 7.3 using custm java service.

Even to map the doc list to a temp doc list, i don’t have the doc list in i/p but instead a document (machineNames) which has multiple doc lists in it.

ShiftDetails/machineNames/123 (machineA) [0] [shifts (doc) /machineName (doc list)* / ShiftAdetails [0] ]
ShiftDetails/machineNames/456 (machineB) [0]

let me know if its not clear.

Thanks for the help!

Regards,
Shreyus

Like fml2 suggested, you will have to create a Java service that takes your structure as input and returns something that can be consumed by the LOOP construct. I would recommend a Java service that transforms your structure into something like this:

shifts (doc)

  • machines (doc list)
    @name (machine name in case you need it)
    – shifts (doc list)
    — A (doc)
    — B (doc)
    — C (doc)

With this structure, you could have a nested LOOP. The outerloop would loop over the machines and the innerloop would loop over the shifts for each machine.

Makes sense?

Percio

Hi Shreya,

Do you need the shifts alone or do you need other data as well.

Regards,
Jacob B

Hi,

Need to fetch data that is inside shifts (doc) /machineName (doc list)* / ShiftAdetails [0], shifts (doc) /machineName (doc list)* / ShiftAdetails [1] and so on…

Regards,
Shreyus

Have you not been able to arrive at a solution based on the feedback given here? If not, please send a sample XML document (it can be a saved pipeline) and I’ll try to help you with that Java service I mentioned.

Percio

I have an open source project called Tundra, which is an Integration Server package that has heaps of services, and in particular has a number of services in it that are useful for dealing with IData document structures that are not known at design time.

For your requirement, you can use the service tundra.document:keys mapping ShiftDetails/machineNames to the $document input, and it will return a string list $keys containing all the keys in ShiftDetails/machineNames (i.e. $keys = [“123”, “456”] for your example).

Then use a loop step which iterates over the $keys, and within the loop invoke tundra.document:get mapping ShiftDetails/machineNames to the $document input, and $keys to the $key input, and it will return the value associated with that key in ShiftDetails/machineNames as $value (i.e. for the first iteration it would return the 123 document list as $value, and on the second iteration would return the 456 document list as $value). Then map $value to a new variable with the document list structure of machineNames, and process it as needed.

If you don’t want to, or are not allowed to, include Tundra in your solution, then taking inspiration from the above you could use the following two simple Java services to achieve the same thing:

  1. A Java service which returns all the top-level keys in a given IData document (the service has one optional input “document” which is an IData document, and one optional output “keys” which is a string list):

    IDataCursor cursor = pipeline.getCursor();

    try {
        IData document = IDataUtil.getIData(cursor, "document");

        if (document != null) {
            List<String> keys = new ArrayList<String>();

            IDataCursor documentCursor = document.getCursor();
            while(documentCursor.next()) {
                keys.add(documentCursor.getKey());
            }
            documentCursor.destroy();

            IDataUtil.put(cursor, "keys", keys.toArray(new String[keys.size()]));
        }
    } finally {
        cursor.destroy();
    }
  1. A Java service which returns the value associated with a top-level key from a given IData document (the service has two optional inputs, “document” which is an IData document and “key” which is a string, and one optional output “value” which is an object):

    IDataCursor cursor = pipeline.getCursor();

    try {
        IData document = IDataUtil.getIData(cursor, "document");
        String key = IDataUtil.getString(cursor, "key");

        if (document != null && key != null) {
            IDataCursor documentCursor = document.getCursor();
            if (documentCursor.first(key)) {
                IDataUtil.put(cursor, "value", documentCursor.getValue());        
            }
        }
    } finally {
        cursor.destroy();
    }

Another approach would be to use tundra.document:pivot which takes in a document (IData) and returns a document list (IData) where each item in the list is a key value pair representing the elements in the original document. You can then loop over pivot result and process each value as required.

Again, if you are not able to include Tundra in your solution, here’s an example Java service which pivots the top-level elements of a document (IData):


    IDataCursor cursor = pipeline.getCursor();

    try {
        IData document = IDataUtil.getIData(cursor, "document");

        if (document != null) {
            java.util.List<IData> pivot = new java.util.ArrayList<IData>();
            
            IDataCursor documentCursor = document.getCursor();
            while(documentCursor.next()) {
                IData item = IDataFactory.create();
                IDataCursor itemCursor = item.getCursor();
                IDataUtil.put(itemCursor, "key", documentCursor.getKey());
                IDataUtil.put(itemCursor, "value", documentCursor.getValue());
                itemCursor.destroy();
                
                pivot.add(item);
            }
            documentCursor.destroy();

            IDataUtil.put(cursor, "pivot", pivot.toArray(new IData[pivot.size()]));
        }
    } finally {
        cursor.destroy();
    }

You could use pub.document:documentToDocumentList to handle the dynamic name. By providing service input “name”, you could convert a dynamic doc name to variable with specific name (the same with input “name”).
Please refers to the attached sample.

2 Likes

Hi Wang,

Wow… this looks very simple and perfect to handle…

Excellent… :smiley:

Regards,
Jacob B