You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
435 lines
15 KiB
435 lines
15 KiB
<Query Kind="Program"> |
|
<NuGetReference>Newtonsoft.Json</NuGetReference> |
|
<Namespace>Newtonsoft.Json</Namespace> |
|
<Namespace>Newtonsoft.Json.Bson</Namespace> |
|
<Namespace>Newtonsoft.Json.Converters</Namespace> |
|
<Namespace>Newtonsoft.Json.Linq</Namespace> |
|
<Namespace>Newtonsoft.Json.Schema</Namespace> |
|
<Namespace>Newtonsoft.Json.Serialization</Namespace> |
|
</Query> |
|
|
|
void Main() |
|
{ |
|
string Rendered = JsonFromTemplate(Globals.strTemplate, Globals.strData); |
|
Rendered.Dump(); |
|
} |
|
|
|
// render adaptive card JSON |
|
public string JsonFromTemplate(string strTemplate, string strData) |
|
{ |
|
string output = ""; |
|
|
|
// replace instances of $data with x-data |
|
// this is to work around JSON Path limitations |
|
strTemplate = strTemplate.Replace("$","x-"); |
|
|
|
// first create JSON objects out of the input |
|
JObject template = JObject.Parse(strTemplate); |
|
JObject data = JObject.Parse(strData); |
|
|
|
// this is the old way - regex against the string |
|
// maybe do it a better way |
|
string queryString = @"..[?(@ =~ /\{(.+)?\}/)]"; |
|
|
|
List<JToken> nodeList = template.SelectTokens(queryString).ToList(); |
|
|
|
// for each templated entity |
|
// retrieve entity from data JSON |
|
// if empty, remove entity |
|
foreach (JValue node in nodeList) |
|
{ |
|
// get string literal for template entity |
|
string fulltext = node.Value<string>(); |
|
|
|
// find the matching element in the data JSON |
|
// strip { and } from fulltext |
|
string cleantext = fulltext.Substring(1, fulltext.Length - 2); |
|
|
|
string searchString = "$." + cleantext; |
|
|
|
// find the token in Data JSON |
|
// can be JValue or JArray |
|
JToken searchResult = data.SelectToken(searchString); |
|
|
|
// if this element exists in the data |
|
// and isn't $data |
|
// replace element with text from Data JSON |
|
// otherwise remove it |
|
if (searchResult != null) |
|
{ |
|
if (searchResult.GetType() == typeof(JValue)) |
|
{ |
|
string oldValue = node.Value<string>(); |
|
string newValue = oldValue.Replace(fulltext, ((JValue)searchResult.Value<string>()).ToString()); |
|
node.Value = node.Value<string>().ToString().Replace(oldValue, newValue); |
|
} |
|
else if (searchResult.GetType() == typeof(JArray)) |
|
{ |
|
// it's a JArray |
|
JArray searchArray = (JArray)searchResult; |
|
|
|
foreach (string item in searchArray) |
|
{ |
|
JObject newItem = new JObject((JObject)node.Parent.Parent); |
|
newItem["x-data"].Parent.Remove(); |
|
newItem["text"] = item; |
|
|
|
node.Parent.Parent.Parent.Add(newItem); |
|
} |
|
|
|
node.Parent.Parent.Remove(); |
|
} |
|
} |
|
else if (fulltext.Contains("{x-")) |
|
{ |
|
// this is handled differently |
|
} |
|
else |
|
{ |
|
// remove this node |
|
node.Parent.Parent.Remove(); |
|
} |
|
} |
|
// now find any empty arrays and nuke their parents |
|
// keep doing this until there are no more [] left in the JSON |
|
|
|
while (template.Descendants().OfType<JArray>().Where(v => v.Type == JTokenType.Array && v.Count() == 0).ToList().Count() > 0) |
|
{ |
|
List<JArray> EmptyNodes = template.Descendants().OfType<JArray>().Where(v => v.Type == JTokenType.Array && v.Count() == 0).ToList(); |
|
foreach (JArray Node in EmptyNodes) |
|
{ |
|
Node.Parent.Parent.Remove(); |
|
} |
|
} |
|
|
|
JsonConvert.SerializeObject(template, Newtonsoft.Json.Formatting.Indented).Dump(); |
|
|
|
return output; |
|
} |
|
|
|
// set up global statics |
|
public class Globals |
|
{ |
|
public static string strData = @" |
|
{ |
|
""template"" : |
|
{ |
|
""image"" : ""image"", |
|
""clade"" : ""Clades"", |
|
""name"" : ""Common Name"", |
|
""order"" : ""Order"", |
|
""family"" : ""Family"", |
|
""genus"" : ""Genus"", |
|
""species"" : ""Species (Latin Name)"" |
|
}, |
|
""item"" : |
|
{ |
|
""image"" : ""almonds.jpg"", |
|
""clade"" : [ |
|
""Tracheophytes"", |
|
""Angiosperms"", |
|
""Eudicots"", |
|
""Rosids"" |
|
], |
|
""name"" : ""American Hazelnut"", |
|
""order"" : ""Fagales"", |
|
""family"" : ""Betulaceae"", |
|
""genus"" : ""Corylus"", |
|
""species"" : ""Corylus Americana"" |
|
} |
|
} |
|
"; |
|
|
|
public static string strTemplate = @" |
|
{ |
|
""type"": ""AdaptiveCard"", |
|
""body"": [ |
|
{ |
|
""type"": ""Container"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{item.name}"", |
|
""size"": ""Large"", |
|
""weight"": ""Bolder"", |
|
""horizontalAlignment"": ""Center"", |
|
""color"": ""Accent"" |
|
}, |
|
{ |
|
""type"": ""Image"", |
|
""url"": ""{item.image}"", |
|
""altText"": """" |
|
}, |
|
{ |
|
""type"": ""ColumnSet"", |
|
""columns"": [ |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""horizontalAlignment"": ""Right"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{template.other}"", |
|
""weight"": ""Bolder"", |
|
""horizontalAlignment"": ""Right"" |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{item.other}"" |
|
} |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""ColumnSet"", |
|
""columns"": [ |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""horizontalAlignment"": ""Right"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{template.name}"", |
|
""weight"": ""Bolder"", |
|
""horizontalAlignment"": ""Right"" |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{item.name}"" |
|
} |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""ColumnSet"", |
|
""columns"": [ |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""horizontalAlignment"": ""Right"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{template.order}"", |
|
""weight"": ""Bolder"", |
|
""horizontalAlignment"": ""Right"" |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{item.order}"" |
|
} |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""ColumnSet"", |
|
""columns"": [ |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""horizontalAlignment"": ""Right"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{template.family}"", |
|
""weight"": ""Bolder"", |
|
""horizontalAlignment"": ""Right"" |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{item.genus}"" |
|
} |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""ColumnSet"", |
|
""columns"": [ |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""horizontalAlignment"": ""Right"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{template.species}"", |
|
""weight"": ""Bolder"", |
|
""horizontalAlignment"": ""Right"" |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{item.species}"" |
|
} |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""ColumnSet"", |
|
""columns"": [ |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""horizontalAlignment"": ""Right"", |
|
""items"": [ |
|
{ |
|
""type"": ""TextBlock"", |
|
""text"": ""{template.clade}"", |
|
""weight"": ""Bolder"", |
|
""horizontalAlignment"": ""Right"" |
|
} |
|
] |
|
}, |
|
{ |
|
""type"": ""Column"", |
|
""width"": ""stretch"", |
|
""items"": [ |
|
{ |
|
""type"": ""Container"", |
|
""items"": [ |
|
{ |
|
""$data"": ""{item.clade}"", |
|
""type"": ""TextBlock"", |
|
""text"": ""{$data}"" |
|
} |
|
] |
|
} |
|
] |
|
} |
|
] |
|
} |
|
] |
|
} |
|
], |
|
""$schema"": ""http://adaptivecards.io/schemas/adaptive-card.json"", |
|
""version"": ""1.0"" |
|
}"; |
|
} |
|
|
|
// How I used to do things with regex: |
|
// ========================================================================================================================================== |
|
// // get list of {template.refs} from JSON string |
|
// Match m = Regex.Match(strTemplate, @"\{(.+)?\}"); |
|
// |
|
// //List<string> Elements = new List<string>(); |
|
// |
|
// Dictionary<string,List<JToken>> elements = new Dictionary<string,List<JToken>>(); |
|
// |
|
// while(m.Success) |
|
// { |
|
// if (!elements.Keys.Contains(m.Value)) |
|
// { |
|
// List<JToken> elementList = new List<JToken>(); |
|
// // find the JToken(s) containing this element |
|
// foreach (string el in Globals.CheckElements) |
|
// { |
|
// IEnumerable<JToken> tempList = template.SelectTokens("$.." + el).Where(y => y.Value<string>().Contains(m.Value)); |
|
// elementList.AddRange(tempList); |
|
// } |
|
// |
|
// // strip {} from element name |
|
// string searchTerm = m.Groups[1].Value; |
|
// |
|
// string searchString = "$." + searchTerm; |
|
// |
|
// // find the token in Data JSON |
|
// // can be JValue or JArray |
|
// var searchResult = data.SelectToken(searchString); |
|
// |
|
// // if this element exists in the data |
|
// // and isn't $data |
|
// // replace element with text from Data JSON |
|
// // otherwise remove it |
|
// if (searchResult != null) |
|
// { |
|
// if (searchResult.GetType() == typeof(JValue)) |
|
// { |
|
// // it's a JValue |
|
// // String.Replace value with SearchResult value as string |
|
// // Elements.Add(m.Value, elementList); |
|
// // for every element in elementList |
|
// // replace m.Value with SearchResult.Value.ToString() |
|
// foreach (JValue element in elementList) |
|
// { |
|
// string oldValue = element.Value<string>(); |
|
// string newValue = oldValue.Replace(m.Value,((JValue)searchResult.Value<string>()).ToString()); |
|
// element.Value = element.Value.ToString().Replace(oldValue, newValue); |
|
// } |
|
// } |
|
// else if (searchResult.GetType() == typeof(JArray)) |
|
// { |
|
// // it's a JArray |
|
// } |
|
// } |
|
// else if (m.Value == "{x-data}") |
|
// { |
|
// // this needs to be output as a list of data |
|
// |
|
// } |
|
// else |
|
// { |
|
// // what is this? |
|
// // find the token in the Template array and remove it |
|
// string nodeText = m.Groups[1].Value; |
|
// |
|
// // search for all nodes containing this value in any of the keys found in CheckElements |
|
// // add to list FoundNodes |
|
// // build a search string |
|
// |
|
// // Evaluates to .*\{item\.name}.* |
|
// string innerValue = Regex.Escape("{" + nodeText + "}"); |
|
// string regexString = $".*{innerValue}.*"; |
|
// |
|
// string jsonPath = $"..[?(@ =~ /{regexString}/)]"; |
|
// |
|
// List<JToken> FoundNodes = template.SelectTokens(jsonPath).ToList(); |
|
// |
|
// foreach (JToken Node in FoundNodes) |
|
// { |
|
// // find node by path |
|
// // this is the value of the property |
|
// // parent is property |
|
// // grandparent is node |
|
// Node.Parent.Parent.Remove(); |
|
// } |
|
// } |
|
// } |
|
// |
|
// m = m.NextMatch(); |
|
// } |