0

I am trying to figure out the best way to decorate html. What I mean is replacing specific syntax string with the actual content.

Kind of like, razor syntax in Asp.net MVC using <%= %>.

Currently, I have an HTML page with design and I just need to replace tags (for ex: <%HISTORICTABLE%>) with actual content.

I have 5-6 tags in HTML that needs to be replaced with the original html.

I might add new/remove tags ('behaviour') from html.

I think decorator pattern should do the trick or would you think its an overkill?

1

The decorator pattern is about augmenting the behavior of objects. For example, we might create a logging decorator that logs all method calls and then forwards the call to the original object. The decorator pattern is not directly useful for creating HTML templates.

All you need for a simple template engine is small function that

  • finds all template tags in the input,
  • replaces the tags with their values, and
  • takes care of HTML escaping.

In pseudocode, this might look like:

def expand_template(template: string, variables: dictionary) -> string {
  return template.replace_all("<%(\w+)%>", (match) => {
    var key = match[0];
    return html_escape(variables.get(key));
  });
}

or in Perl:

$template =~ s/ <%(\w+)%> / html_escape($variables{$1}) /xeg;

Here, the variables define the available “tags”. This approach also ensures that all tags are replaced at the same time, so that the order of expansion does not matter.

The use of a decorator pattern might make sense if you want to chain multiple kinds of expansions, and want to configure the order of expansions dynamically. For example:

interface HtmlTransformer {
  def transformed(html: string) -> string;
}

class Null() implements HtmlTransformer {
  override def transformed(html: source) -> string = source;
}

class TagExpander(next: HtmlTransformer, tags: dictionary) implement HtmlTransformer {
 override def transformed(html: source) -> string {
   return next.transformed(html)
              .replace_all("<%(\w+)%>", (match) => html_escape(tags.get(match[0])));
 }
}

var template = Null();
// add one decorator
template = TagExpander(template, {"foo": "bar <%baz%>"});
// maybe add another decorator
if (some_condition_holds) {
  template = TagExpander(template, {"baz": "qux"});
}

print(template.transformed("This is some <%foo%> text"))
// prints either: This is some foo bar <%baz%> text
//            or: This is some foo bar qux text
// depending on runtime behavior.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.