I have template, and i need to build html. I can parse each element but stuck when trying to build all html. My code did not work for now. And may by all my way is wrong, and it shuld be another method to make html from template. Can any one help?
const data = ['html', [
['head', [
['title', 'titletext'],
]],
['body', { class: 'bodyClass' }, [
['h1', { class: 'headerClass' }, 'h1text'],
['div', [
['span', 'span1text'],
['span', 'span2text'],
]],
]],
]];
const tagBuilder = (tagArray) => {
if (tagArray[1] instanceof Array) {
return tagBuilder(tagArray[1]);
}
if (tagArray[1] instanceof Object) {
return `<${tagArray[0]} class="${tagArray[1].class}">` + String(tagArray[2]) + `</${tagArray[0]}>`;
}
return `<${tagArray[0]}>` + String(tagArray[1]) + `</${tagArray[0]}>`;
}
const htmpBuilder = (data) => {
return data.map(element => tagBuilder(element));
};
document.getElementById("output").textContent = htmpBuilder(data);
<pre id="output">
</pre>
Output i need:
<html>
<head>
<title>titletext</title>
</head>
<body class="bodyClass">
<h1 class="headerClass">h1text</h1>
<div>
<span>span1text</span>
<span>span2text</span>
</div>
</body>
</html>
You might consider creating a structure with objects instead - that way, you can just look up the .class
property of the object, or the .contents
property of the object, or the .tag
property of the object, the process will probably make a whole lot more sense at a glance. The only real non-trivial logic involved is checking if the .contents
is an array (in which case, recursively .map
them by tagBuilder
and join by the empty string):
const data = {
tag: 'html',
contents: [
{
tag: 'head',
contents: [{
tag: 'title',
contents: 'titletext'
}]
}, {
tag: 'body',
class: 'bodyClass',
contents: [{
tag: 'h1',
class: 'headerClass',
contents: 'h1text'
}, {
tag: 'div',
contents: [{
tag: 'span',
contents: 'span1text'
}, {
tag: 'span',
contents: 'span2text'
}]
}]
}
]
};
const tagBuilder = ({ tag, class: className, contents = '' }) => {
const contentsStr = Array.isArray(contents)
? contents.map(tagBuilder).join('')
: contents;
return `<${tag}${className ? ` class="${className}"` : ''}>${contentsStr}</${tag}>`;
}
console.log(tagBuilder(data));
If you need newlines between tags and pretty-printed HTML too (which usually shouldn't matter), then pass along an indent
parameter too, which gets added to the start of tag lines (and the start of end-tag lines, when that tag contains non-text children):
const data = {
tag: 'html',
contents: [
{
tag: 'head',
contents: [{
tag: 'title',
contents: 'titletext'
}]
}, {
tag: 'body',
class: 'bodyClass',
contents: [{
tag: 'h1',
class: 'headerClass',
contents: 'h1text'
}, {
tag: 'div',
contents: [{
tag: 'span',
contents: 'span1text'
}, {
tag: 'span',
contents: 'span2text'
}]
}]
}
]
};
const tagBuilder = ({ tag, class: className, contents = '' }, indent = 0) => {
const contentsStr = Array.isArray(contents)
? '\n' + contents.map(item => ' '.repeat(indent + 2) + tagBuilder(item, indent + 2)).join('\n') + '\n'
: contents;
return `<${tag}${className ? ` class="${className}"` : ''}>${contentsStr}${Array.isArray(contents) ? ' '.repeat(indent) : ''}</${tag}>`;
}
console.log(tagBuilder(data));
If you have to use your original data
structure (which I'd consider to be a mistake, since it requires confusing logic), then extract the tag, contents, and className from the array, then do the exact same thing:
const data = ['html', [
['head', [
['title', 'titletext'],
]],
['body', { class: 'bodyClass' }, [
['h1', { class: 'headerClass' }, 'h1text'],
['div', [
['span', 'span1text'],
['span', 'span2text'],
]],
]],
]];
const tagBuilder = (arr, indent = 0) => {
const tag = arr.shift();
const className = !Array.isArray(arr[0]) && typeof arr[0] === 'object'
? arr.shift().class
: '';
const contents = arr.length
? arr.shift()
: '';
const contentsStr = Array.isArray(contents)
? '\n' + contents.map(item => ' '.repeat(indent + 2) + tagBuilder(item, indent + 2)).join('\n') + '\n'
: contents;
return `<${tag}${className ? ` class="${className}"` : ''}>${contentsStr}${Array.isArray(contents) ? ' '.repeat(indent) : ''}</${tag}>`;
}
console.log(tagBuilder(data));
thank you for helpfull advice. your template looks more informative But now we have what we have. ( And I need build html from templates with this structure.
Well, you did say "And may by all my way is wrong" - trying to construct HTML from such a weird structure is a strange thing to want to do, I'd consider having to work with such a structure in the first place to be one of the big problems. You can still test and extract the types of arguments from the array, then use the same logic as before, but it looks quite ugly IMO
You right this is "weird structure". :( Thank you for help!