处理xml(html)中的空格
xml文档(包括html)是从一个独立的根结点开始,它包含指向子节点的指针。每一个子节点都包含指针指向它的父节点、相邻节点和子节点。标准dom中,dom指针不仅可以指向元素,也可以指向文本节点。 请看以下html代码:
<h1>DOM简介</h1>
<p id="test">DOM是一个表达XML文档的标准</p>
<p>你随处可见dom的身影</p>
</body>
我想获得id为test的p元素的下一个p元素,可能理所当然的认为用document.getElementById('test').nextSibling就能获得。其实不然。在ie中确实能够获得你想要的,而在firefox、Opera9和Safari中你只能获得一个空格。《精通javascript》上提供了一个函数,用于处理xm中的这些空格,其作用原理就是找出文本节点,并删除这些节点,以达到删除这些空格的目的。
//如果不提供参数,则处理整个HTML文档
element = element || document;
//使用第一个子节点作为开始指针
var cur = element.firstChild;
//一直到没有子节点为止
while (cur != null){
//如果节点为文本节点,应且包含空格
if ( cur.nodeType == && ! /\S/.test(cur.nodeValue)){
//删除这个文本节点
element.removeChild( cur );
//否则,它就是一个元素
} else if (cur.nodeType == 1){
//递归整个文档
cleanWhitespace( cur );
}
cur = cur.nextSibling;//遍历子节点
}
}
正如书中作者所提到的,该函数的缺点是必须遍历每个DOM元素和文本节点,会严重降低网站的加载速度。每一次为文档注入新的html,都需要重新扫描dom中的新内容,确保没有增加新的有空格填充的文本节点。
在这里,不妨做一个简单的判断,如果id为test的p元素的下一个节点是文本节点(即nodeType为3)的话,就继续往下遍历。如果是元素节点的话,则不需要往下遍历。代码如下:
var reason = testP.nextSibling;
if(reason.nodeType == 1){
alert(reason.innerHTML);
} else if(reason.nodeType == 3){
alert(reason.nextSibling.innerHTML);
}
}
对非IE浏览器,可以用常量来表明不同的DOM节点类型。document.ELEMENT_NODE、document.TEXT_NODE、document.DOCUMENT_NODE代表元素节点、文本节点、文档节点。
最后,利用数组写了一个函数,能够有效的处理dom中的空格,其原理就是将一个元素的的父元素找出来,然后通过它父元素的childNodes属性找出该元素的所有兄弟元素。遍历该元素和它的兄弟元素,将所有元素节点放在一个数组里。这样调用这个数组,就只有元素节点而没有文本节点,也就没有了讨厌的空格。
该函数如下:
var elem = elem || document;
var parentElem = elem.parentNode;
var childElem = parentElem.childNodes;
var childElemArray = new Array;
for (var i=0; i<childElem.length; i++){
if (childElem[i].nodeType==1){
childElemArray.push(childElem[i]);
}
}
return childElemArray;
}
最后完整的一个示例如下:
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>DOMWhitespace</title>
<script type="text/javascript">
window.onload = function(){
var testP = document.getElementById('test');
cleanWhitespaces(testP);
alert(testP.innerHTML);
}
function cleanWhitespaces(elem){
var elem = elem || document;
var parentElem = elem.parentNode;
var childElem = parentElem.childNodes;
var childElemArray = new Array;
for (var i=0; i<childElem.length; i++){
if (childElem[i].nodeType==1){
childElemArray.push(childElem[i]);
}
}
return childElemArray;
}
</script>
</head>
<body>
<h1>DOM简介</h1>
<p id="test">dom的广泛使用是有道理的,以下是一些原因:</p>
<p>你随处可见dom的身影</p>
<ul>
<li><a href="" title="">link1</a></li>
<li><a href="" title="">link2</a></li>
</ul>
</body>
</html>
var loopIndex;
for (loopIndex = 0; loopIndex < xml.childNodes.length; loopIndex++){
var currentNode = xml.childNodes[loopIndex];
if (currentNode.nodeType == 1){
removeWhitespace(currentNode);
}
if (((/^\s+$/.test(currentNode.nodeValue))) &&(currentNode.nodeType == 3)){
xml.removeChild(xml.childNodes[loopIndex--]);
}
}
}
原理是对元素的所有的子节点做一个遍历。然后做一个判断,如果是子元素节点(nodeType = 1),则遍历该子元素的所有的子节点,用递归检查是否包含空白节点;如果处理的子节点是文本节点(nodeType = 3),则检查是否是纯粹的空白节点,如果是,就将它从xml对象中删除。
这个函数,应该和上面我自己写的函数作用和使用方法基本一样。非常不错的函数。
本博文发布3天后,我在《ajax宝典》上又看到了一个用于处理xml中空格的好函数。原理还是一样的,代码如下: