I've just wrote a little example of the parser, similar to mentioned by you, using plain old JavaScript. My code is a bit dirty (as mentioned by Casey Hope, you shouldn't extend Object.prototype
) , perhaps, but it works and very easy to understand, I hope.
The function itself:
Object.prototype.toHtml = function(options)
{
//Iterates over elements
var processElements = function(obj, handler)
{
//Stores found elements
var elements = [];
for (var elem in obj)
{
//Skips all 'derived' properties
if (!obj.hasOwnProperty(elem)) continue;
//Attribute
if (elem.indexOf("_") == 0)
{
elements.push({type: "attribute", name : /^_([a-z][0-9a-z]+)$/i(elem)[1], value : obj[elem]});
}
//Internal contents
else if (elem == "contents")
{
elements.push({type: "contents", value : obj[elem]});
}
//Text node
else if (elem == "text")
{
elements.push({type: "text", value : obj[elem]});
}
//Ordinary element
else
{
elements.push({type: "element", name : elem, value : obj[elem]});
}
}
//Returns parsed elements
return elements;
}
//Internal function to deal with elements
var toHtmlInternal = function(name, elements)
{
//Creates a new element by name using DOM
var element = document.createElement(name);
//Element children and attributes
var children = processElements(elements);
for (var i = 0; i < children.length; i++)
{
switch (children[i]["type"])
{
case "element":
element.appendChild(toHtmlInternal(children[i]["name"], children[i]["value"]));
break;
case "attribute":
element.setAttribute(children[i]["name"], children[i]["value"]);
break;
case "text":
element.appendChild(document.createTextNode(children[i]["value"]));
break;
case "contents":
for (var j = 0; j < children[i]["value"].length; j++)
{
var content = children[i]["value"][j];
if (typeof content == "string")
{
element.appendChild(document.createTextNode(content));
}
else if (typeof content == "object")
{
element.appendChild(content.toHtml().firstChild);
}
}
break;
}
}
//Returns it
return element;
}
//Initial element checkment
var initial = processElements(this);
//Generic wrapper
var wrapper = document.createElement("div");
for (var i = 0; i < initial.length; i++)
{
if (initial[i]["type"] == "element")
{
wrapper.appendChild(toHtmlInternal(initial[i]["name"], initial[i]["value"]));
}
}
//Returns wrapper
return wrapper;
};
How to use:
//A simple testing template
var html = ({
//Element name is just a plain name here
body: {
//Nested element
div : {
//All attributes are prepended with underscore
_id : "title",
//Content of the element is represented by such construction
text : "Great work!"
},
span : {
text : "My name is Peter"
},
h1 : {
_class : "common",
//Elements can be defined using 'contents' notation also, so we could include text nodes
contents : ["This is my ", {a : {text: "beautiful"}} , " header"]
}
}
}).toHtml();
alert(html.innerHTML);