我想在javascript中处理一些html代码,以消除所有额外的空白,并将标签和换行符转换为单个空格。这是一个棘手的部分:一些空白是有意义的,有些则不是,并且很难以编程方式告诉哪个是哪个。例如:
<table>
<tr>
<td>hi</td>
</tr>
</table>
在上面的代码中,可以消除所有空格和换行符,因为在tr和td标记之间有一个空格实际上没有意义(即使浏览器可能在那里创建一个文本节点,它也不会改变外观这页纸)。另一方面:
<span>following is a link</span>
<a href="#">here it is</a>
<span>and this is text after the link</span>
这里,结束范围标记和开头“a”标记(等)之间的空白是有意义的 - 没有它,链接周围就没有空格。
有没有一般的方法来处理这个?似乎要求该算法具有一些html结构知识和不同标签的不同特征。
(注意:如果你想知道为什么我在javascript中解析html ....这是一个实验性客户端模板构建器Gizmo - 长篇故事,但请接受我有充分的理由这样做:))
答案 0 :(得分:0)
您可以将所有>\s+<
替换为><
。但这不安全。
想象一下:<span>this</span> <span>text</span>
在打印时会变成thistext
。用一个透明空间替换多个空格的所有出现应该是安全的:
html = html.replace(/>\s+</g,"> <");
答案 1 :(得分:0)
好的,我自己解决了,所以我会把解决方案放在这里。我决定使用DOM而不是html作为字符串,然后我可以抓住innerHTML作为最后一步。代码有点笨重,但想法是:
遍历元素的DOM树,将每个节点的数据保存到数组中(即线性,而不是树)。对于元素节点,在数组中存储“startelem”和“endelem”,相当于开始标记和结束标记。还要记下每个元素的计算“显示”属性(例如内联,块等),并将其放在数组中的两个项目中。 (对于所有节点,我也将深度存储到树中,但似乎我不需要使用它。)
对于文本节点,请注意它是常规文本节点,所有空格还是空字符串。
遍历数组,对于“空白”文本节点,查看数组中的上一个和下一个项目。如果显示其中任何一个:内联,则将节点保留为单个空格。如果不是,请将文本节点更改为空字符串。
之后,对元素执行innerHTML将不会有额外的空格,并且,尽管我可以说,元素的浏览器中的外观将保持不变。
以下是代码:
var stripUnneededTextNodes= function (elem) {
var array = [];
addNodeAndChildrenToArray(elem, 1, array);
for (var i=1; i<array.length-1; i++) {
if (array[i].type == "whitespace") {
if (array[i-1].display == "inline" && array[i+1].display == "inline") {
array[i].node.nodeValue = ' ';
}
else {
array[i].node.nodeValue = '';
array[i].killed = true;
}
delete array[i].node;
}
else if (array[i].type == "text") {
var val = array[i].node.nodeValue;
if (val.charAt(0) == ' ' && array[i-1].display != "inline") {
array[i].node.nodeValue = val = val.substring(1);
}
if (val.charAt(val.length-1) == ' ' && array[i+1].display != "inline") {
array[i].node.nodeValue = val.substring(0, val.length-1);
}
delete array[i].node;
}
}
};
var addNodeAndChildrenToArray = function (node, depth, array) {
switch (node.nodeType) {
case 1: { // ELEMENT_NODE
var display = document.defaultView.getComputedStyle (node, null).display;
array.push ({type: "startelem", tag: node.tagName, display: display, depth: depth});
if (node.childNodes && node.childNodes.length != 0) {
for (var i=0; i<node.childNodes.length; i++)
addNodeAndChildrenToArray(node.childNodes.item(i), depth+1, array);
}
array.push ({type: "endelem", tag: node.tagName, display: display, depth: depth});
}
break;
case 3: { //TEXT_NODE
var newVal = node.nodeValue.replace(/\s+/g, ' ');
node.nodeValue = newVal;
if (newVal == ' ')
array.push ({type: "whitespace", node: node, depth: depth});
else if (newVal == '')
array.push ({type: "emptytext", depth: depth});
else
array.push ({type: "text", node: node, display: "inline", depth: depth});
}
break;
}
};