We have a requirement where we need to feed data into an empty json array element from another array object using element comparison.
The sample payloads and required results are mentioned below for better understanding.
Payload1: (Input Payload)
{
"data": [
{
"name":"ram",
"eno":"100",
"dept":"Sales",
"sal":null
},
{
"name":"gopal",
"eno":"101",
"dept":"Sales",
"sal":null
},
{
"name":"hari",
"eno":"102",
"dept":"Sales",
"sal":null
},
{
"name":"pankaj",
"eno":"103",
"dept":"Sales",
"sal":null
},
{
"name":"raju",
"eno":"104",
"dept":"Sales",
"sal":null
}
]
}
Payload2: (Response From a third party webservice)
{
"data": [
{
"eno": "100",
"sal": 2000
},
{
"eno": "101",
"sal": 2300
},
{
"eno": "102",
"sal": 1800
},
{
"eno": "104",
"sal": 2500
}
]
}
Required Result:
{
"data": [
{
"name":"ram",
"eno":"100",
"dept":"Sales",
"sal":2000
},
{
"name":"gopal",
"eno":"101",
"dept":"Sales",
"sal":2300
},
{
"name":"hari",
"eno":"102",
"dept":"Sales",
"sal":1800
},
{
"name":"raju",
"eno":"104",
"dept":"Sales",
"sal":2500
}
]
}
.................................................................
Here is how you can do this by only using synapse. I hardcoded the second response.
<?xml version="1.0" encoding="UTF-8"?>
<api context="/HelloWorld" name="HelloWorld" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<enrich>
<source clone="true" type="body"/>
<target property="inputBody" type="property"/>
</enrich>
<payloadFactory media-type="json">
<format>
{
"data": [
{
"eno": "100",
"sal": 2000
},
{
"eno": "101",
"sal": 2300
},
{
"eno": "102",
"sal": 1800
},
{
"eno": "104",
"sal": 2500
}
]
}
</format>
<args/>
</payloadFactory>
<foreach expression="json-eval($.data)" id="foreach_1">
<sequence>
<property expression="json-eval($.eno)" name="eno" scope="default" type="STRING"/>
<property expression="json-eval($.sal)" name="sal" scope="default" type="STRING"/>
<enrich>
<source clone="true" property="inputBody" type="property"/>
<target type="body"/>
</enrich>
<enrich>
<source clone="true" property="sal" type="property"/>
<target xpath="//data[eno=$ctx:eno]/sal"/>
</enrich>
<enrich>
<source clone="true" type="body"/>
<target property="inputBody" type="property"/>
</enrich>
</sequence>
</foreach>
<enrich>
<source clone="true" property="inputBody" type="property"/>
<target type="body"/>
</enrich>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
I embed an XML into a JSON for the field details and wso2 converts it to JSON. How can I resolve this?
<payloadFactory media-type="json">
<format>{
"Customer": {
"name": "$1",
"details": "$2"
}
}</format>
<args>
<arg evaluator="xml" expression="get-property('name')"/>
<arg evaluator="xml" expression="get-property('detail')"/>
</args>
</payloadFactory>
Output
{
"Customer": {
"name": "Adam",
"details": "{"id": "123"}"
}
}
expected
{
"Customer": {
"name": "Adam",
"details": "<id>123</id>"
}
}
You can simply add the flag literal="true" in the PLFactory args.
<payloadFactory media-type="json">
<format>{
"Customer": {
"name": "$1",
"details": "$2"
}
}</format>
<args>
<arg evaluator="xml" expression="get-property('name')"/>
<arg evaluator="xml" expression="get-property('detail') literal="true" />
</args>
</payloadFactory>
I was using steeltoe 2.4.3 in my .net core 3.1 application. Recently I updated steeltoe packages to v3.0.1 and it looks like logs are not coming in serilog format. I am not able to figure out what is wrong. I do have the serilog configuration in my appsettings like below.
{
"management": {
"endpoints": {
"path": "/myexample/cloudfoundryapplication",
"cloudfoundry": {
"validateCertificates": false
},
"actuator": {
"exposure": {
"include": [ "*" ],
"exclude": [ "env", "refresh" ]
}
}
}
},
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Information",
"Steeltoe": "Information"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
}
},
{
"Name": "Trace",
"Args": {
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
}
}
],
"Enrich": [ "FromLogContext" ]
},
"AllowedHosts": "*"
}
Program.cs is like below
public static class Program
{
public static void Main(string[] args)
{
Activity.DefaultIdFormat = ActivityIdFormat.W3C;
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.AddCloudFoundryConfiguration()
.ConfigureLogging((builderContext, loggingBuilder) =>
{
// Add Serilog Dynamic Logger
loggingBuilder.AddDynamicSerilog();
})
.AddCloudFoundryActuators()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
My .csproj looks iike below.
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<None Update="wwwroot\**\*;*.yml">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Serilog.Sinks.Trace" Version="2.1.0" />
<PackageReference Include="Serilog.Formatting.Compact" Version="1.1.0" />
<PackageReference Include="Steeltoe.Extensions.Logging.DynamicSerilogCore" Version="3.0.1" />
<PackageReference Include="Steeltoe.Management.CloudFoundryCore" Version="3.0.1" />
<PackageReference Include="Steeltoe.Extensions.Configuration.CloudFoundryCore" Version="3.0.1" />
</ItemGroup>
</Project>
AddDynamicSerilog doesn't (currently) add a console sink, try updating your code to look like this:
AddDynamicSerilog(new LoggerConfiguration().WriteTo.Console())
This PR will result in the Console sink being added automatically if no configuration is provided, and it will probably ship in Steeltoe 3.0.2 (no ETA yet)
I have a Input json below
[
{
"fileName": "abc",
"value": [
{
"SSC": {
"Payload": [
{
"Ledger": [
{
"Line": [
{
"AccountingCode": [
"402050046767"
],
"AccountingPeriod": [
"00720201243"
]
},
{
"AccountingCode": [
"203010334567"
],
"AccountingPeriod": [
"00720201234"
]
}
]
}
]
}
]
}
}
]
},
{
"fileName": "abc",
"value": [
{
"SSC": {
"Payload": [
{
"Ledger": [
{
"Line": [
{
"AccountingCode": [
"40205004"
],
"AccountingPeriod": [
"0072020"
]
},
{
"AccountingCode": [
"20301033"
],
"AccountingPeriod": [
"0072020"
]
}
]
}
]
}
]
}
}
]
}
]
my expected output is
[
{
"fileName": "abc",
"value": [
{
"SSC": {
"Payload": [
{
"Ledger": [
{
"Line": [
{
"AccountingCode": [
"402050046767"
],
"AccountingPeriod": [
"00720201243"
]
},
{
"AccountingCode": [
"203010334567"
],
"AccountingPeriod": [
"00720201234"
]
},
{
"AccountingCode": [
"40205004"
],
"AccountingPeriod": [
"0072020"
]
},
{
"AccountingCode": [
"20301033"
],
"AccountingPeriod": [
"0072020"
]
}
]
}
]
}
]
}
}
]
}
]
Below is the xslt i have tried but not getting the proper output
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="3.0"
xmlns="http://www.w3.org/2005/xpath-functions"
xpath-default-namespace="http://www.w3.org/2005/xpath-functions"
expand-text="yes">
<xsl:param name="input"/>
<xsl:output method="text"/>
<xsl:template name="xsl:initial-template">
<xsl:variable name="input-as-xml" select="json-to-xml($input)"/>
<xsl:variable name="transformed-xml" as="element(array)">
<array>
<map>
<string key="fileNames">
<xsl:for-each select="$input-as-xml//string[#key='fileName']">
<xsl:variable name="file" select="../string[#key='fileName']"/>
<xsl:value-of select="$file"/>
</xsl:for-each>
</string>
<array key="value">
<map>
<array key="SSC">
<map>
<array key="Payload">
<map>
<array key="Ledger">
<xsl:for-each select="$input-as-xml//array[#key='Ledger']">
<map>
<xsl:choose>
<xsl:when test="$input-as-xml//string[#key='fileName'] = 'abc'">
<xsl:value-of select="$input-as-xml//array[#key='Lines']"/>
</xsl:when>
</xsl:choose>
</map>
</xsl:for-each>
</array>
</map>
</array>
</map>
</array>
</map>
</array>
</map>
</array>
</xsl:variable>
<xsl:value-of select="xml-to-json($transformed-xml)"/>
</xsl:template>
</xsl:stylesheet>
I am tring to select Array "Lines" from the json if the file name is abc then combine the value of the selected in Array "Ledger"
Please can anyone help me understand how to achieve this in xslt.
You could do this without converting to XML and back again: just manipulate the JSON as a structure of maps and arrays. Something along the lines of
<xsl:template name="xsl:initial-template">
<xsl:variable name="in" select="json-doc('input.json')"/>
<xsl:variable name="out" as="map(*)*">
<xsl:for-each-group select="$in?*" group-by="?fileName">
<xsl:map>
<xsl:map-entry key="'fileName'" select="current-grouping-key()"/>
<xsl:map-entry key="'value'" select="
array {
map {'SSC':
map {'Payload':
array {
map {'Ledger':
array {
map{'Line': array:join(current-group()?
value?*?SSC?Payload?*?Ledger?*?Line)}
}
}
}
}"/>
</xsl:map>
</xsl:for-each-group>
</xsl:variable>
<xsl:sequence select="array{$out}"/>
</xsl:template>
I haven't tested this and there are probably a few bugs in the complex path to iron out, but I hope it conveys the idea.
(Note, this would be easier if XSLT 3.0 had an xsl:array instruction. If you're prepared to use Saxon extensions, there's a saxon:array that plugs this gap.)
I am trying to create a CFChart with Stacked Bars and unstacked Lines. Have been trying to work around in the Webcharts Tool but no luck so far.
In the example image all the series are seriesplacement=stacked, but I want to have the bars(Avg and TDD) as stacked and the lines (Max and Min) as seriesplacement=default. Is there a way to achieve the same in Cfchart?
If I am understanding correctly, just set the placement of the line series in your xml style:
<?xml version="1.0" encoding="UTF-8"?>
<frameChart>
<elements place="Stacked" drawOutline="false">
<series index="0" place="Default" shape="Line" />
<series index="1" place="Default" shape="Line" />
</elements>
</frameChart>
Then generate a "stacked" chart as usual:
<cfchart format="png" style="#yourCustomStyle#">
<cfchartseries type="line" serieslabel="Min">
...
</cfchartseries>
<cfchartseries type="line" serieslabel="Max">
...
</cfchartseries>
<cfchartseries type="bar" serieslabel="Avg" >
...
</cfchartseries>
<cfchartseries type="bar" serieslabel="TDD">
...
</cfchartseries>
</cfchart>
CFChart is based on ZingCharts which is formatted using JSON. They have some good docs and a builder to develop with. I haven't figured out how to get the left y-scale to adjust to MIN value, MAX seems to be automatic. Below I put together some sample data and code (.cfm & .json) for you to get started with.
Some starter data and the CFChart info (Lines-StackedBars.cfm)
<cfscript>
GraphData = queryNew("");
queryAddColumn(GraphData, "dates", "Integer", ['1/1/11','1/2/11','1/3/11','1/4/11','1/5/11']);
queryAddColumn(GraphData, "MIN", "Integer", [42,37,45,29,61]);
queryAddColumn(GraphData, "MAX", "Integer", [110,98,82,103,94]);
queryAddColumn(GraphData, "AVG", "Integer", [80,75,80,65,85]);
queryAddColumn(GraphData, "TDD", "Integer", [23,33,32,28,26]);
</cfscript>
<cfchart chartwidth="800"
chartheight="500"
format="html"
style="LineStackedBar.json"
title="Unstacked Lines w/ Stacked Bars">
<cfchartseries query="GraphData"
type="Bar"
itemcolumn="dates"
valuecolumn="AVG"
color="blue"
serieslabel="AVG">
<cfchartseries query="GraphData"
type="Bar"
itemcolumn="dates"
valuecolumn="TDD"
color="green"
serieslabel="TDD">
<cfchartseries query="GraphData"
type="Line"
itemcolumn="dates"
valuecolumn="MIN"
color="red"
serieslabel="MIN">
<cfchartseries query="GraphData"
type="Line"
itemcolumn="dates"
valuecolumn="MAX"
color="orange"
serieslabel="MAX">
</cfchart>
The code above uses LineStackedBar.json to handle the formatting
{
"graphset":[
{
"legend":{
"position":"30%, 0%",
"border-color":"#CCCCCC",
"background-color":"#FFFFFF",
"margin-top":40,
"layout":"x4",
"shadow":false,
"alpha":1
},
"border-color":"#cccccc",
"tooltip":{
"font-size":11,
"font-color":"#FFFFFF",
"bold":true,
"font-family":"Helvetica",
"padding":5
},
"series":[
{
"hover-state":{
"visible":false
},
"shadow-blur-y":1,
"shadow-color":"#cccccc",
"shadow-alpha":1,
"shadow":true,
"background-color-2":"#FFCF8C",
"background-color":"#735328",
"type":"bar",
"stacked":"true",
"shadow-distance":2,
"shadow-blur-x":2
},
{
"hover-state":{
"visible":false
},
"shadow-blur-y":1,
"shadow-color":"#cccccc",
"shadow-alpha":1,
"shadow":true,
"background-color-2":"#FEFFD1",
"background-color":"#9D9C5D",
"type":"bar",
"stacked":"true",
"shadow-distance":2,
"shadow-blur-x":2
},
{
"hover-state":{
"visible":false
},
"line-color":"#699EBF",
"border-color":"#699EBF",
"line-width":3,
"type":"line",
"scales":"scale-x,scale-y-2",
"stacked":"false"
},
{
"hover-state":{
"visible":false
},
"line-color":"#143F59",
"border-color":"#143F59",
"line-width":3,
"type":"line",
"scales":"scale-x,scale-y-2",
"stacked":"false"
}
],
"scale-y":{
"tick":{
"line-gap-size":0,
"line-color":"#cccccc",
"line-width":1,
"size":10
},
"font-size":16,
"line-color":"#cccccc",
"bold":true,
"format":"%v",
"item":{
"font-size":11,
"font-family":"Helvetica",
"color":"#333333"
},
"label":{
"color":"#333333"
},
"line-width":2,
"font-family":"Helvetica",
"color":"#333333"
},
"scale-y-2":{
"tick":{
"line-gap-size":0,
"line-color":"#cccccc",
"line-width":1,
"size":10
},
"font-size":16,
"line-color":"#cccccc",
"bold":true,
"format":"%v",
"item":{
"font-size":11,
"font-family":"Helvetica",
"color":"#333333"
},
"label":{
"color":"#333333"
},
"line-width":2,
"font-family":"Helvetica",
"color":"#333333"
},
"plotarea":{
"margin-top":80,
"margin-left":70,
"margin-right":30
},
"scale-x":{
"tick":{
"line-gap-size":0,
"line-color":"#cccccc",
"line-width":1,
"size":10
},
"font-size":16,
"line-color":"#cccccc",
"bold":true,
"item":{
"font-size":11,
"font-family":"Helvetica",
"color":"#333333"
},
"guide":{
"line-width":0
},
"label":{
"color":"#333333"
},
"line-width":2,
"font-family":"Helvetica",
"color":"#333333"
},
"3d-aspect":{
"true3d":false
},
"background-color":"white",
"border-width":1,
"plot":{
"hover-marker":{
"background-color":"#888888",
"size":3
},
"marker":{
"background-color":"#cccccc",
"size":3
},
"preview":true,
"tooltip-text":"%v"
},
"type":"mixed",
"title":{
"border-width":1,
"border-color":"#cccccc",
"background-color":"white",
"font-size":18,
"bold":true,
"font-family":"Helvetica",
"color":"#333333"
}
}
]
}