javascript用DOM解释XML

  JAVASCRIPT中使用DOM操作XML文档

<script language="JavaScript">
<!--
var doc = new ActiveXObject("Msxml2.DOMDocument"); //ie5.5+,CreateObject("Microsoft.XMLDOM")


//加载文档
//doc.load("b.xml");

//创建文件头
var p = doc.createProcessingInstruction("xml","version='1.0'  encoding='gb2312'");

    //添加文件头
    doc.appendChild(p);

//用于直接加载时获得根接点
//var root = doc.documentElement;

//两种方式创建根接点
//    var root = doc.createElement("students");
    var root = doc.createNode(1,"students","");

    //创建子接点
    var n = doc.createNode(1,"ttyp","");

        //指定子接点文本
        //n.text = " this is a test";
   
    //创建孙接点
    var o = doc.createElement("sex");
        o.text = "男";    //指定其文本

    //创建属性
    var r = doc.createAttribute("id");
        r.value="test";

        //添加属性
        n.setAttributeNode(r);

    //创建第二个属性   
    var r1 = doc.createAttribute("class");
        r1.value="tt";
       
        //添加属性
        n.setAttributeNode(r1);

        //删除第二个属性
        n.removeAttribute("class");

        //添加孙接点
        n.appendChild(o);

        //添加文本接点
        n.appendChild(doc.createTextNode("this is a text node."));

        //添加注释
        n.appendChild(doc.createComment("this is a comment/n"));
   
        //添加子接点
        root.appendChild(n);
   
    //复制接点
    var m = n.cloneNode(true);

        root.appendChild(m);
       
        //删除接点
        root.removeChild(root.childNodes(0));

    //创建数据段
    var c = doc.createCDATASection("this is a cdata");
        c.text = "hi,cdata";
        //添加数据段
        root.appendChild(c);
   
    //添加根接点
    doc.appendChild(root);

    //查找接点
    var a = doc.getElementsByTagName("ttyp");
    //var a = doc.selectNodes("//ttyp");

    //显示改接点的属性
    for(var i= 0;i<a.length;i++)
    {
        alert(a[i].xml);
        for(var j=0;j<a[i].attributes.length;j++)
        {
            alert(a[i].attributes[j].name);
        }
    }

    //修改节点,利用XPATH定位节点
    var b = doc.selectSingleNode("//ttyp/sex");
    b.text = "女";

    //alert(doc.xml);

    //XML保存(需要在服务端,客户端用FSO)
    //doc.save();
   
    //查看根接点XML
    if(n)
    {
        alert(n.ownerDocument.xml);
    }

//-->
</script>


    在DOM眼中,HTML跟XML一样是一种树形结构的文档,<html>是根(root)节点,<head>、<title>、<body>是<html>的子(children)节点,互相之间是兄弟(sibling)节点;<body>下面才是子节点<table>、<span>、<p>等等。如下图:

    这个是不是跟XML的结构有点相似呢。不同的是,HTML文档的树形主要包含表示元素、标记的节点和表示文本串的节点。


 HTML文档的节点

DOM下,HTML文档各个节点被视为各种类型的Node对象。每个Node对象都有自己的属性和方法,利用这些属性和方法可以遍历整个文档树。由于HTML文档的复杂性,DOM定义了nodeType来表示节点的类型。这里列出Node常用的几种节点类型:

接口
 nodeType常量
 nodeType值
 备注
 
Element
 Node.ELEMENT_NODE
 1
 元素节点
 
Text
 Node.TEXT_NODE
 3
 文本节点
 
Document
 Node.DOCUMENT_NODE
 9
 document
 
Comment
 Node.COMMENT_NODE
 8
 注释的文本
 
DocumentFragment
 Node.DOCUMENT_FRAGMENT_NODE
 11
 document片断
 
Attr
 Node.ATTRIBUTE_NODE
 2
 节点属性
 


DOM树的根节点是个Document对象,该对象的documentElement属性引用表示文档根元素的Element对象(对于HTML文档,这个就是<html>标记)。Javascript操作HTML文档的时候,document即指向整个文档,<body>、<table>等节点类型即为Element。Comment类型的节点则是指文档的注释。具体节点类型的含义,请参考《Javascript权威指南》,在此不赘述。

Document定义的方法大多数是生产型方法,主要用于创建可以插入文档中的各种类型的节点。常用的Document方法有:

方法
 描述
 
createAttribute()
 用指定的名字创建新的Attr节点。
 
createComment()
 用指定的字符串创建新的Comment节点。
 
createElement()
 用指定的标记名创建新的Element节点。
 
createTextNode()
 用指定的文本创建新的TextNode节点。
 
getElementById()
 返回文档中具有指定id属性的Element节点。
 
getElementsByTagName()
 返回文档中具有指定标记名的所有Element节点。
 


对于Element节点,可以通过调用getAttribute()、setAttribute()、removeAttribute()方法来查询、设置或者删除一个Element节点的性质,比如<table>标记的border属性。下面列出Element常用的属性:

属性
 描述
 
tagName
 元素的标记名称,比如<p>元素为P。HTML文档返回的tabName均为大写。
 


Element常用的方法:

方法
 描述
 
getAttribute()
 以字符串形式返回指定属性的值。
 
getAttributeNode()
 以Attr节点的形式返回指定属性的值。
 
getElementsByTabName()
 返回一个Node数组,包含具有指定标记名的所有Element节点的子孙节点,其顺序为在文档中出现的顺序。
 
hasAttribute()
 如果该元素具有指定名字的属性,则返回true。
 
removeAttribute()
 从元素中删除指定的属性。
 
removeAttributeNode()
 从元素的属性列表中删除指定的Attr节点。
 
setAttribute()
 把指定的属性设置为指定的字符串值,如果该属性不存在则添加一个新属性。
 
setAttributeNode()
 把指定的Attr节点添加到该元素的属性列表中。
 


Attr对象代表文档元素的属性,有name、value等属性,可以通过Node接口的attributes属性或者调用Element接口的getAttributeNode()方法来获取。不过,在大多数情况下,使用Element元素属性的最简单方法是getAttribute()和setAttribute()两个方法,而不是Attr对象。


使用DOM操作HTML文档


Node对象定义了一系列属性和方法,来方便遍历整个文档。用parentNode属性和childNodes[]数组可以在文档树中上下移动;通过遍历childNodes[]数组或者使用firstChild和nextSibling属性进行循环操作,也可以使用lastChild和previousSibling进行逆向循环操作,也可以枚举指定节点的子节点。而调用appendChild()、insertBefore()、removeChild()、replaceChild()方法可以改变一个节点的子节点从而改变文档树。

需要指出的是,childNodes[]的值实际上是一个NodeList对象。因此,可以通过遍历childNodes[]数组的每个元素,来枚举一个给定节点的所有子节点;通过递归,可以枚举树中的所有节点。下表列出了Node对象的一些常用属性和方法:

Node对象常用属性:

属性
 描述
 
attributes
 如果该节点是一个Element,则以NamedNodeMap形式返回该元素的属性。
 
childNodes
 以Node[]的形式存放当前节点的子节点。如果没有子节点,则返回空数组。
 
firstChild
 以Node的形式返回当前节点的第一个子节点。如果没有子节点,则为null。
 
lastChild
 以Node的形式返回当前节点的最后一个子节点。如果没有子节点,则为null。
 
nextSibling
 以Node的形式返回当前节点的兄弟下一个节点。如果没有这样的节点,则返回null。
 
nodeName
 节点的名字,Element节点则代表Element的标记名称。
 
nodeType
 代表节点的类型。
 
parentNode
 以Node的形式返回当前节点的父节点。如果没有父节点,则为null。
 
previousSibling
 以Node的形式返回紧挨当前节点、位于它之前的兄弟节点。如果没有这样的节点,则返回null。
 


Node对象常用方法:

方法
 描述
 
appendChild()
 通过把一个节点增加到当前节点的childNodes[]组,给文档树增加节点。
 
cloneNode()
 复制当前节点,或者复制当前节点以及它的所有子孙节点。
 
hasChildNodes()
 如果当前节点拥有子节点,则将返回true。
 
insertBefore()
 给文档树插入一个节点,位置在当前节点的指定子节点之前。如果该节点已经存在,则删除之再插入到它的位置。
 
removeChild()
 从文档树中删除并返回指定的子节点。
 
replaceChild()
 从文档树中删除并返回指定的子节点,用另一个节点替换它。
 


接下来,让我们使用上述的DOM应用编程接口,来试着操作HTML文档。


A、遍历文档的节点

DOM把一个HTML文档视为树,因此,遍历整个树是应该是家常便饭。跟之前说过的一样,这里我们提供两个遍历树的例子。通过它,我们能够学会如何使用childNodes[]和firstChile、lastChild、nextSibling、previousSibling遍历整棵树。

例子1-- sample3_1.htm:

这个例子使用了childNodes[]和递归方式来遍历整个文档,统计文档中出现的Element元素总数,并把Element标记名全部打印出来。需要特别注意的是,在使用DOM时,必须等文档被装载完毕再执行遍历等行为操作文档。sample3_1.htm具体代码如下:

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>无标题文档</title>

<script language="javascript">

var elementName = ""; //全局变量,保存Element标记名,使用完毕要清空

function countTotalElement(node) { //参数node是一个Node对象

       var total = 0;

       if(node.nodeType == 1) { //检查node是否为Element对象

              total++;                 //如果是,计数器加1

              elementName = elementName + node.tagName + "/r/n"; //保存标记名

       }

       var childrens = node.childNodes;         //获取node的全部子节点

       for(var i=0;i<childrens.length;i++) {

              total += countTotalElement(childrens[i]); //在每个子节点上进行递归操作

       }

       return total;

}

</script>

</head>

<body>

<a href="javascript:void(0)"

onClick="alert('标记总数:' + countTotalElement(document) + '/r/n全部标记如下:/r/n' + elementName);elementName='';">开始统计</a>

</body>

</html>

运行效果如下:

               

例子2 – sample3_2.htm:

接下来使用firstChile、lastChild、nextSibling、previousSibling遍历整个文档树。修改一下countTotalElement函数,其他跟sample3_1.htm一样:

function countTotalElement(node) { //参数node是一个Node对象

       var total = 0;

       if(node.nodeType == 1) { //检查node是否为Element对象

              total++;                 //如果是,计数器加1

              elementName = elementName + node.tagName + "/r/n"; //保存标记名

       }

       var childrens = node.childNodes;         //获取node的全部子节点

       for(var m=node.firstChild; m!=null;m=m.nextSibling) {

              total += countTotalElement(m); //在每个子节点上进行递归操作

       }

       return total;

}

B、搜索文档中特定的元素

在使用DOM的过程中,有时候需要定位到文档中的某个特定节点,或者具有特定类型的节点列表。这种情况下,可以调用Document对象的getElementsByTagName()和getElementById()方法来实现。

document.getElementsByTagName()返回文档中具有指定标记名的全部Element节点数组(也是NodeList类型)。Element出现在数组中的顺序就是他们在文档中出现的顺序。传递给getElementsByTagName()的参数忽略大小写。比如,想定位到第一个<table>标记,可以这样写:document.getElementsByTagName(“table”)[0]。例外的,可以使用document.body定位到<body>标记,因为它是唯一的。

getElementsByTagName()返回的数组取决于文档。一旦文档改变,返回结果也立即改变。相比,getElementById()则比较灵活,可以随时定位到目标,只是要实现给目标元素一个唯一的id属性值。这个我们在《AJAX开发简略》的“级联菜单”例子中已经使用过了。

Element对象也支持getElementsByTagName()和getElementById()。不同的是,搜索领域只针对调用者的子节点。

C、修改文档内容

遍历整棵文档树、搜索特定的节点,我们最终目的之一是要修改文档内容。接下来的三个例子将使用Node的几个常用方法,来演示如何修改文档内容。

例子3 -- sample4_1.htm:

这个例子包含三个文本节点和一个按钮。点击按钮后,三个文本节点和按钮的顺序将被颠倒。程序使用了Node的appendChild()和removeChild()方法。

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>无标题文档</title>

<script language="javascript">

       function reverseNode(node) { // 颠倒节点node的顺序

              var kids = node.childNodes; //获取子节点列表

              var kidsNum = kids.length; //统计子节点总数

              for(var i=kidsNum-1;i>=0;i--) { //逆向遍历子节点列表

                     var c = node.removeChild(kids[i]); //删除指定子节点,保存在c中

                     node.appendChild(c); //将c放在新位置上

              }

       }

</script>

</head>

<body>

<p>第一行</p>

<p>第二行</p>

<p>第三行</p>

<p><input type="button" name="reverseGo" value="颠倒"

onClick="reverseNode(document.body)"></p>

</body>

</html>

             

例子4-- sample4_2.htm:

例子1通过直接操作body的子节点来修改文档。在HTML文档中,布局和定位常常通过表格<table>来实现。因此,例子4将演示操作表格内容,将表格的四个单元行顺序颠倒。如果没有使用<tbody>标签,则<table>把全部的<tr>当做是属于一个子节点<tbody>,所以我们采用数组缓存的方式,把行数据颠倒一下。这个例子同时也演示了如何使用DOM创建表格单元行。

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>无标题文档</title>

<script language="javascript">

function reverseTable() {

       var node = document.getElementsByTagName("table")[0]; //第一个表格

       var child = node.getElementsByTagName("tr"); //取得表格内的所有行

       var newChild = new Array(); //定义缓存数组,保存行内容

       for(var i=0;i<child.length;i++) {

              newChild[i] = child[i].firstChild.innerHTML;

       }

       node.removeChild(node.childNodes[0]); //删除全部单元行

       var header = node.createTHead(); //新建表格行头

       for(var i=0;i<newChild.length;i++) {

              var headerrow = header.insertRow(i); //插入一个单元行

              var cell = headerrow.insertCell(0); //在单元行中插入一个单元格

              //在单元格中创建TextNode节点

              cell.appendChild(document.createTextNode(newChild[newChild.length-i-1]));

       }

}

</script>

</head>

<body>

<table width="200" border="1" cellpadding="4" cellspacing="0">

    <tr>

        <td height="25">第一行</td>

    </tr>

    <tr>

        <td height="25">第二行</td>

    </tr>

    <tr>

        <td height="25">第三行</td>

    </tr>

    <tr>

        <td height="25">第四行</td>

    </tr>

</table>

<br>

<input type="button" name="reverse" value="开始颠倒" onClick="reverseTable()">

</body>

</html>

    

例子5 -- sample4_3.htm:

正如我们在Node节点介绍部分所指出的那样,appendChild()、replaceChild()、removeChild()、insertBefore()方法会立即改变文档的结构。下面的例子包含两个表格,我们试着把表格二的内容替换表格一的内容。

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>无标题文档</title>

<script language="javascript">

function replaceContent() {

       var table1 = document.getElementsByTagName("table")[0];

       var table2 = document.getElementsByTagName("table")[1];

       var kid1 = table1.firstChild.firstChild.firstChild; //定位到<td>节点

       var kid2 = table2.firstChild.firstChild.firstChild; //定位到<td>节点

       var repKid = kid2.firstChild; //定位到表格二<td>内含的TextNode节点

       try {

              //用表格二的单元格内容替换表格一的单元格内容,表格二变成没有单元格内容

              kid1.replaceChild(repKid,kid1.firstChild);

              //下面注释如果开放,将出现object error,因为表格二已经被改变

              //kid2.replaceChild(kid1.firstChild,kid2.firstChild);

       }catch(e){

              alert(e);

       }

}

</script>

</head>

<body>

<table width="200" border="1" cellspacing="0" cellpadding="0">

<tbody>

    <tr>

        <td>表格一</td>

    </tr>

</tbody>

</table>

<br>

<table width="200" border="1" cellspacing="0" cellpadding="0">

<tbody>

    <tr>

        <td>表格二</td>

    </tr>

</tbody>

</table>

<br>

<input type="button" name="replaceNode" value="替换" onClick="replaceContent()">

</body>

</html>

    

注意,当执行kid1.replaceChild(repKid,kid1.firstChild);的时候,table2的子节点已经被转移到table1了,table2已经没有子节点,不能再调用table2的子节点。看看代码的注释,试着运行一下,应该就知道文档是怎么改变的了。

D、往文档添加新内容

在学会遍历、搜索、修改文档之后,我们现在试着网文档添加新的内容。其实没有什么新意,只是利用我们上述提到的Node的属性和方法而已,还是操作<table>标记的内容。有新意的是,我们要实现一个留言簿。是的,留言簿,你可以往里面留言,只是不能刷新噢。

例子6 – sample5_1.htm:

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>无标题文档</title>

<script language="javascript">

function insertStr() {

       var f = document.form1;

       var value = f.str.value;

       if(value!="") {

              // 从最终的TextNode节点开始,慢慢形成<tbody>结构

              var text = document.createTextNode(value); //新建一个TextNode节点

              var td = document.createElement("td"); //新建一个td类型的Element节点

              var tr = document.createElement("tr"); //新建一个tr类型的Element节点

              var tbody = document.createElement("tbody"); //新建一个tbody类型的Element节点

              td.appendChild(text); //将节点text加入td中

              tr.appendChild(td); //将节点td加入tr中

              tbody.appendChild(tr); //将节点tr加入tbody中

              var parNode = document.getElementById("table1"); //定位到table上

              parNode.insertBefore(tbody,parNode.firstChild); //将节点tbody插入到节点顶部

              //parNode.appendChild(tbody); //将节点tbody加入节点尾部

       }

}

</script>

</head>

<body>

<form name="form1" method="post" action="">

    <input name="str" type="text" id="str" value="">

    <input name="insert" type="button" id="insert" value="留言" onClick="insertStr()">

</form>

<table width="400" border="1" cellspacing="0" cellpadding="0" id="table1">

<tbody>

    <tr>

        <td height="25">网友留言列表:</td>

    </tr>

</tbody>

</table>

</body>

</html>

我们之前说过,<table>的子节点是<tbody>,<tbody>的子节点才是<tr>,<tr>是<td>的父节点,最后<td>内部的TextNode节点。所以,往<table>增加单元格行要逐级形成,就像往树里面添加一个枝桠一样,要有叶子有径。看看,这个留言簿是不是很简单啊。这个例子同时也演示了往<table>表格标记里面增加内容的另一种方法。

 

E使用DOM操作XML文档

在数据表示方面,XML文档更加结构化。DOM在支持HTML的基础上提供了一系列的API,支持针对XML的访问和操作。利用这些API,我们可以从XML中提取信息,动态的创建这些信息的HTML呈现文档。处理XML文档,通常遵循“加载XML文档à提取信息à加工信息à创建HTML文档”的过程。下面的例子演示了如何加载并处理XML文档。

这个例子包含两个JS函数。loadXML()负责加载XML文档,其中既包含加载XML文档的2级DOM代码,又有实现同样操作的Microsoft专有API代码。需要提醒注意的是,文档加载过程不是瞬间完成的,所以对loadXML()的调用将在加载文档完成之前返回。因此,需要传递给loadXML()一个引用,以便文档加载完成后调用。

例子中的另外一个函数makeTable(),则在XML文档加载完毕之后,使用最后前介绍过的DOM应用编程接口读取XML文档信息,并利用这些信息形成一个新的table表格。

例子7 -- sample6_1.htm:

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>无标题文档</title>

<script language="javascript">

function loadXML(handler) {

       var url = "employees.xml";

       if(document.implementation&&document.implementation.createDocument) {

              var xmldoc = document.implementation.createDocument("", "", null);

              xmldoc.onload =  handler(xmldoc, url);

              xmldoc.load(url);

       }

       else if(window.ActiveXObject) {

              var xmldoc = new ActiveXObject("Microsoft.XMLDOM");

              xmldoc.onreadystatechange = function() {

                     if(xmldoc.readyState == 4) handler(xmldoc, url);

              }

              xmldoc.load(url);

       }

}

function makeTable(xmldoc, url) {

       var table = document.createElement("table");

       table.setAttribute("border","1");

       table.setAttribute("width","600");

       table.setAttribute("class","tab-content");

       document.body.appendChild(table);

       var caption = "Employee Data from " + url;

       table.createCaption().appendChild(document.createTextNode(caption));

       var header = table.createTHead();

       var headerrow = header.insertRow(0);

       headerrow.insertCell(0).appendChild(document.createTextNode("姓名"));

       headerrow.insertCell(1).appendChild(document.createTextNode("职业"));

       headerrow.insertCell(2).appendChild(document.createTextNode("工资"));

       var employees = xmldoc.getElementsByTagName("employee");

       for(var i=0;i<employees.length;i++) {

              var e = employees[i];

              var name = e.getAttribute("name");

              var job = e.getElementsByTagName("job")[0].firstChild.data;

              var salary = e.getElementsByTagName("salary")[0].firstChild.data;

              var row = table.insertRow(i+1);

              row.insertCell(0).appendChild(document.createTextNode(name));

              row.insertCell(1).appendChild(document.createTextNode(job));

              row.insertCell(2).appendChild(document.createTextNode(salary));

       }

}

</script>

<link href="css/style.css" rel="stylesheet" type="text/css">

</head>

 

<body onLoad="loadXML(makeTable)">

</body>

</html>

供读取调用的XML文档 – employees.xml:

<?xml version="1.0" encoding="gb2312"?>

<employees>

       <employee name="J.Doe">

              <job>Programmer</job>

              <salary>32768</salary>

       </employee>

       <employee name="A.Baker">

              <job>Sales</job>

              <salary>70000</salary>

       </employee>

       <employee name="Big Cheese">

              <job>CEO</job>

              <salary>100000</salary>

       </employee>

</employees>

 


处理XML文档

脱离XML文档的AJAX是不完整的。在本部分未完成之前,有读者说AJAX改名叫AJAH(H应该代表HTML吧)比较合适。应该承认,XML文档在数据的结构化表示以及接口对接上有先天的优势,但也不是所有的数据都应该用XML表示。有些时候单纯的文本表示可能会更合适。下面先举个AJAX处理返回XML文档的例子再讨论什么时候使用XML。

7.5.1、处理返回的XML

例子8 -- sample7_1.htm:

在这个例子中,我们采用之前确定的AJAX开发框架,稍微修改一下body内容和processRequest的相应方式,将先前的employees.xml的内容读取出来并显示。

body的内容如下:

<input type="button" name="read"

 value="读取XML" onClick="send_request('employees.xml')">

processRequest()方法修改如下:

       // 处理返回信息的函数

    function processRequest() {

        if (http_request.readyState == 4) { // 判断对象状态

            if (http_request.status == 200) { // 信息已经成功返回,开始处理信息

                            var returnObj = http_request.responseXML;

                            var xmlobj = http_request.responseXML;

                            var employees = xmlobj.getElementsByTagName("employee");

                            var feedbackStr = "";

                            for(var i=0;i<employees.length;i++) { // 循环读取employees.xml的内容

                                   var employee = employees[i];

                                   feedbackStr += "员工:" + employee.getAttribute("name");

                                   feedbackStr +=

" 职位:" + employee.getElementsByTagName("job")[0].firstChild.data;

                                   feedbackStr +=

 " 工资:" + employee.getElementsByTagName("salary")[0].firstChild.data;

                                   feedbackStr +=  "/r/n";

                            }

                            alert(feedbackStr);

            } else { //页面不正常

                alert("您所请求的页面有异常。");

            }

        }

}

运行一下,看来效果还不错:

 


7.5.2、选择合适的XML生成方式

现在的web应用程序往往采用了MVC三层剥离的设计方式。XML作为一种数据保存、呈现、交互的文档,其数据往往是动态生成的,通常由JavaBean转换过来。由JavaBean转换成XML文档的方式有好几种,选择合适的转换方式往往能达到事半功倍的效果。下面介绍两种常用的方式,以便需要的时候根据情况取舍。

A、类自行序列化成XML

类自行序列化成XML即每个类都实现自己的toXML()方法,选择合适的API、适当的XML结构、尽量便捷的生成逻辑快速生成相应的XML文档。显然,这种方式必须要求每个类编写专门的XML生成代码,每个类只能调用自己的toXML()方法。应用诸如JDOM等一些现成的API,可以减少不少开发投入。例子9是一个利用JDOM的API形成的toXML()方法。

例子9 -- toXml() 的 JDOM 实现 -- Employ类的toXml()方法:

public Element toXml() { 

       Element employee = new Element(“employee”);

       Employee.setAttribute(“name”,name);

       Element jobE = new Element(“job”).addContent(job);

       employee.setContent(jobE);

       Element salaryE = new Element(“salary”).addContent(salary);

       employee.setContent(salaryE);

       return employee;

}

JDOM提供了现成的API,使得序列化成XML的工作更加简单,我们只需要把toXML()外面包装一个Document,然后使用XMLOutputter把文档写入servlet就可以了。toXml()允许递归调用其子类的toXML()方法,以便生成包含子图的XML文档。

       使用类自行序列化成XML的方式,要每个类都实现自己的toXML()方法,而且存在数据模型与视图耦合的问题,即要么为每个可能的视图编写独立的toXML()方法,要么心甘情愿接收冗余的数据,一旦数据结构或者文档发生改变,toXML()就要做必要的修改。

B、页面模板生成XML方式

一般的,可以采用通用的页面模板技术来生成XML文档,这个XML文档可以符合任何需要的数据模型,供AJAX灵活的调用。另外,模板可以采用任何标记语言编写,提高工作效率。下面是一个采用Struts标签库编写的XML文档,输出之前提到的employees.xml:

Sample8_2.jsp:

<%@ page contentType="application/xml; charset=gb2312" import="Employee"%>

<%@ page import="java.util.Collection,java.util.ArrayList"%>

<?xml version="1.0"?>

<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>

<%

Employee em1 = new Employee();

em1.setName("J.Doe");

em1.setJob("Programmer");

em1.setSalary("32768");

Employee em2 = new Employee();

em2.setName("A.Baker");

em2.setJob("Sales");

em2.setSalary("70000");

Employee em3 = new Employee();

em3.setName("Big Cheese");

em3.setJob("CEO");

em3.setSalary("100000");

Collection employees = new ArrayList();

employees.add(em1);

employees.add(em2);

employees.add(em3);

pageContext.setAttribute("employees",employees);

%>

<employees>

<logic:iterate name="employees" id="employee">

       <employee name="<bean:write name='employee' property='name'/>">

              <job><bean:write name="employee" property="job"/></job>

              <salary><bean:write name="employee" property="salary"/></salary>

       </employee>

</logic:iterate>

</employees>

 

采用页面模板生成XML方式,需要为每个需要的的数据模型建立一个对立的JSP文件,用来生成符合规范的XML文档,而不能仅仅在类的toXML()方法中组织对象图来实现。不过,倒是可以更加方便的确保标记匹配、元素和属性的顺序正确以及XML实体正确转义。

参考资料中Philip McCarthy的文章还描述了一种Javascript对象标注的生成方式,本文在此不赘述。有兴趣的读者可以自行查看了解。

7.5.3、如何在使用XML还是普通文本间权衡

使用XML文档确实有其方便之处。不过XML文档的某些问题倒是要考虑一下,比如说延迟,即服务器不能立即解析XML文档成为DOM模型。这个问题在一定程度上会影响AJAX要求的快速反应能力。另外,某些情况下我们并不需要使用XML来表示数据,比如说数据足够简单成只有一个字符串而已。就好像我们之前提到的数据校验和级联菜单的例子一样。所以,个人认为在下面这些情况下可以考虑使用XML来作为数据表示的介质:

l         数据比较复杂,需要用XML的结构化方式来表示

l         不用考虑带宽和处理效率支出

l         与系统其他API或者其他系统交互,作为一种数据中转中介

l         需要特定各式的输出视图而文本无法表示的

总之,要认真评估两种表示方式的表示成本和效率,选择合适的合理的表示方式。

在关于AJAX的系列文章的下一篇,我们将综合使用DOM和XML,来实现一个可以持久化的简单留言簿。另外,还将试着模拟MSN Space的部分功能,来体会AJAX的魅力

posted on 2006-01-03 01:18 湘子 阅读(420) 评论(0)  编辑 收藏 收藏至365Key 所属分类: XML摸索 、JavaScript

 
  
标题  请输入标题
姓名  请输入你的姓名
主页  
请输入验证码 
验证码 *  
 
内容(提交失败后,可以通过“恢复上次提交”恢复刚刚提交的内容) 请输入评论内容
 
 
Remember Me?
    登录  使用高级评论  新用户注册  返回页首  恢复上次提交       
[使用Ctrl+Enter键可以直接提交]
 
 
导航博客园 首页 新随笔 联系 聚合 管理 统计随笔 - 43 文章 - 20 评论 - 43 引用 - 0 公告人所拥有的「最后的」(last)自由是,
我们可以选择我们的态度。
遭遇同样的打击,
有的人选择的是绝望,
有的人却选择了希望

 

 


收听金鹰955广播WEB版
金鹰955在线收听

 
留言簿给我留言 查看公开留言 查看私人留言 我参与的团队Skin设计小组 (0/21) 最新随笔1. [转] C#下 读取xml节点的数据总结 2. 关闭浏览器窗口或离开页面时 3. javascript 的面向对象特性参考 4. 自己写的一个转换js中转换XML格式的函数 5. JAVASCRIPT中使用DOM操作XML文档 6. 尝试创建web项目或打开URL (Http/1.0 500 Server Error) 7. 优化JavaScript脚本的性能 8. XML数据岛,数据绑定 9. 数据库查询性能优化(合理使用索引|避免或简化排序|避免对大型表进行全表顺序扫描|避免使用相关的子查询|避免使用通配符匹配 ) 10. 在JavaScript的数组中进行数组元素查找和替换 随笔分类AJAX技术 (0) (rss) DotNet (7) (rss) JavaScript (13) (rss) SKIN之路 (6) (rss) Sql Server (1) (rss) XML摸索 (10) (rss) 心路思语 (1) (rss) 正则表达式 (2) (rss) 文章分类程序人生 (1) (rss) 读书生活 (1) (rss) 权限系统控制 (12) (rss) 软件测试 (0) (rss) 职场天地 (1) (rss) 相册SKIN用图 (32) 爱晚红枫会员 (4) 博客用图 (9) 私人照片 (18) 收藏夹AJAX开发 (2) (rss) DOTNET (4) (rss) JavaScript (4) (rss) ORACLE (1) (rss) SQL技术 (2) (rss) Webservice (1) (rss) 創建柱狀圖和餅圖 (4) (rss) 权限系统 (7) (rss) 日志管理 (1) (rss) 设计模式 (3) (rss) 业界前瞻 (2) (rss) 在.NET中操作XML (4) (rss) 正则表达式 (3) (rss) Web标准网页设计师 (rss) 一个不错的网站,学习XHTML+CSS Web开发asp.net初学者 CSDN Web开发版 NewWebPick.com 中国DotNet俱乐部 xml学习XML DOM XML学习的好地方  博客集合MSN上的Blog
MSN上的Blog,记录一些真实的心灵感悟! 爱晚红枫博客群 爱晚红枫博客群网站是专注于湖南大学校园生活的博客网站 图客 深邃的内心,自由自我 网站收藏夹爱晚红枫
爱晚红枫·湖南大学论坛是 一个由学生自主筹划,建设,及运 营的,主要面向湖南大学师生的非 官方性网站网站正式成立2004年 7月1日,其域名为Hnubbs.net。 为目前湖南大学规模最大,人气 最旺的学生网站。网站谨记"实事 求是,敢为人先"的校训",倡导"思 想自由彰显个性"的宗旨,致力于 母校论坛和其他公益性事业 我的邻居alittlefish的博客 (rss) 海东的技术资料 搜索  最新随笔1. [转] C#下 读取xml节点的数据总结 2. 关闭浏览器窗口或离开页面时 3. javascript 的面向对象特性参考 4. 自己写的一个转换js中转换XML格式的函数 5. JAVASCRIPT中使用DOM操作XML文档 6. 尝试创建web项目或打开URL (Http/1.0 500 Server Error) 7. 优化JavaScript脚本的性能 8. XML数据岛,数据绑定 9. 数据库查询性能优化(合理使用索引|避免或简化排序|避免对大型表进行全表顺序扫描|避免使用相关的子查询|避免使用通配符匹配 ) 10. 在JavaScript的数组中进行数组元素查找和替换 最新评论 1. re: 用户权限系统设计方案 评论内容较长,点击标题查看 --湘子 2. re: 数据库查询性能优化(合理使用索引|避免或简化排序|避免对大型表进行全表顺序扫描|避免使用相关的子查询|避免使用通配符匹配 ) 链表结构,

聚集索引-->顺序表结构.其物理数据和逻辑排序紧邻.
非聚集索引-->单链表结构.起物理和逻辑排序不按顺序排列.
--湘子 3. 我也想该好皮肤 评论内容较长,点击标题查看 --枫叶子 4. re: window.showModalDialog使用手册 不错,我现在有个问题要问你!我已经发信息到你的信箱中,我的Email是:yuewenbin325@126.com --ALe 5. re: window.showModalDialog使用手册 评论内容较长,点击标题查看 --wendell 6. re: "未将对象引用设置到对象的实例"异常的原因,请大家接下去 1、ViewState 对象为Unll。 如何解决?使用Request.QueryString()时,所获取的对象不存在,或在值为空时未赋初始值 ????
--MONKEY 7. re: window.showModalDialog使用手册 评论内容较长,点击标题查看 --湘子 8. re: "未将对象引用设置到对象的实例"异常的原因,请大家接下去 1、ViewState 对象为Unll。 评论内容较长,点击标题查看 --Crying_Boy 9. re: 在JavaScript的数组中进行数组元素查找和替换 评论内容较长,点击标题查看 --湘子 10. re: 在NTFS分区中复制文件的同时如何复制权限 very good. --birdshome 11. re: 适用于.text系统的博客皮肤Nature和purple 评论内容较长,点击标题查看 --湘子 12. re: 适用于.text系统的博客皮肤Nature和purple 怎么用? --Silva 13. re: 适用于.text系统的博客皮肤Nature和purple 怎么用? --清秋冷月 14. re: XPath是一种XML文档的寻址语言 评论内容较长,点击标题查看 --湘子 15. re: XPath是一种XML文档的寻址语言 评论内容较长,点击标题查看 --Pvistely 16. re: xml并不神奇,只是我们自己没有理解 评论内容较长,点击标题查看 --湘子 17. re: 先组装字符串再拆分,加强通用性 评论内容较长,点击标题查看 --湘子 18. re: 在NTFS分区中复制文件的同时如何复制权限 好,正是我要找的。万里寻她千百度,回首却在自带工具中。 --timemax 19. re: xml并不神奇,只是我们自己没有理解 呵呵,现在项目比较紧张啊~~~没有时间来做这个了 --湘子 20. re: xml并不神奇,只是我们自己没有理解 呵呵,能不能为我们也做几套皮肤啦,:)
http://blog.nowans.com --bugx 21. re: xml并不神奇,只是我们自己没有理解 呵呵,能不能为我们也做几套皮肤啦,:) --bugx 22. re: 学一门语言的过程 “多线程,网络通讯,串口操作,套打,高级的图形界面效果(不用标准的WinForm控件),而且要在20多天内实现!”
高人啊!
--中国科幻 23. re: 爱晚红枫的博客配色----绿野仙踪 你这个SKIN,在大于1024*768的分辨率的情况下~~
顶头的图片不够长~~有些字显示在图片之外了 --NickYao 24. re: 绿草蓝天----为博客园又pick了一个SKin 谢谢 alittlefish 的提醒
我用ftb 的 代码编辑帖了下,现在应该好了一点了吧

--湘子 25. re: 绿草蓝天----为博客园又pick了一个SKin 你把上头的代码用cuteedit的添代码的方式贴出来吧,这样看起来有点累哦。 --alittlefish 26. re: 绿草蓝天----为博客园又pick了一个SKin 满好看的。呵呵 --alittlefish 27. re: 绿草蓝天----为博客园又pick了一个SKin 好的

有时间我整理出这方面的文章出来~
 
 --湘子 28. re: 绿草蓝天----为博客园又pick了一个SKin 有时间些点关于色彩选择和搭配的文章,好吗?谢谢啦! --YuL 29. re: 绿草蓝天----为博客园又pick了一个SKin 评论内容较长,点击标题查看 --dudu 30. re: DIY你的博客皮肤:Blog模板之一----猪啊 评论内容较长,点击标题查看 --dudu 31. re: DIY你的博客皮肤:Blog模板之一----猪啊 图片还要处理一下, 我来弄吧。 --dudu 32. re: DIY你的博客皮肤:Blog模板之一----猪啊 名字不太好取

還是DUDU你來取吧 呵呵 ~

--湘子 33. re: DIY你的博客皮肤:Blog模板之一----猪啊 那你起个名字, 我来发布吧。 --dudu 34. re: DIY你的博客皮肤:Blog模板之一----猪啊 dudu来了呵~~
好的,今晚就发布这个SKIN吧
不过这个不能算我的原创~ --湘子 35. re: DIY你的博客皮肤:Blog模板之一----猪啊 把这个Skin整理一下, 起个名字, 作为一个新Skin发布吧。 --dudu 36. re: DIY你的博客皮肤:Blog模板之一----猪啊 评论内容较长,点击标题查看 --湘子 37. re: DIY你的博客皮肤:Blog模板之一----猪啊 水滴 需要用js实现的吧?
skin不是只能修改css的吗?
你是怎么把js加上去的? --huangyi 38. re: DIY你的博客皮肤:Blog模板之一----猪啊 右边menu 的水滴是怎么搞的啊? 好玩好玩 --huangyi 39. re: 学一门语言的过程 评论内容较长,点击标题查看 --湘子 40. re: DIY你的博客皮肤:Blog模板之一----猪啊 呵,我用这个了,很喜欢....呵....谢谢.....

--gwazy 阅读排行榜1. DIY你的博客皮肤:Blog模板之一----猪啊 (1873) 2. 绿草蓝天----为博客园又pick了一个SKin(1701) 3. JavaScript的类型转换(字符转数字,数字转字符)(1510) 4. 爱晚红枫的博客配色----绿野仙踪(1344) 5. "未将对象引用设置到对象的实例"异常的原因,请大家接下去 1、ViewState 对象为Unll。(1075) 6. window.showModalDialog使用手册 (1038) 7. 适用于.text系统的博客皮肤Nature和purple(828) 8. document.getElementById的一些细节(760) 9. 在JavaScript的数组中进行数组元素查找和替换(558) 10. 学一门语言的过程(550) 11. XPath是一种XML文档的寻址语言(542) 12. 在NTFS分区中复制文件的同时如何复制权限 (503) 13. document.all还是document.getElementsByName(493) 14. 初学ASP.Net时在论坛收藏收集的一些资料备忘 (488) 15. xml并不神奇,只是我们自己没有理解(475) 16. JAVASCRIPT中使用DOM操作XML文档(420) 17. JavaScript数组的快速克隆(slice()函数)和数组的排序、乱序和搜索(sort()函数)(385) 18. 【收藏①】17种正则表达式(378) 19. 【备忘1】防止表格/层 被撑破的CSS控制代码(353) 20. XML数据岛,数据绑定(341) 21. 一些使用ASP.NET和VISUAL STUDIO.NET2003的经验和技巧(283) 22. 如何取中文为2的指定字符串字节数(281) 23. 客户端操作xml数据岛的方法(258) 24. 数据库查询性能优化(合理使用索引|避免或简化排序|避免对大型表进行全表顺序扫描|避免使用相关的子查询|避免使用通配符匹配 )(242) 25. 服务器端生成xml的方法(240) 26. 如何去除字符串中的多余空格?(228) 27. 优化JavaScript脚本的性能(221) 28. Dom基础(199) 29. ∥定义链接(193) 30. 先组装字符串再拆分,加强通用性(187) 31. [转]ASP.NET中的数据绑定:哪个更快? (177) 32. 新注册了一个BLOG(168) 33. [转]XML初级应用ABC(166) 34. [转]使用SQL语句来进行分页处理 (155) 35. [转]JavaScript中正则表达函数的说明与应用(154) 36. 我的后大学时代(143) 37. showModelessDialog()使用详解 (132) 38. B/S架构下软件开发技术参考(129) 39. 尝试创建web项目或打开URL (Http/1.0 500 Server Error)(98) 40. 自己写的一个转换js中转换XML格式的函数(84) 评论排行榜1. DIY你的博客皮肤:Blog模板之一----猪啊 (11) 2. 绿草蓝天----为博客园又pick了一个SKin(6) 3. 爱晚红枫的博客配色----绿野仙踪(4) 4. xml并不神奇,只是我们自己没有理解(4) 5. window.showModalDialog使用手册 (3) 6. 适用于.text系统的博客皮肤Nature和purple(3) 7. "未将对象引用设置到对象的实例"异常的原因,请大家接下去 1、ViewState 对象为Unll。(2) 8. XPath是一种XML文档的寻址语言(2) 9. 学一门语言的过程(2) 10. 在NTFS分区中复制文件的同时如何复制权限 (2) 11. 在JavaScript的数组中进行数组元素查找和替换(1) 12. 先组装字符串再拆分,加强通用性(1) 13. 数据库查询性能优化(合理使用索引|避免或简化排序|避免对大型表进行全表顺序扫描|避免使用相关的子查询|避免使用通配符匹配 )(1) 14. XML数据岛,数据绑定(0) 15. 优化JavaScript脚本的性能(0) 16. 尝试创建web项目或打开URL (Http/1.0 500 Server Error)(0) 17. JAVASCRIPT中使用DOM操作XML文档(0) 18. 自己写的一个转换js中转换XML格式的函数(0) 19. javascript 的面向对象特性参考(0) 20. 关闭浏览器窗口或离开页面时(0) 21. [转] C#下 读取xml节点的数据总结 (0) 22. 客户端操作xml数据岛的方法(0) 23. B/S架构下软件开发技术参考(0) 24. 服务器端生成xml的方法(0) 25. [转]XML初级应用ABC(0) 26. [转]使用SQL语句来进行分页处理 (0) 27. 我的后大学时代(0) 28. [转]ASP.NET中的数据绑定:哪个更快? (0) 29. document.getElementById的一些细节(0) 30. JavaScript的类型转换(字符转数字,数字转字符)(0) 31. JavaScript数组的快速克隆(slice()函数)和数组的排序、乱序和搜索(sort()函数)(0) 32. document.all还是document.getElementsByName(0) 33. 初学ASP.Net时在论坛收藏收集的一些资料备忘 (0) 34. Dom基础(0) 35. showModelessDialog()使用详解 (0) 36. 【备忘1】防止表格/层 被撑破的CSS控制代码(0) 37. 【收藏①】17种正则表达式(0) 38. ∥定义链接(0) 39. 一些使用ASP.NET和VISUAL STUDIO.NET2003的经验和技巧(0) 40. 如何取中文为2的指定字符串字节数(0) Powered by:

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值