Link to home
Start Free TrialLog in
Avatar of kalyangkm
kalyangkmFlag for United States of America

asked on

Drop XML records based on items in an array using Groovy

Hi Folks,


I have an XML with a bunch of records with UserID being the unique value in all. And also have an array of UserIDs. Using Groovy I need to retain only those records in the XML which exists in the

userArray = ["885247","1149285"]

Open in new window

 I have a groovy which only brings me one record. I am not good at groovy with XML parsers please suggest how to make it work properly


XML

<EmpJob>
    <EmpJob>       <managerId>1130351</managerId>       <userId>1158278</userId>       <managerUserNav>         <User>           <defaultFullName>Roy coon</defaultFullName>         </User>       </managerUserNav>     </EmpJob>     <EmpJob>       <managerId>874274</managerId>       <userId>4072314</userId>       <managerUserNav>         <User>           <defaultFullName>Roman Card</defaultFullName>         </User>       </managerUserNav>     </EmpJob>     <EmpJob>       <managerId>73661</managerId>       <userId>42479</userId>       <managerUserNav>         <User>           <defaultFullName>Pawan Kalyan</defaultFullName>         </User>       </managerUserNav>     </EmpJob>     <EmpJob>       <managerId>NO_MANAGER</managerId>       <managerUserNav/>       <userId>1149285</userId>     </EmpJob>     <EmpJob>       <managerId>794895</managerId>       <userId>885189</userId>       <managerUserNav>         <User>           <defaultFullName>BEVERLY Hills</defaultFullName>         </User>       </managerUserNav>     </EmpJob>     <EmpJob>       <managerId>476232</managerId>       <userId>885247</userId>       <managerUserNav>         <User>           <defaultFullName>Bruno Abdulla</defaultFullName>         </User>       </managerUserNav>     </EmpJob>    </EmpJob>

Open in new window


My groovy:

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap; import groovy.xml.XmlUtil; import groovy.xml.StreamingMarkupBuilder; import groovy.xml.*; def Message processData(Message message) {       //Body        def body = message.getBody();       def list=new XmlParser().parse(body);      // def userList = message.getProperty("userIDs");       String[] userArray = ["885247","1149285"];       def newPayload;              userArray.eachWithIndex { id ->                def newNode = list.EmpJob.findAll{ it.userId.text() == id }       newPayload.appendNode(newNode);                         }              message.setBody(XmlUtil.serialize(newPayload));       return message; }

Open in new window


I need the following XML output which I am not able to achieve with the above groovy


<EmpJob>
    <EmpJob>
      <managerId>NO_MANAGER</managerId>
      <managerUserNav/>
      <userId>1149285</userId>
    </EmpJob>
    <EmpJob>
      <managerId>476232</managerId>
      <userId>885247</userId>
      <managerUserNav>
        <User>
          <defaultFullName>Bruno Abdulla</defaultFullName>
        </User>
      </managerUserNav>
    </EmpJob>
</EmpJob>

Open in new window

Avatar of Gertone (Geert Bormans)
Gertone (Geert Bormans)
Flag of Belgium image

Have you considered passing the array as a sequence in a parameter to an XSLT?
You are using XSLT2.0 or above, I believe.
It would be a really easy job to do then
Avatar of kalyangkm

ASKER

Hi Geert,

I am not sure I understand. Could you please elaborate on "passing the array as sequence in a parameter". Just FYI, in my case the array would be passed as an array list from another groovy script
An XSLT can have a global parameter (xsl:param)
You can pass information through the parameter on calling for the XSLT
If it is a groovy array, you could flatten it to something like this ('885247','1149285')
which the XSLT processor would understand as a sequence (if you type it as a sequence)
And then you could test for the different user id in the xslt

In a meeting right now. I could make some examples later
Are you calling the XSLT from groovy?
I am not calling the XSLT from groovy. I have no problem using XSLT but the only issue I have is passing the array to this XSLT.
Hi Geert, just checking if you had chance to look at some examples you mentioned?
ASKER CERTIFIED SOLUTION
Avatar of Gertone (Geert Bormans)
Gertone (Geert Bormans)
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Most XSLT processors allow you to do this from the command line
users=('1158278','885247')

Open in new window

I picked two different ones to test they are picked up

Since you are using XSLT 3, you are likely using Saxon.
In order for Saxon to pick up the sequence up as a sequence instead of a string, you need to tell Saxon that the parameter is an Xpath instead of a string
You can do that by prepending the parameter with a ? in the command line execution
?users=('1158278','885247')

Open in new window

works like a charm

All you need to do now is flatten the groovy array (preferably no spaces) output it inside a batch or shell script file and execute the script.
I prefer that over filtering straight in groovy, but opinions may differ
Hi Geert,

Thanks for the example. I am able to run he XSLT with static values for UserID. But Now I would need to understand how can I pass an arraylist of UserIDs from another Groovy to this XSLT.

I got some help and able to make my groovy work, But would like to see how the same logic can be done in XSLT which I am more interested in. I suppose there is a small modification that needs to be done to your XSLT solution that you gave above where you are passing static values "users" select="('885247','1149285')". Instead of this I need to pass the whole array list.

The groovy which is working to get the filter UserID is the following:
In this groovy I am initializing userID and passing "IDs" (which is an ArrayList from another groovy outside the program) the  "def userID = message.getProperty("IDs")".....is what I am referring to. so please let me know how to achieve this part in XSLT
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import groovy.xml.XmlUtil;
import groovy.xml.StreamingMarkupBuilder;
import groovy.xml.*;

def Message processData(Message message) {
    //Body 
    def body = message.getBody(java.lang.String) as String;
    def list = new XmlParser().parseText(body);
    def userID = message.getProperty("IDs");
    List<String> userList  = Arrays.asList(userID.replace("'","").split("\\s*,\\s*"));
    //String[] userIdArray = userList.split(',');

    list.EmpJob.each {

        def notPresent = true;

        userList.each { arrayItem ->

                if (it.userId.text() == arrayItem) {
                    notPresent = false;
                }
        }

        if (notPresent == true) {
            list.remove(it);
        }
    }

    message.setBody(XmlUtil.serialize(list));
    return message;
}

Open in new window


The explanation is in my last comment
- in groovy get the user ids
- dump the array to a string of the above shown form
- pass that to saxon as if it was not a string but an XPath

Maybe you need to start by saying how you call an XSLT process

And maybe,if all is one groovy script, a full blown groovy solution is better
sorry, I am totally lost with the second part of the solution that you gave earlier about the XPath.

you think the solution I have in Groovy is better than implementing in XLST?
Well, the concept to understand is that you can pass in a parameter when you execute an XSLT
This way you can modify the behavior of the stylesheet

In this case the parameter is not a fixed string, but an array that you receive from groovy

Looking at the groovy solution you have, I would suggest you stick to that indeed

Thanks for your feedback.