using System.Collections.Generic;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
public static void Main(string[] args)
string cart = @"{'id':'8ea1a18b-ee05-4c72-b691-5a6e0e080b98','visitId':'055511a7-dd54-48ec-b09c-bcd8d205dcf1','metadata':{'createdBy':'9a220007-ac73-41d0-a5b8-27b66c71c600','created':'2018-01-05T23:29:48.3602503+00:00','modifiedBy':'9a220007-ac73-41d0-a5b8-27b66c71c600','modified':'2018-01-05T23:30:05.0947562+00:00','type':'Cart','version':'0.1'},'tenantId':'9a220007-ac73-41d0-a5b8-27b66c71c600','fulfillmentId':null,'status':'PaymentComplete','businessData':null,'businessDataVersion':null,'userParts':[],'items':[{'id':'45b7ba99-812a-4897-b838-bc3a9227bd72','type':'','itemNumber':'000100001502','description':'2017','amount':140938.37,'taxable':false,'userParts':[{'name':'ParcelNumber','value':'000100001502'},{'name':'InterestAndPenalty','value':'13966.87'}],'quantity':1}],'payer':{'id':'3d89a69f-fe7d-4b9e-b1fb-a6f33b1d12ba','last':'kumar','first':'kirthi','title':null,'phone':'2062637926','email':'kirthi.kumar@kingcounty.gov','address':[{'id':'c89b861e-9cf8-4c9e-bf1e-6a5ee390e89b','addressType':'Payer','street':'401 5th ave','street2':'','city':'Seattle','region':'WA','countryCode':'US','postalCode':'98104'}]},'transactions':[{'id':'00eff3f7-3c97-4794-a30e-64ae60bae210','transactionType':'Purchase','paymentType':'Visa','paymentAccount':'1111','transactionNumber':'6115563','total':144250.42,'amount':140938.37,'transactionTimestamp':'2018-01-04T23:30:01.547','transactionSource':'API','fees':3312.05,'status':'Approved','vendorTransactionInfo':'{\r\n \'OrderTypeCD\': \'1\',\r\n \'OrderTypeName\': \'Purchase\',\r\n \'StatusCD\': \'6\',\r\n \'Status\': \'Approved - PCB\'\r\n}'}],'extendedPropertiesVersion':null,'extendedProperties':null}";
string cartTemplate = @"<div><p>Dear {{cart:.payer.first}} {{cart:.payer.last}},</p><p>Thank you for submitting your payment using the Property Tax Information System. Your transaction reference number is {{cart:.transactions[?(@.transactionType=='Purchase' && @.status=='Approved')].transactionNumber}}.</p><p>The following items were submitted on {{cart:.transactions[?(@.transactionType=='Purchase' && @.status=='Approved')].transactionTimestamp:date}}:</p><table border='1'<tbody><tr><td><strong>Product Id</strong></td><td><strong>Description</strong></td></tr><tr>{{itemsTemplate}}</tr></tbody></table><p><br />The total amount of the purchase including a {{cart:.transactions[?(@.transactionType=='Purchase' && @.status=='Approved')].fees:currency}} convenience fee was {{cart:.transactions[?(@.transactionType=='Purchase' && @.status=='Approved')].total:currency}}.</p><p><font color='red'>If you paid by e-check, please verify that this transaction is posted to your checking account within three business days. If you entered an invalid checking account, an account not authorized for this transaction, or funds are insufficient, your transaction will be reversed and your tax account may be subject to late payment penalties.</font></p><p>Please note that it may take up to two weeks for your property tax payment to be reflected in our records after receiving your payment.</p><p>Please print this email for your records. If you have any questions regarding your transaction, please contact a King County representative at 206-263-2890. Please do not respond to this email.</p><p>Sincerely,</p><p>King County Ecommerce</p><div>";
string itemsTemplate = @"<td>{{item:.itemNumber}}</td><td>{{item:.description}}</td>";
ICollection<string> cartMatches = Regex.Matches(cartTemplate.Replace(Environment.NewLine, ""), @"\{\{([^}]*)\}\}").Cast<Match>().Select(x => x.Groups[1].Value).ToList();
ICollection<string> itemsMatches = Regex.Matches(itemsTemplate.Replace(Environment.NewLine, ""), @"\{\{([^}]*)\}\}").Cast<Match>().Select(x => x.Groups[1].Value).ToList();
JObject jCart = JObject.Parse(cart);
JArray jItems = (JArray)jCart.SelectToken("items");
StringBuilder itemsHtml = new StringBuilder();
foreach(JObject jItem in jItems.Children())
string itemTemplate = itemsTemplate;
foreach (string placeholder in itemsMatches)
string placeHolderValue = "NOT FOUND";
if (placeholder.StartsWith("item:", StringComparison.OrdinalIgnoreCase))
string jsonPath = placeholder.Replace("item:", "");
placeHolderValue = (string)jItem.SelectToken(jsonPath);
itemTemplate = itemTemplate.Replace("{{" + placeholder + "}}", placeHolderValue);
itemsHtml.Append(itemTemplate);
foreach (string placeholder in cartMatches)
string placeHolderValue = "NOT FOUND";
if (placeholder.StartsWith("cart:", StringComparison.OrdinalIgnoreCase))
string jsonPath = placeholder.Replace("cart:", "");
placeHolderValue = (string)jCart.SelectToken(jsonPath);
if (placeholder.StartsWith("items:", StringComparison.OrdinalIgnoreCase))
if(!string.IsNullOrEmpty(itemsHtml.ToString()))
placeHolderValue = itemsHtml.ToString();
if (placeholder.StartsWith("sys:", StringComparison.OrdinalIgnoreCase))
string jsonPath = placeholder.Replace("sys:", "");
placeHolderValue = System.DateTime.Now.ToShortDateString();
cartTemplate = cartTemplate.Replace("{{" + placeholder + "}}", placeHolderValue);
Console.WriteLine(cartTemplate);
private static string ApplyPlaceHolderOptions(string placeHolderValue, List<string> options)
foreach (string option in options)
placeHolderValue = string.Format("{0:c}", Convert.ToDecimal(placeHolderValue));
Console.WriteLine(placeHolderValue);
placeHolderValue = TimeZoneInfo.ConvertTimeFromUtc(Convert.ToDateTime(placeHolderValue), TimeZoneInfo.Local).ToString("MM/dd/yyyy h:mm:ss tt");
Console.WriteLine(placeHolderValue);