如何为我在 JavaScript 中编写的 HTML 生成器添加适当的缩进
How can I add proper indentation to this HTML generator that I wrote in JavaScript
我编写了一个函数,它接受一个表示 DOM 树的对象并输出 HTML 字符串。我使用了 DFS 方法来遍历对象。
const tree = {
children: [
{ children: [{ children: ['bar'], tag: 'span' }], tag: 'div' },
{ children: ['baz'], tag: 'div' },
],
tag: 'body',
}
function fromTreeToString(root) {
if (!root.children) {
return root
}
return (
`<${root.tag}>` + '\n' +
`${root.children.map((node) => fromTreeToString(node)).join('\n')}` + '\n' +
`</${root.tag}>`
)
}
fromTreeToString(tree)
输出为
<body>
<div>
<span>
bar
</span>
</div>
<div>
baz
</div>
</body>
我想知道如何修改此函数以使输出具有正确的缩进。理想情况下,输出应该类似于
<body>
<div>
<span>
bar
</span>
</div>
<div>
baz
</div>
</body>
理想情况下,此 API 的用户可以自定义缩进,例如选项卡与 space
您可以将适当的缩进传递给您的函数:
function fromTreeToString(root, indent) {
indent = indent || '';
if (!root.children) {
return indent + root
}
return (
`${indent}<${root.tag}>` + '\n' +
`${root.children.map((node) => fromTreeToString(node, indent + '. ')).join('\n')}` + '\n' +
`${indent}</${root.tag}>`
)
}
这里,每次递归都会增加缩进'. '
。模板字符串中的中间行没有直接缩进。它从递归调用中的 indent + '. '
中获取缩进。
在此版本中,您传递缩进字符串并返回一个函数,该函数采用树结构和 returns 格式化字符串:
const fromTreeToString = (indent = ' ', depth = 0) => (node) =>
`${indent.repeat(depth)}${node.tag ? `<${node .tag
}>\n${(node.children || []).map(c => fromTreeToString(indent, depth + 1)(c)) .join ('\n')
}\n${indent.repeat(depth)}</${node .tag}>` : node}`
const tree = {children: [{children: [{children: ['bar'], tag: 'span'}], tag: 'div'}, {children: ['baz'], tag: 'div'}, ], tag: 'body'}
const twoSpace = fromTreeToString(' ')
const fourSpace = fromTreeToString(' ')
const oneTab = fromTreeToString('\t')
console .log (twoSpace(tree))
console .log (fourSpace(tree))
console .log (oneTab(tree))
.as-console-wrapper {max-height: 100% !important; top: 0}
注意您的标题具有误导性,因为您不是解析HTML而是格式化它。
更新
这里是没有higher-order功能的版本。您可以传递任何您喜欢的缩进字符串。不通过就加两个空格。
const fromTreeToString = (node, indent = ' ', depth = 0) =>
`${indent.repeat(depth)}${node.tag ? `<${node .tag
}>\n${(node.children || []).map(c => fromTreeToString(c, indent, depth + 1)) .join ('\n')
}\n${indent.repeat(depth)}</${node .tag}>` : node}`
const tree = {children: [{children: [{children: ['bar'], tag: 'span'}], tag: 'div'}, {children: ['baz'], tag: 'div'}, ], tag: 'body'}
console .log (fromTreeToString(tree, ' '))
console .log (fromTreeToString(tree, ' '))
console .log (fromTreeToString(tree, '\t'))
您也可以首先使用递归到 return 一个 数组 行,并且只在末尾连接它们:
function fromTreeToString(root, indent='\t') {
const recur = root => root.children ? [
`<${root.tag}>`,
...root.children.flatMap(recur).map(s => indent + s),
`</${root.tag}>`
] : root;
return recur(root).join('\n');
}
const tree = {children: [{ children: [{ children: ['bar'], tag: 'span' }], tag: 'div' },{ children: ['baz'], tag: 'div' },],tag: 'body'}
console.log(fromTreeToString(tree, '. '));
这是使用 object-scan 的迭代答案。可能不是您 应该 使用的东西,但您可以。老实说,我只是很好奇它会如何发挥作用
// const objectScan = require('object-scan');
const tree = { children: [{ children: [{ children: ['bar'], tag: 'span' }], tag: 'div' }, { children: ['baz'], tag: 'div' }], tag: 'body' };
const fn = (down) => ({ key, value, context }) => {
if (value.constructor === Object) {
context.push(`${' '.repeat(key.length / 2)}<${down ? '' : '/'}${value.tag}>`);
} else if (down && typeof value === 'string') {
context.push(`${' '.repeat(key.length / 2)}${value}`);
}
};
const r = objectScan(['', '**(^children$)'], {
reverse: false,
useArraySelector: false,
breakFn: fn(true),
filterFn: fn(false)
})(tree, []).join('\n');
console.log(r);
/* =>
<body>
<div>
<span>
bar
</span>
</div>
<div>
baz
</div>
</body>
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@14.3.1"></script>
免责声明:我是object-scan
的作者
我编写了一个函数,它接受一个表示 DOM 树的对象并输出 HTML 字符串。我使用了 DFS 方法来遍历对象。
const tree = {
children: [
{ children: [{ children: ['bar'], tag: 'span' }], tag: 'div' },
{ children: ['baz'], tag: 'div' },
],
tag: 'body',
}
function fromTreeToString(root) {
if (!root.children) {
return root
}
return (
`<${root.tag}>` + '\n' +
`${root.children.map((node) => fromTreeToString(node)).join('\n')}` + '\n' +
`</${root.tag}>`
)
}
fromTreeToString(tree)
输出为
<body>
<div>
<span>
bar
</span>
</div>
<div>
baz
</div>
</body>
我想知道如何修改此函数以使输出具有正确的缩进。理想情况下,输出应该类似于
<body>
<div>
<span>
bar
</span>
</div>
<div>
baz
</div>
</body>
理想情况下,此 API 的用户可以自定义缩进,例如选项卡与 space
您可以将适当的缩进传递给您的函数:
function fromTreeToString(root, indent) {
indent = indent || '';
if (!root.children) {
return indent + root
}
return (
`${indent}<${root.tag}>` + '\n' +
`${root.children.map((node) => fromTreeToString(node, indent + '. ')).join('\n')}` + '\n' +
`${indent}</${root.tag}>`
)
}
这里,每次递归都会增加缩进'. '
。模板字符串中的中间行没有直接缩进。它从递归调用中的 indent + '. '
中获取缩进。
在此版本中,您传递缩进字符串并返回一个函数,该函数采用树结构和 returns 格式化字符串:
const fromTreeToString = (indent = ' ', depth = 0) => (node) =>
`${indent.repeat(depth)}${node.tag ? `<${node .tag
}>\n${(node.children || []).map(c => fromTreeToString(indent, depth + 1)(c)) .join ('\n')
}\n${indent.repeat(depth)}</${node .tag}>` : node}`
const tree = {children: [{children: [{children: ['bar'], tag: 'span'}], tag: 'div'}, {children: ['baz'], tag: 'div'}, ], tag: 'body'}
const twoSpace = fromTreeToString(' ')
const fourSpace = fromTreeToString(' ')
const oneTab = fromTreeToString('\t')
console .log (twoSpace(tree))
console .log (fourSpace(tree))
console .log (oneTab(tree))
.as-console-wrapper {max-height: 100% !important; top: 0}
注意您的标题具有误导性,因为您不是解析HTML而是格式化它。
更新
这里是没有higher-order功能的版本。您可以传递任何您喜欢的缩进字符串。不通过就加两个空格。
const fromTreeToString = (node, indent = ' ', depth = 0) =>
`${indent.repeat(depth)}${node.tag ? `<${node .tag
}>\n${(node.children || []).map(c => fromTreeToString(c, indent, depth + 1)) .join ('\n')
}\n${indent.repeat(depth)}</${node .tag}>` : node}`
const tree = {children: [{children: [{children: ['bar'], tag: 'span'}], tag: 'div'}, {children: ['baz'], tag: 'div'}, ], tag: 'body'}
console .log (fromTreeToString(tree, ' '))
console .log (fromTreeToString(tree, ' '))
console .log (fromTreeToString(tree, '\t'))
您也可以首先使用递归到 return 一个 数组 行,并且只在末尾连接它们:
function fromTreeToString(root, indent='\t') {
const recur = root => root.children ? [
`<${root.tag}>`,
...root.children.flatMap(recur).map(s => indent + s),
`</${root.tag}>`
] : root;
return recur(root).join('\n');
}
const tree = {children: [{ children: [{ children: ['bar'], tag: 'span' }], tag: 'div' },{ children: ['baz'], tag: 'div' },],tag: 'body'}
console.log(fromTreeToString(tree, '. '));
这是使用 object-scan 的迭代答案。可能不是您 应该 使用的东西,但您可以。老实说,我只是很好奇它会如何发挥作用
// const objectScan = require('object-scan');
const tree = { children: [{ children: [{ children: ['bar'], tag: 'span' }], tag: 'div' }, { children: ['baz'], tag: 'div' }], tag: 'body' };
const fn = (down) => ({ key, value, context }) => {
if (value.constructor === Object) {
context.push(`${' '.repeat(key.length / 2)}<${down ? '' : '/'}${value.tag}>`);
} else if (down && typeof value === 'string') {
context.push(`${' '.repeat(key.length / 2)}${value}`);
}
};
const r = objectScan(['', '**(^children$)'], {
reverse: false,
useArraySelector: false,
breakFn: fn(true),
filterFn: fn(false)
})(tree, []).join('\n');
console.log(r);
/* =>
<body>
<div>
<span>
bar
</span>
</div>
<div>
baz
</div>
</body>
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@14.3.1"></script>
免责声明:我是object-scan
的作者