Reputation: 1165
I would like to get some ideas how to achieve the following task. I'm writing a lightweight template language. That takes any array or json object and replaces the string-values with values from my local data store. Please let me illustrate how it works:
var obj = {
prop: "_p{propnameA}",
secondprop: "_p{propnameB}",
thirdprop: "Hello, this is \"_p{propnameC}\" and _p{propnameD},
arr: [
"textvalue", "propB value = _p{propB}"
]
}
I've wrote an algorithm that iterates over each property of each json or array. Now i need a fast way to replace all my template-tags to their actual values. I would like to use different types of template-tags:
etc.
each template-tag means something different in my program. For Example: the template-tag _p{} calls a method in my application with the parameter of the tag-value. _p{propval} is a equivalent to myApp.getProperty("propval")
Other tags call other methods of my application. I am thinking about using a string.replace with a regular expression for my tags. But i run into two problems:
the evaluated value of a tag must not always be a string. it could also be a more complex data type like an array or json object. In my first example code at the top of this question the resulting value for "_p{propnameA}" could be an array like [1,2,3,4]. Or _p{propnameB} could be a number and so my example on top should evaluate like:
obj = {
prop: [1, 2, 3, 4],
secondprop: 827,
thirdprop: "Hello, this is \"valueC\" and valueD",
arr: ["textvalue", "propE value = 827"]
}
obviously obj.secondprop should not have the string value "827" but the number instead while obj.arr[1] should be a string.
Do you got some smart ideas how to do this? Thank you very much for any help!
Upvotes: 0
Views: 104
Reputation: 215029
If I understood correctly, you're looking for something like this:
// evaluate a single placeholder like _p{foo}
function evalPlaceholder(prefix, content) {
switch(prefix) {
case "_p": do_this();
case "_c": do_that();
//etc
}
}
// eval a string with placeholders
function evalTemplate(str) {
var m = str.match(/^(_\w){([^{}]+)}$/);
if(m) {
// the whole string _is_ a placeholder
return evalPlaceholder(m[1], m[2]);
}
// otherwise, the string can _contain_ placeholders
return str.replace(/(_\w){(.+?)}/g, function(_, $1, $2) {
return evalPlaceholder($1, $2);
});
}
// walk an object recursively and eval all templates
function evalObject(obj) {
Object.keys(obj).forEach(function(k) {
var v = obj[k];
if(typeof v == "object")
evalObject(v)
else
obj[k] = evalTemplate(v);
})
}
Upvotes: 1
Reputation: 1340
first, you can cast numeric values to strings in two ways, which I am sure you have seen something like this before:
1- toString function call: var x = 825; console.log(x.toString())
2- adding the number to a string: var x = '' + 825
so if you don't want numeric values, but only strings, just make sure you convert the value to string (even if it's a string nothing will happen) before you use it.
second, I don't think I really got your problem, but from what I got, your problem is much simpler that a regex, you're only replacing well defined string, so while iterating over the values all you need is:
var p = prop.toString();
if(p.startsWith("_p") {
p.replace("_p", "_c)
}
I hope this is what you are looking for
Upvotes: 0