SOA Composite XSLT Transformation - xslt-2.0

Sample input data
interfaceSourceCode,requisitioningBUName,InterfaceHeaderKey,CategoryName,CurrencyCode,DeliverToLocationCode,DeliverToOrganizationCode,DestinationTypeCode,InterfaceLineKey,ItemDescription,ItemNumber,LineType,NoteToBuyer,ProcurementBUName,Quantity,RequesterEmail,UnitOfMeasureCode,Price,ChargeAccountSegment1,ChargeAccountSegment2,ChargeAccountSegment3,ChargeAccountSegment4,ChargeAccountSegment5,ChargeAccountSegment6,ChargeAccountSegment7,DistributionQuantity,InterfaceDistributionKey,Percent
SCO,XXXX Internal Customer Service - CA,300000039139651,"Chemicals, Lubricants and Non-Gen Fuels.Additives.Additives",CAD,Nisku Distribution Centre,NDC,INVENTORY,400000039139652,"TRANSFORMER, 25 KVA OH, 12470GRDY/7200/347/600Y 1PH C/W TAPS SPEC. #YECL-T-15",16340094,Goods,TEST12345678,XXXX Internal Customer Service - CA,6,xyz#discard.mail.us2.oracle.cloud.com,zzr,500,10002,00000,00000,00000,130000,00000,00,6,500000039139652,100
SCO,XXXX Internal Customer Service - CA,300000039139651,"Chemicals, Lubricants and Non-Gen Fuels.Additives.Additives",CAD,Nisku Distribution Centre,NDC,INVENTORY,400000039139653,"TRANSFORMER, 25 KVA OH, 12470GRDY/7200/347/600Y 1PH C/W TAPS SPEC. #YECL-T-15",16340094,Goods,TEST12345678,XXXX Internal Customer Service - CA,6,xyz#discard.mail.us2.oracle.cloud.com,zzr,500,10002,00000,00000,00000,130000,00000,00,6,500000039139653,100
SCO,XXXX Internal Customer Service - CA,300000039139652,"Chemicals, Lubricants and Non-Gen Fuels.Additives.Additives",CAD,Nisku Distribution Centre,NDC,INVENTORY,400000039139654,"TRANSFORMER, 25 KVA OH, 12470GRDY/7200/347/600Y 1PH C/W TAPS SPEC. #YECL-T-15",16340094,Goods,TEST12345678,XXXX Internal Customer Service - CA,6,xyz#discard.mail.us2.oracle.cloud.com,zzr,500,10002,00000,00000,00000,130000,00000,00,6,500000039139654,100
SCO,XXXX Internal Customer Service - CA,300000039139652,"Chemicals, Lubricants and Non-Gen Fuels.Additives.Additives",CAD,Nisku Distribution Centre,NDC,INVENTORY,400000039139655,"TRANSFORMER, 25 KVA OH, 12470GRDY/7200/347/600Y 1PH C/W TAPS SPEC. #YECL-T-15",16340094,Goods,TEST12345678,XXXX Internal Customer Service - CA,6,xyz#discard.mail.us2.oracle.cloud.com,zzr,500,10002,00000,00000,00000,130000,00000,00,6,500000039139655,100
I want to write XSLT transformation to group it based on interface source code, requisitionbuname, followed by looping through InterfaceHeaderKey. Pls. suggest

consider using for-each-group xslt 2.0 construct.....
<xsl:for-each-group select="//put your parent tag here let say interfaceSourceCode" group-by="//put your element">
<xsl:for-each-group select="current-group().. if next grouping element is at same level or change accordingly" group-by="..put second grouping element let say requisitioningBUName and so on">
<xsl:for-each select="//element let say InterfaceHeaderKey">
.....values go here
</xsl:for-each>
</xsl:for-each-group>
</xsl:for-each-group>

Related

How to exclude multiple values in OData call?

I am creating a SAPUI5 application. This application is connected to a backend SAP system via OData. In the SAPUI5 application I use a smart chart control. Out of the box the smart chart lets the user create filters for the underlying data. This works fine - except if you try to use multiple 'not equals' for one property. Is there a way to accomplish this?
I found out that all properties within an 'and_expression' (including nested or_expressions) must have unique name.
The reason why two parameters with the same property don't get parsed into the select options:
/IWCOR/CL_ODATA_EXPR_UTILS=>GET_FILTER_SELECT_OPTIONS takes the expression you pass and parses it into a table of select options.
The select option table returned is of type /IWCOR/IF_ODATA_TYPES=>EDM_SELECT_OPTION_T which is a HASHED TABLE .. WITH UNIQUE KEY property.
From: https://archive.sap.com/discussions/thread/3170195
The problem is that you cannot combine NE terms with OR. Because both parameters after the NE should not be shown in the result set.
So at the end the it_filter_select_options is empty and only the iv_filter_string is filled.
Is there a manual way of facing this problem (evaluation of the iv_filter_string) to handle multiple NE terms?
This would be an example request:
XYZ/SmartChartSet?$filter=(Category%20ne%20%27Smartphone%27%20and%20Category%20ne%20%27Notebook%27)%20and%20Purchaser%20eq%20%27CompanyABC%27%20and%20BuyDate%20eq%20datetime%272018-10-12T02%3a00%3a00%27&$inlinecount=allpages
Normally I want this to exclude items with the category 'Notebook' and 'Smartphone' from my result set that I retrieve from the backend.
If there is a bug inside /iwcor/cl_odata_expr_utils=>get_filter_select_options which makes it unable to treat multiple NE filters of the same component, and you cannot wait for an OSS. I would suggest to wrap it inside a new static method that will make the following logic (if you will be stuck with the ABAP implementation i would try to at least partially implement it when i get time):
Get all instances of <COMPONENT> ne '<VALUE>' inside a () (using REGEX).
Replace each <COMPONENT> with <COMPONENT>_<i> so there will be ( <COMPONENT>_1 ne '<VALUE_1>' and <COMPONENT>_2 ne '<VALUE_2>' and... <COMPONENT>_<n> ne '<VALUE_n>' ).
Call /iwcor/cl_odata_expr_utils=>get_filter_select_options with the modified query.
Modify the rt_select_options result by changing COMPONENT_<i> to <COMPONENT> again.
I can't find the source but I recall that multiple "ne" isn't supported. Isn't that the same thing that happens when you do multiple negatives in SE16, some warning is displayed?
I found this extract for Business ByDesign:
Excluding two values using the OR operator (for example: $filter=CACCDOCTYPE ne ‘1000’ or CACCDOCTYPE ne ‘4000’) is not possible.
The workaround I see is to select the Categories you actively want, not the ones you don't in the UI5 app.
I can also confirm that my code snippet I've used a long time for filtering also has the same problem...
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_MGW_ABS_DATA->FILTERING
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_TECH_REQUEST_CONTEXT TYPE REF TO /IWBEP/IF_MGW_REQ_ENTITYSET
* | [<-->] CR_ENTITYSET TYPE REF TO DATA
* | [!CX!] /IWBEP/CX_MGW_BUSI_EXCEPTION
* | [!CX!] /IWBEP/CX_MGW_TECH_EXCEPTION
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD FILTERING.
FIELD-SYMBOLS <lt_entityset> TYPE STANDARD TABLE.
ASSIGN cr_entityset->* TO <lt_entityset>.
CHECK: cr_entityset IS BOUND,
<lt_entityset> IS ASSIGNED.
DATA(lo_filter) = io_tech_request_context->get_filter( ).
/iwbep/cl_mgw_data_util=>filtering(
exporting it_select_options = lo_filter->get_filter_select_options( )
changing ct_data = <lt_entityset> ).
ENDMETHOD.

Gumbo Apache Storm Monitoring Metrics

I am trying to configure Gumbo for storm topology monitoring from here
There is not clear example or usage given on the site, need some clarification on what are the parameter and where to add this code given on the site above
MonitorClient mclient = MonitorClient.forConfig(conf);
// There are multiple metric groups, each with multiple metrics.
// Components have names and multiple instances, each of which has an integer ID
mclient.declare(metricGroup,metric,task_id,component_id);
mclient.increment(metricGroup,metric, 1L , task_id);
TaskHook.registerTo(config);
Now what values we need to provide for MetricGroup, metric, task_id and component_id? If need to find it from each Spout and Bolt how can we do it? Where should this code be placed, is it in topology builder before submitting the topology or in individual Spout/Bolt class under open/prepare methods or somewhere else. Appreciate any help on this question.
I tried few option and below is the config that worked for me, the Group Name can be anything, Metric name is the name of the stream going out from one component to other, taskid can be any unique task number,
conf.put("gumbo.server.kind", "local");
conf.put("gumbo.local.port", 8086); //Any port it must be same in the html file
conf.put("gumbo.start", System.currentTimeMillis()); // should be the same for all calls
conf.put("gumbo.bucketSize", 1000L);
conf.put("gumbo.enabled", true);
conf.put("gumbo.http.host", "hostname");
conf.put("gumbo.http.port", 8086);//Any port it must be same in the html file
conf.put("gumbo.http.app", "gumbo");
conf.put("gumbo.enabled", true);
conf.put("gumbo.server.key", topology_id);
MonitorClient mclient = MonitorClient.connect(conf);
GumboTaskHook.registerTo(conf);
mclient.declare("Backlog",RTConstants.MATCH_LEFT_STREAM,3,RTConstants.TRANSFORM_LEFT_BOLT);
mclient.increment("Backlog",RTConstants.MATCH_LEFT_STREAM, 1L , 3);
mclient.declare("Backlog",RTConstants.MATCH_RIGHT_STREAM,4,RTConstants.TRANSFORM_RIGHT_BOLT);
mclient.increment("Backlog",RTConstants.MATCH_RIGHT_STREAM, 1L , 4);

XSLT 2.0. Loop inside a Function

Hitting my wall here...
I've got the following data where a Primary Employee may have multiple dependents. I need to create a function that will match the Employee's SSN (ab:SSN) against the Dependent_SSN and determine if one of them is a 'Spouse'. If so, then we'll return the Dependent_SSN of the 'Spouse'.
If not, we'll move on and return the next non-'Spouse' Dependent_SSN.
I'm trying to create a function as I think I'll need this more than once. The code snippet resides inside of an existing template that is doing other looping functionality.
I've tried this but Oxygen returns an error:
<xsl:function name="ab:PQB">
<xsl:param name="EE_SSN">
</xsl:param>
<xsl:for-each select="/ab:Report_Data/ab:Report_Entry[ab:Employee_ID=$EE_SSN]/ab:Report_Data/ab:Report_Entry[ab:Employee_ID=$EE_SSN]ab:dependents/ab:Dependent_SSN">
</xsl:for-each>
The Error returned is :
"Engine name: Saxon-PE 9.3.0.5
Severity: fatal
Description: Unexpected token name "wd:dependents" beyond end of expression"
I know I need to test the higher level SSN against looping through the dependents, but like I said "I'm against my wall" :)
Data is here:
<ab:Report_Entry>
<ab:SSN>888881006</ab:SSN>
<ab:Last_Name>Smith</ab:Last_Name>
<ab:First_Name>Kimberly</ab:First_Name>
<ab:dependents>
<ab:Dependent_SSN>888881009</ab:Dependent_SSN>
<ab:Relation ab:Descriptor="Spouse">
</ab:Relation>
</ab:dependents>
<ab:dependents>
<ab:Dependent_SSN>888881004</ab:Dependent_SSN>
<ab:Relation ab:Descriptor="Child">
</ab:Relation>
</ab:dependents>
<ab:dependents>
<ab:Dependent_SSN>888881003</ab:Dependent_SSN>
<ab:Relation ab:Descriptor="Child">
<ab:ID ab:type="Related_Person_Relationship_ID">Child</ab:ID>
</ab:Relation>
</ab:dependents>
<ab:dependents>
<ab:Dependent_SSN>888881001</ab:Dependent_SSN>
<ab:Dependent_ID>1032D-4</ab:Dependent_ID>
<ab:Relation ab:Descriptor="Child">
<ab:ID ab:type="Related_Person_Relationship_ID">Child</ab:ID>
</ab:Relation>
</ab:dependents>
</ab:Report_Entry>
Thank you to any advice!
You might want to define the type of the input parameter and the type of the function result and then you should write a function body returning a value of that type. Currently your description sounds rather procedural, that is not going to work with XSLT/XPath.
As for the error, I think in the path /ab:Report_Data/ab:Report_Entry[ab:Employee_ID=$EE_SSN]/ab:Report_Data/ab:Report_Entry[ab:Employee_ID=$EE_SSN]ab:dependents/ab:Dependent_SSN you need one more slash /ab:Report_Data/ab:Report_Entry[ab:Employee_ID=$EE_SSN]/ab:Report_Data/ab:Report_Entry[ab:Employee_ID=$EE_SSN]/ab:dependents/ab:Dependent_SSN to have a syntactically correct path. That should avoid the syntax error you get but is not likely to return the result you want.

Find child of child which attribute code is equal to the parameter passed on the url - XSL

On this dynamic website,
The url looks something like this : departments/CHEM.html
CHEM is a parameter.
<xsl:param name="dep" select="'CHEM'" />
a piece of the xml is below
<course acad_year="2012" cat_num="5085" offered="Y">
<term term_pattern_code="1" fall_term="Y" spring_term="N">fall term</term>
<department code="CHEM">
<dept_long_name>Department of Chemistry and Chemical Biology</dept_long_name>
<dept_short_name>Chemistry and Chemical Biology</dept_short_name>
</department>
</course> ....
I am trying to get the dept_short_name to use on my H1 tag, but I have not been successful.So far I tried
<h2><xsl:value-of select="course/department/[code={#$dep}]"/></h2>
Any suggestions??? Thanks!
Just use:
<xsl:value-of select="course/department[#code eq $dep]/dept_short_name"/>
Remember:
In XPath 2.0 (XSLT 2.0) use the eq operator for value comparissons -- it is more efficient than the general comparisson operator = which really, only, needs to be used when at least one of its operands is a sequence.
I would try this:
<xsl:value-of select="course/department[#code=$dep]/dept_short_name/text()"/>
That says: find the department element (inside a course element) whose code attribute is the value of parameter "dep", then find the dept_short_name child element, then get the text inside that element.
You have to use the # to say that "code" is an attribute, but "dep" should not have it. I think the {} notation is for use inside attributes of the non-XSLT elements of your stylesheet, so I wouldn't use it inside a value-of expression.

Problem with BizTalk multi-input map

I have a map that takes 2 input messages, like this:
<ns0:Root>
<InputMessagePart_0>
<root>
<Indicator>1</Indicator>
<NewValue>AAA</NewValue>
</root>
<InputMessagePart_0>
<InputMessagePart_1>
<root>
<Value>BBB</Value>
</root>
<InputMessagePart_1>
</ns0:Root>
(Lots of the nodes are not shown for clarity)
The ouput message looks like this:
<Root>
<Value>AAA</Value>
</Root>
(It's identical to InputMessagePart_1)
If the Indicator is 1, I want Value to be replaced with NewValue. If it's 0, I want Value to stay the same. I used a scripting functoid with code like this:
public string Get_Value(string indicator, string value, string newValue)
{
if(indicator == "1")
{
return newValue;
}
else
{
return value;
}
}
I'm running into problems due to the fact that Value might not actually occur in the original InputMessagePart_1 - if it doesn't, I want to create it. With the script above, even though Indicator is 1, I'm not getting a return string when Value doesn't exist.
Any suggestions?
Updated: I did some further testing by removing the if/then logic and just returned a hard-coded string from the functoid, and I get the same results... it seems that just having the empty input kills the entire functionality of the functoid...
You should want to use the Equal functoid and test whether the value is 1. You'll then feed the result to the input of two functoids:
First, to a Value Mapping functoid, which is connected to the <New Value> tag in the first part of the source schema.
Second, to a Logical Not functoid, which is then connected to another Value Mapping functoid connected to the <Value> tag in the second part of the source schema.
If the <Indicator>; tag does not contain the expected value 1 or is not present in the source message, the Logical Equal functoid will return False, and the second branch of the map will execute.
It doesn't matter whether the Value tag is present in the second part of the source schema. If it is not, either one of the Value Mapping functoids will create it in the destination.
If you definitely need to depend upon the <Indicator> tag, you might want to use the Logical Existence functoid, that returns whether any specified input node appears in the source message.
If all else fails using the mapper, you might try switching to XSLT - see here how to scrape the XSLT out of your existing BTM.
The map that you are after looks straightforward:
<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > .. etc ... whatever you've scraped out
<xsl:output ...
<xsl:template match=...>
<ns1:Root>
<ns1:Value>
<xsl:choose>
<xsl:when test="/ns0:Root/ns0:InputMessagePart_0/ns0:root/ns0:Indicator/text()='1'">
<xsl:value-of select="/ns0:Root/ns0:InputMessagePart_0/ns0:root/ns0:NewValue/text()" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="/ns0:Root/ns0:InputMessagePart_1/ns0:root/ns0:Value/text()" />
</xsl:otherwise>
</xsl:choose>
<ns1:Value>
</ns1:Root>

Resources