Browse Source

Completed design of template renderer

master
Claire Davis 3 years ago
parent
commit
bb38e0cfbd
  1. 91
      Adaptive Card Editor UWP/MainPage.xaml.cs
  2. 200
      Scripts/template parser.linq

91
Adaptive Card Editor UWP/MainPage.xaml.cs

@ -162,14 +162,14 @@ namespace Adaptive_Card_Editor_UWP
// render a card using template and data
try
{
string Template = txtInput.Text;
string Data = txtData.Text;
string template = txtInput.Text;
string data = txtData.Text;
string Rendered = JsonFromTemplate(Template, Data);
string rendered = JsonFromTemplate(template, data);
// render the card from the rendered template + data
AdaptiveCardRenderer cardRenderer = new AdaptiveCardRenderer();
AdaptiveCardParseResult parsedCard = AdaptiveCard.FromJsonString(Rendered);
AdaptiveCardParseResult parsedCard = AdaptiveCard.FromJsonString(rendered);
RenderedAdaptiveCard theCard = cardRenderer.RenderAdaptiveCard(parsedCard.AdaptiveCard);
grdTemplated.Children.Add(theCard.FrameworkElement);
}
@ -211,7 +211,90 @@ namespace Adaptive_Card_Editor_UWP
JObject Template = JObject.Parse(strTemplate);
JObject Data = JObject.Parse(strData);
// 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();
}
}
output = JsonConvert.SerializeObject(template);
return output;
}

200
Scripts/template parser.linq

@ -11,43 +11,105 @@
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);
// body = array of jobjects
JArray TemplateBody = (JArray)Template["body"];
// for each jobject in this array
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
TemplateBody.Dump();
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 Dictionary<string, string> Containers = new Dictionary<string, string>
{
{ "ActionSet", "actions"},
{ "Container", "items" },
{ "ColumnSet", "columns"},
{ "Column", "items"},
{ "FactSet", "facts"},
{ "Fact", ""},
{ "ImageSet", "images"}
};
{
public static string strData = @"
{
""template"" :
@ -278,4 +340,96 @@ public class Globals
""$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();
// }
Loading…
Cancel
Save