XML DOM解析详细介绍_JS版

内容:XML文档(内部有DTD),JS文档(方法都写里面),HTML(将XML解析的东西显示到网页上)。

本次实验的全体过程如下:

写一个XML文档,一个JS文档,内含解析方法等,HTML调用JS文档的方法将结果显示到网页上(我的是谷歌)。

因为DOM解析实际上是将XML文档的节点树全部存到内存里,所以我们只需要获得这颗节点树的根节点,那么不管是遍历,修改,增加,删除,实际上和数据结构的树的操作方法是类似的。

先贴XML的文档:

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE 班级 [
<!ELEMENT 班级 (学生+)>
<!ELEMENT 学生 (各科成绩)>
<!ELEMENT 各科成绩 (Course+,Score+)>
<!ELEMENT Course (#PCDATA)>
<!ELEMENT Scor (#PCDATA)>
<!ATTLIST 班级 代号 CDATA #FIXED "软件1400">
<!ATTLIST 学生 name CDATA #REQUIRED>
]>
<班级 代号="软件1401">
<学生 name="阮小二">
<各科成绩>
<Course>计算机基础</Course>
<Score>70</Score>
<Course>C 语言</Course>
<Score>80</Score>
<Course>计算机网络</Course>
<Score>86</Score>
<Course>XML 技术</Course>
<Score>96</Score>
</各科成绩>
</学生>
<学生 name="宋江">
<各科成绩>
<Course>计算机基础</Course>
<Score>76</Score>
<Course>C 语言</Course>
<Score>82</Score>
<Course>计算机网络</Course>
<Score>76</Score>
<Course>XML 技术</Course>
<Score>96</Score>
</各科成绩>
</学生>
</班级>

首先在JS文件里写出解析方法:

function loadXML(address)//XML的解析方法
{
var xmlhttp;
if(window.XMLHttpRequest)//这里的if语句用来判断你浏览器的类型,因为DOM解析对浏览器的兼容性有要求
{
xmlhttp=new XMLHttpRequest();//创建一个XMLHttp对象,非IE浏览器
document.write("xmlhttp is ok");
}
else if(window.ActiveXobject){
xmlhttp = new ActiveXobject("Microsoft.XMLHTTP");//IE浏览器解析器
document.write("ActiveXobject is ok");
}
else
{
document.write("all is done");
}
xmlhttp.open("GET",address,false);//打开XMLHTTP对象,这里要用同步,避免没加载完就往下执行
xmlhttp.send(null);//发送一个 XML HTTP 请求到服务器(服务器一般就是你的浏览器)
return xmlhttp.responseXML;//返回XML DOM对象
}

HTML代码:


xmlDoc来接收XML DOM对象,x来获取我们的XML文件的根节点元素,

结果是:

这里我们的节点树的根节点已经被我们获取到了。x就是了。

我们来遍历一遍:

HTML。把x的子节点集传进去

JS:

function Input(x)
{
for(var i=0;i<x.length;i++)//遍历x节点集
{
var y=x.item(i);//设置y为x序号为i的子节点
while(y!=null&&y.nodeType==3)//排除空白节点
{
y=y.nextSibling;//y等于y的下一个兄弟节点
i++;
}
if(i>=x.length)//判断循环是否结束
break;
document.write(y.nodeName);//输出节点名字
if(y.hasAttributes())//如果有属性,输出属性内容
{
document.write(":"+y.attributes[0].value);
}
if(y.childNodes.length!=1||y.childNodes[0].nodeType!=3)//判断是否是子节点(||y.childNodes[0].nodeType!=3)用于自己增加的节点
{
document.write("</br>")
Input(y.childNodes);//递归
}

else {
document.write(":"+y.childNodes.item(0).nodeValue+"</br>");
}}}

我用了递归的方式遍历,参考树的遍历吧,因为结构一样,所以递归很方便。这里特别要注意的是,XML文档里经常会有空白节点,实际上,空白节点产生的原因是空格,回车,换行,XML没有过滤掉,而是把这些当作一个节点。所以节点树会有许多空白节点。

我过滤空白节点的方法是

while(y!=null&&y.nodeType==3)//排除空白节点
{
y=y.nextSibling;//y等于y的下一个兄弟节点
i++;
}

y!=null这是因为后面遇到的一个问题加上去的,和排除空白节点无关。

空白节点的类型是3(TextNode),所以直接判断过滤就好了。

结果是

会了遍历,其他就很简单了。

查找:可以用getElementsByTagName("");

比如查找学生,可以用x.getElementsByTagName("学生");这个方法的返回值是学生的节点集,有2个,阮小二和宋江。

事实上x可以是任何你要查找的节点的父节点。上例中用xmlDoc查找也行。

查找再加遍历也简单,直接将查找到的节点集中你想遍历 的那个节点的子节点集传进Input这个递归方法里就行了。

删除,先查找到这个节点,比如q是你确定好的节点,q.parentNode.removeChild(q);就可以将q这个节点包括以它为父节点的节点树都删除。

这里特别说下增加节点:

function Inser(x)
{
newxml = xmlDoc.createElement("学生");//创建一个名称为学生的节点
newxml.setAttribute("name","武松");//将节点的属性设置为name,值为武松
newGKCJ = xmlDoc.createElement("各科成绩");//创建一个名为各科成绩的节点
for(i=0;i<8;i++)
{
var newEle;
if(i%2==0)
{
newEle = xmlDoc.createElement(Course);//创建课程节点
newEle.appendChild(xmlDoc.createTextNode(Class[i/2]));//将课程节点的值(文本节点)加入到课程节点中
}
else
{
newEle = xmlDoc.createElement(Score);//同上
newEle.appendChild(xmlDoc.createTextNode(grade));
}
newGKCJ.appendChild(newEle);//将课程节点或者分数节点加入到各科成绩节点中
}
newxml.appendChild(newGKCJ);//将各科成绩节点加入到学生节点中
x.appendChild(newxml); //将学生节点加入到根节点中

}

我们用代码加入的节点树是没有空白节点的!

这里我遇到的一个问题是我的递归函数是用来递归那些存在空白节点的节点树,而这颗新增加进去的没有空白节点,就出错,而且挺莫名其妙的。

所以我在Input(x)函数里的删除空白节点循环里加了一条y!=null,在递归判断力加了一条y.childNodes[0].nodeType!=3。

如果y.childNodes[0].nodeType!=3这条没有,出现以下情况


原因:武松这个节点下面的子节点只有<各科成绩>,所以长度为1,没有进入到递归中,<各科成绩>节点我们创建的时候没有值,所以为null。而前面的学生节点因为有空白节点,所以长度都大于1,为3(回车两个,字节点1个)。

如果没有y!=null,直接报错,


跟在!=null后面的y.nodeType报错,因为有y=null。

虽然解决了问题,不过原因我还是不清楚。。




PS:遇到的其他问题。

1:如果直接把HTML文件拖到浏览器里打开是解析不出XML文件的,似乎是因为浏览器内部的解析器原因,网上也没什么好办法。我的解决方式是自己用Tomcat部署一个服务器打开就好了。

2:XML中的中文解析到网页上是乱码。我将浏览器的编码方式,XML的编码方式,HTML的编码格式都改成了UTF-8,解决。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章