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,解決。

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