An editor for Microsoft Adaptive Cards that supports the new templating language and DOESN'T use JavaScript, because JavaScript isn't a real programming language.
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

<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();
// }