select and combine 2 arrays in xslt - xslt

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.)

Related

AWS SCP to enforce Tag Policy fails

So I am following this AWS blog to enforce tagging policy across AWS Organization.
I did create the tag policy and the SCP and attached both to the OUs.
Tag policy
{
"tags": {
"costcenter": {
"tag_key": {
"##assign": "costcenter"
},
"tag_value": {
"##assign": [
"CC102",
"CC103",
"CC104"
]
},
"enforced_for": {
"##assign": [
"ec2:instance"
]
}
},
"team": {
"tag_key": {
"##assign": "team"
},
"tag_value": {
"##assign": [
"Team1",
"Team2",
"Team3"
]
},
"enforced_for": {
"##assign": [
"ec2:instance"
]
}
}
}
}
SCP
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyEC2CreationSCP1",
"Effect": "Deny",
"Action": [
"ec2:RunInstances"
],
"Resource": [
"arn:aws:ec2:*:*:instance/*",
"arn:aws:ec2:*:*:volume/*"
],
"Condition": {
"Null": {
"aws:RequestTag/costcenter": "true"
}
}
},
{
"Sid": "Statement1",
"Effect": "Deny",
"Action": [
"ec2:RunInstances"
],
"Resource": [
"arn:aws:ec2:*:*:instance/*",
"arn:aws:ec2:*:*:volume/*"
],
"Condition": {
"Null": {
"aws:RequestTag/team": "true"
}
}
}
]
}
When I try to launch an EC2 with non compliant tags, I get the error not authorized with clear message about violating the tag policy
using non compliant tags error
but even when I comply to the policy I get the non authorized message
using compliant tags error
Here is the decoded message
{
"DecodedMessage": "{\"allowed\":false,\"explicitDeny\":true,\"matchedStatements\":{\"items\":[{\"statementId\":\"DenyEC2CreationSCP1\",\"effect\":\"DENY\",\"principals\":{\"items\":[{\"value\":\"AROAY4Z6JOQ4EEGF437YJ\"}]},\"principalGroups\":{\"items\":[]},\"actions\":{\"items\":[{\"value\":\"ec2:RunInstances\"}]},\"resources\":{\"items\":[{\"value\":\"arn:aws:ec2:*:*:instance/*\"},{\"value\":\"arn:aws:ec2:*:*:volume/*\"}]},\"conditions\":{\"items\":[{\"key\":\"aws:RequestTag/costcenter\",\"values\":{\"items\":[{\"value\":\"true\"}]}}]}},{\"statementId\":\"Statement1\",\"effect\":\"DENY\",\"principals\":{\"items\":[{\"value\":\"AROAY4Z6JOQ4EEGF437YJ\"}]},\"principalGroups\":{\"items\":[]},\"actions\":{\"items\":[{\"value\":\"ec2:RunInstances\"}]},\"resources\":{\"items\":[{\"value\":\"arn:aws:ec2:*:*:instance/*\"},{\"value\":\"arn:aws:ec2:*:*:volume/*\"}]},\"conditions\":{\"items\":[{\"key\":\"aws:RequestTag/team\",\"values\":{\"items\":[{\"value\":\"true\"}]}}]}},{\"statementId\":\"DenyEC2CreationSCP1\",\"effect\":\"DENY\",\"principals\":{\"items\":[{\"value\":\"AROAY4Z6JOQ4EEGF437YJ\"}]},\"principalGroups\":{\"items\":[]},\"actions\":{\"items\":[{\"value\":\"ec2:RunInstances\"}]},\"resources\":{\"items\":[{\"value\":\"arn:aws:ec2:*:*:instance/*\"},{\"value\":\"arn:aws:ec2:*:*:volume/*\"}]},\"conditions\":{\"items\":[{\"key\":\"aws:RequestTag/costcenter\",\"values\":{\"items\":[{\"value\":\"true\"}]}}]}},{\"statementId\":\"Statement1\",\"effect\":\"DENY\",\"principals\":{\"items\":[{\"value\":\"AROAY4Z6JOQ4EEGF437YJ\"}]},\"principalGroups\":{\"items\":[]},\"actions\":{\"items\":[{\"value\":\"ec2:RunInstances\"}]},\"resources\":{\"items\":[{\"value\":\"arn:aws:ec2:*:*:instance/*\"},{\"value\":\"arn:aws:ec2:*:*:volume/*\"}]},\"conditions\":{\"items\":[{\"key\":\"aws:RequestTag/team\",\"values\":{\"items\":[{\"value\":\"true\"}]}}]}}]},\"failures\":{\"items\":[]},\"context\":{\"principal\":{\"id\":\"AROAY4Z6JOQ4EEGF437YJ:nejla\",\"arn\":\"arn:aws:sts::random-account-number:assumed-role/OrganizationAccountAccessRole/nejla\"},\"action\":\"ec2:RunInstances\",\"resource\":\"arn:aws:ec2:us-east-1:random-account-number:volume/*\",\"conditions\":{\"items\":[{\"key\":\"aws:Resource\",\"values\":{\"items\":[{\"value\":\"volume/*\"}]}},{\"key\":\"aws:Account\",\"values\":{\"items\":[{\"value\":\"random-account-number\"}]}},{\"key\":\"ec2:AvailabilityZone\",\"values\":{\"items\":[{\"value\":\"us-east-1e\"}]}},{\"key\":\"ec2:Encrypted\",\"values\":{\"items\":[{\"value\":\"false\"}]}},{\"key\":\"ec2:VolumeType\",\"values\":{\"items\":[{\"value\":\"gp2\"}]}},{\"key\":\"ec2:IsLaunchTemplateResource\",\"values\":{\"items\":[{\"value\":\"false\"}]}},{\"key\":\"aws:Region\",\"values\":{\"items\":[{\"value\":\"us-east-1\"}]}},{\"key\":\"aws:Service\",\"values\":{\"items\":[{\"value\":\"ec2\"}]}},{\"key\":\"ec2:VolumeID\",\"values\":{\"items\":[{\"value\":\"*\"}]}},{\"key\":\"ec2:VolumeSize\",\"values\":{\"items\":[{\"value\":\"8\"}]}},{\"key\":\"ec2:ParentSnapshot\",\"values\":{\"items\":[{\"value\":\"arn:aws:ec2:us-east-1::snapshot/snap-0c371a5504a01769d\"}]}},{\"key\":\"aws:Type\",\"values\":{\"items\":[{\"value\":\"volume\"}]}},{\"key\":\"ec2:Region\",\"values\":{\"items\":[{\"value\":\"us-east-1\"}]}},{\"key\":\"aws:ARN\",\"values\":{\"items\":[{\"value\":\"arn:aws:ec2:us-east-1:random-account-number:volume/*\"}]}}]}}}"
}
Desired outcomes
The decoded message clearly says there is an explicit denial from your SCP policies. (You should mask your AWS account id)
{
"allowed": false,
"explicitDeny": true,
"matchedStatements": {
"items": [
{
"statementId": "DenyEC2CreationSCP1",
"effect": "DENY",
"principals": {
"items": [
{
"value": "AROAY4Z6JOQ4EEGF437YJ"
}
]
},
"principalGroups": {
"items": []
},
"actions": {
"items": [
{
"value": "ec2:RunInstances"
}
]
},
"resources": {
"items": [
{
"value": "arn:aws:ec2:*:*:instance/*"
},
{
"value": "arn:aws:ec2:*:*:volume/*"
}
]
},
"conditions": {
"items": [
{
"key": "aws:RequestTag/costcenter",
"values": {
"items": [
{
"value": "true"
}
]
}
}
]
}
},
{
"statementId": "Statement1",
"effect": "DENY",
"principals": {
"items": [
{
"value": "AROAY4Z6JOQ4EEGF437YJ"
}
]
},
"principalGroups": {
"items": []
},
"actions": {
"items": [
{
"value": "ec2:RunInstances"
}
]
},
"resources": {
"items": [
{
"value": "arn:aws:ec2:*:*:instance/*"
},
{
"value": "arn:aws:ec2:*:*:volume/*"
}
]
},
"conditions": {
"items": [
{
"key": "aws:RequestTag/team",
"values": {
"items": [
{
"value": "true"
}
]
}
}
]
}
},
{
"statementId": "DenyEC2CreationSCP1",
"effect": "DENY",
"principals": {
"items": [
{
"value": "AROAY4Z6JOQ4EEGF437YJ"
}
]
},
"principalGroups": {
"items": []
},
"actions": {
"items": [
{
"value": "ec2:RunInstances"
}
]
},
"resources": {
"items": [
{
"value": "arn:aws:ec2:*:*:instance/*"
},
{
"value": "arn:aws:ec2:*:*:volume/*"
}
]
},
"conditions": {
"items": [
{
"key": "aws:RequestTag/costcenter",
"values": {
"items": [
{
"value": "true"
}
]
}
}
]
}
},
{
"statementId": "Statement1",
"effect": "DENY",
"principals": {
"items": [
{
"value": "AROAY4Z6JOQ4EEGF437YJ"
}
]
},
"principalGroups": {
"items": []
},
"actions": {
"items": [
{
"value": "ec2:RunInstances"
}
]
},
"resources": {
"items": [
{
"value": "arn:aws:ec2:*:*:instance/*"
},
{
"value": "arn:aws:ec2:*:*:volume/*"
}
]
},
"conditions": {
"items": [
{
"key": "aws:RequestTag/team",
"values": {
"items": [
{
"value": "true"
}
]
}
}
]
}
}
]
},
"failures": {
"items": []
},
"context": {
"principal": {
"id": "AROAY4Z6JOQ4EEGF437YJ:nejla",
"arn": "arn:aws:sts::123456789:assumed-role/OrganizationAccountAccessRole/nejla"
},
"action": "ec2:RunInstances",
"resource": "arn:aws:ec2:us-east-1:123456789:volume/*",
"conditions": {
"items": [
{
"key": "aws:Resource",
"values": {
"items": [
{
"value": "volume/*"
}
]
}
},
{
"key": "aws:Account",
"values": {
"items": [
{
"value": "123456789"
}
]
}
},
{
"key": "ec2:AvailabilityZone",
"values": {
"items": [
{
"value": "us-east-1e"
}
]
}
},
{
"key": "ec2:Encrypted",
"values": {
"items": [
{
"value": "false"
}
]
}
},
{
"key": "ec2:VolumeType",
"values": {
"items": [
{
"value": "gp2"
}
]
}
},
{
"key": "ec2:IsLaunchTemplateResource",
"values": {
"items": [
{
"value": "false"
}
]
}
},
{
"key": "aws:Region",
"values": {
"items": [
{
"value": "us-east-1"
}
]
}
},
{
"key": "aws:Service",
"values": {
"items": [
{
"value": "ec2"
}
]
}
},
{
"key": "ec2:VolumeID",
"values": {
"items": [
{
"value": "*"
}
]
}
},
{
"key": "ec2:VolumeSize",
"values": {
"items": [
{
"value": "8"
}
]
}
},
{
"key": "ec2:ParentSnapshot",
"values": {
"items": [
{
"value": "arn:aws:ec2:us-east-1::snapshot/snap-0c371a5504a01769d"
}
]
}
},
{
"key": "aws:Type",
"values": {
"items": [
{
"value": "volume"
}
]
}
},
{
"key": "ec2:Region",
"values": {
"items": [
{
"value": "us-east-1"
}
]
}
},
{
"key": "aws:ARN",
"values": {
"items": [
{
"value": "arn:aws:ec2:us-east-1:123456789:volume/*"
}
]
}
}
]
}
}
}
Please make sure you are using the policies with the correct conditions, if there is any explicit denial in the policies, it always takes a high priority.

how to loop through current-group in xslt3.0 and print each value

I have a input json in the format
[
{
"PERSON_ID": 78,
"EFFECTIVE_START_DATE": "2013-12-02 00:00:00",
"LAST_NAME": "Hulk78"
},
{
"PERSON_ID": 78,
"EFFECTIVE_START_DATE": "2020-06-24 07:29:26",
"LAST_NAME": "Hulks78"
},
{
"PERSON_ID": 79,
"EFFECTIVE_START_DATE": "2015-12-02 00:00:00",
"LAST_NAME": "Hulk79"
},
{
"PERSON_ID": 79,
"EFFECTIVE_START_DATE": "2020-07-24 07:29:26",
"LAST_NAME": "Hulks79"
},
{
"PERSON_ID": 80,
"EFFECTIVE_START_DATE": "2013-12-10 00:00:00",
"LAST_NAME": "Hulk15"
}
]
The expected output
[
{
"PersonId": 78,
"value": [
{
"EffectiveDate": "2013-12-02 00:00:00",
"lastName":"Hulk78"
},
{
"EffectiveDate": "2020-06-24 07:29:26",
"lastName":"Hulks78"
}
]
}
....
]
I want to transform the input json by grouping the person_id value and for each group add its respective effectiveDate and lastname in a array of values corresponding to that person id.
Below is the xslt that i have tried.
<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>
<xsl:for-each-group select="$input-as-xml" group-by="//number[#key='PERSON_ID']">
<map>
<string key="PersonId">
<xsl:value-of select="current-grouping-key()"/>
</string>
<array key="Value">
<xsl:for-each select="current-group()">
<map>
<string key="EffectiveDate">
<xsl:value-of select="../string[#key='EFFECTIVE_START_DATE']"/>
</string>
<string key="LASTNAME">
<xsl:value-of select="#LAST_NAME"/>
</string>
</map>
</xsl:for-each>
</array>
</map>
</xsl:for-each-group>
</array>
</xsl:variable>
<xsl:value-of select="xml-to-json($transformed-xml)"/>
</xsl:template>
</xsl:stylesheet>
Can anyone please help me in understanding how to take out each effective date and last name from the current group.
This is the output i am getting
[
{
"PersonId": "78",
"Value": [
{
"EffectiveDate": "",
"LASTNAME": ""
}
]
},
{
"PersonId": "79",
"Value": [
{
"EffectiveDate": "",
"LASTNAME": ""
}
]
},
{
"PersonId": "80",
"Value": [
{
"EffectiveDate": "",
"LASTNAME": ""
}
]
}
]
You were close. This is how to build the variable:
<xsl:variable name="transformed-xml" as="element()">
<array>
<xsl:for-each-group select="$input-as-xml/array/map" group-by="number[#key='PERSON_ID']">
<map>
<string key="PersonId">
<xsl:value-of select="current-grouping-key()"/>
</string>
<array key="Value">
<xsl:for-each select="current-group()">
<map>
<string key="EffectiveDate">
<xsl:value-of select="string[#key='EFFECTIVE_START_DATE']"/>
</string>
<string key="LASTNAME">
<xsl:value-of select="string[#key='LAST_NAME']"/>
</string>
</map>
</xsl:for-each>
</array>
</map>
</xsl:for-each-group>
</array>
</xsl:variable>
Note that, as an alternative approach, you can also transform the JSON directly as XDM 3.1 maps and arrays and do the grouping on that data, without the need to convert to XML back and forth; the only drawback is that XSLT 3 lacks an instruction to create an array so there you have to rely on XPath 3.1 expressions like [ ] or array { } which sometimes requires you to use a function call inside a template.
An example for your sample would be
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:function name="mf:group" as="map(*)*">
<xsl:param name="persons" as="map(*)*"/>
<xsl:for-each-group select="$persons" group-by="?PERSON_ID">
<xsl:sequence select="map { 'PersonId' : current-grouping-key(),
'value' : array {
current-group() ! map { 'EffectiveDate ' : ?EFFECTIVE_START_DATE,
'lastName' : ?LAST_NAME } } }"/>
</xsl:for-each-group>
</xsl:function>
<xsl:output method="json" indent="yes"/>
<xsl:param name="json-input" as="xs:string"/>
<xsl:template name="xsl:initial-template">
<xsl:apply-templates select="parse-json($json-input)"/>
</xsl:template>
<xsl:template match=".">
<xsl:sequence select="array { mf:group(?*) }"/>
</xsl:template>
</xsl:stylesheet>
Another disadvantage to the JSON -> XML -> JSON conversion is the lack of order of the key value pairs in XDM maps, that way the serialized JSON often doesn't have the order of keys you expect. The commercial versions of Saxon have some extension attribute to define the order for serialization.
With xslt3 of Saxon JS 2.2 and later you can even feed the JSON directly as the input to the transform with the -json:data.json option and use e.g.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:function name="mf:group" as="map(*)*">
<xsl:param name="persons" as="map(*)*"/>
<xsl:for-each-group select="$persons" group-by="?PERSON_ID">
<xsl:sequence select="map { 'PersonId' : current-grouping-key(),
'value' : array {
current-group() ! map { 'EffectiveDate ' : ?EFFECTIVE_START_DATE,
'lastName' : ?LAST_NAME } } }"/>
</xsl:for-each-group>
</xsl:function>
<xsl:output method="json" indent="yes"/>
<xsl:template match=".">
<xsl:sequence select="array { mf:group(?*) }"/>
</xsl:template>
</xsl:stylesheet>
I think we will see a similar option for the next mayor Saxon Java release.

steeltoe serilog dynamic logger not working after migrating to steeltoe 3.0

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)

binding.gyp: How to use "copies" section to copy files in multiple location

I am writing code to load c++ dll from electron. I am using node-gyp. In my binding.gyp file I use "copies" tag to copy dlls to Release folder. However I want to copy few more files to be copied to a different location. I tried hit and trial method to do it but was unsuccessful. Here is how my binding.gyp looks:
{
"targets": [{
"conditions":[
["OS=='win'", {
"copies":[{
'destination': './build/Release',
'files':[
'../../cl-fc-client-thirdparty/bugtrap/BugTrapU-x64.dll',
'../build/bin/msvc/Release64/cloudDrive2Lib.dll',
'../../cl-fc-client-thirdparty/openssl/1.0.2j/lib/x86_64-win32/ssleay32MD.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoZip64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoXML64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoUtil64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoNetSSL64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoNet64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoJSON64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoFoundation64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoCrypto64.dll',
'../../cl-fc-client-thirdparty/openssl/1.0.2j/lib/x86_64-win32/libeay32MD.dll'
]
}]
}]
],
"target_name": "electronToCppBridge",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"sources": [
"src/electronToCppBridge.cc",
],
'include_dirs': [
"<!#(node -p \"require('node-addon-api').include\")"
],
'libraries': ["../libs/cloudDrive2Lib.lib"],
'dependencies': [
"<!(node -p \"require('node-addon-api').gyp\")"
],
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
}]
}
Never mind, I was able to achieve this in the following way:
{
"targets": [{
"conditions":[
["OS=='win'", {
"copies":[
{
'destination': './build/Release',
'files':[
'../../cl-fc-client-thirdparty/bugtrap/BugTrapU-x64.dll',
'../build/bin/msvc/Release64/cloudDrive2Lib.dll',
'../../cl-fc-client-thirdparty/openssl/1.0.2j/lib/x86_64-win32/ssleay32MD.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoZip64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoXML64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoUtil64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoNetSSL64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoNet64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoJSON64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoFoundation64.dll',
'../../cl-fc-client-thirdparty/poco/1.7.5/bin64/PocoCrypto64.dll',
'../../cl-fc-client-thirdparty/openssl/1.0.2j/lib/x86_64-win32/libeay32MD.dll'
]
},
{
'destination': './libs',
'files':['../build/bin/msvc/Release64/cloudDrive2Lib.lib']
}
]
}]
],
"target_name": "electronToCppBridge",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"sources": [
"src/electronToCppBridge.cc",
],
'include_dirs': [
"<!#(node -p \"require('node-addon-api').include\")"
],
'libraries': ["../libs/cloudDrive2Lib.lib"],
'dependencies': [
"<!(node -p \"require('node-addon-api').gyp\")"
],
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
}]
}

How to loop through common id values in XSLT

I recently started working on XSLT. I have a requirement of grouping node values based on id field. However id field could be a duplicate value. For example, lets say below is the XML structure.
<ProductResults>
<ProductResult>
<ProductId>1000</ProductId>
<Location>Bangalore</Location>
<ModuleNumber>02</ModuleNumber>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>2000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Bangalore</Location>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>01</ModuleNumber>
<Location>Mumbai</Location>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>4000</ProductId>
<ModuleNumber>02</ModuleNumber>
<Location>Kolkata</Location>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Chennai</Location>
<StoreId>1234<StoreId>
</ProductResult>
</ProductResults>
If you notice, the ProductId 1000 is repeating thrice. I am supposed to write XSLT to produce below output.
{
"StoreId": "1234",
"Locations": [
{
"ProductId": "1000",
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "02"
},
{
"Location": "Mumbai",
"ModuleNumber": "01"
},
{
"Location": "Chennai",
"ModuleNumber": "03"
}
]
},
{
"ProductId": "2000",
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "03"
}
]
},
{
"ProductId": "4000",
"Locations": [
{
"Location": "Kolkata",
"ModuleNumber": "02"
}
]
}
]
}
Since the ProductId field is repeating, I cannot use foreach loop directly which creates extra code block for same ProductId . Any suggestions on this?.
Thanks in advance.
The following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"
version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:apply-templates select="#*|node()" />
</xsl:template>
<xsl:template match="#*|node()">
<xsl:variable name="uniqueProducts"
select="count(//ProductId[not(. = following::ProductId)])"/>
{
"StoreId": <xsl:value-of select="ProductResult/StoreId"/>,
"Locations": [
<xsl:for-each select="//ProductId[not(. = following::ProductId)]">
<xsl:sort select="."/>
{
"ProductId": "<xsl:value-of select="."/>,
"Locations": [
<xsl:call-template name="location">
<xsl:with-param name="productId" select="."/>
</xsl:call-template>
]
<xsl:if test="position() < $uniqueProducts">,</xsl:if>
</xsl:for-each>
]}
</xsl:template>
<xsl:template name="location">
<xsl:param name="productId"/>
<xsl:for-each select="//ProductResult[ProductId=$productId]">
{
"Location": "<xsl:value-of select="Location"/>",
"ModuleNumber": "<xsl:value-of select="ModuleNumber"/>"
}
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied to the following (corrected, as you didn't close the StoreId in your example)
Input XML:
<ProductResults>
<ProductResult>
<ProductId>1000</ProductId>
<Location>Bangalore</Location>
<ModuleNumber>02</ModuleNumber>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>2000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Bangalore</Location>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>01</ModuleNumber>
<Location>Mumbai</Location>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>4000</ProductId>
<ModuleNumber>02</ModuleNumber>
<Location>Kolkata</Location>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Chennai</Location>
<StoreId>1234</StoreId>
</ProductResult>
</ProductResults>
produces the following
Output XML:
{
"StoreId": 1234,
"Locations": [
{
"ProductId": "1000,
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "02"
}
,
{
"Location": "Mumbai",
"ModuleNumber": "01"
}
,
{
"Location": "Chennai",
"ModuleNumber": "03"
}
]
,
{
"ProductId": "2000,
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "03"
}
]
,
{
"ProductId": "4000,
"Locations": [
{
"Location": "Kolkata",
"ModuleNumber": "02"
}
]
]}
Note that this is only an example for the grouping, with e.g. an additional for-each loop it would be possible to adjust this to take care for more than a single StoreId.
For simplification I've just wrote this for the one StoreId provided using <xsl:value-of select="ProductResult/StoreId"/> instead of checking for different StoreId values and processing all of them.
For detailed references you can check this article by Jeni Tennison http://www.jenitennison.com/xslt/grouping/muenchian.xml for Muenchian Grouping, and
you can e.g. have a look at http://www.dpawson.co.uk/xsl/sect2/N4486.html for XSLT Grouping.
Update: Just adjusted first posted XSLT, and for explanation how this works - the <xsl:for-each select="//ProductId[not(. = following::ProductId)]"> loop processes all unique ProductId values, calling the <xsl:template name="location"> with the current ProductId as parameter and generating the output for every location that matches the ProductId. Though the updated approach doesn't use Muenchian Grouping, it may still be of value for you so I'll keep the reference.