局部刷新技术(2)
一、XML文档 与 XML DOM
XML 文档 | XML DOM (Document Object Model) 树 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<?xml version="1.0" encoding="UTF-8" ?> <课程> <公共课 编号="C00001" 必修="false"> <名称 类型="string" 宽度="50">高等数学</名称> <学分 类型="decimal">5.0</学分> </公共课> <公共课 编号="C00002" 必修="true"> <名称 类型="string" 宽度="50">体育</名称> <学分 类型="decimal">4.0</学分> </公共课> <专业课 编号="C54001" 专业代码="54" 必修=true> <名称 类型="string" 宽度="50">C#语言程序设计</名称> <学分 类型="decimal">6.0</学分> </专业课> </课程> |
● -- node(节点) |
二、XML DOM Document 对象成员
1、常用 Document 对象属性
属性 | 描述 | IE | Firefox | Opera | W3C |
childNodes | 5 | 1 | 9 | Yes | |
documentElement | 返回文档的根节点 | 5 | 1 | 9 | Yes |
firstChild | 返回文档的首个子节点 | 5 | 1 | 9 | Yes |
lastChild | 返回文档的最后一个子节点。 | 5 | 1 | 9 | Yes |
nodeName | 依据节点的类型返回其名称。 | 5 | 1 | 9 | Yes |
nodeType | 返回节点的节点类型。 | 5 | 1 | 9 | Yes |
nodeValue | 根据节点的类型来设置或返回节点的值。 | 5 | 1 | 9 | Yes |
text | 返回节点及其后代的文本(仅用于 IE)。 | 5 | No | No | No |
2、常用 Document 对象方法
方法 | 描述 | IE | Firefox | Opera | W3C |
getElementById() | 查找具有指定的唯一 ID 的元素。 | 5 | 1 | 9 | Yes |
getElementsByTagName() | 返回所有具有指定名称的元素节点。 | 5 | 1 | 9 | Yes |
三、XML DOM Element 对象成员
1、常用 Element 对象属性
属性 | 描述 | IE | Firefox | Opera | W3C |
attributes | 返回元素的属性的 NamedNodeMap | 5 | 1 | 9 | Yes |
childNodes | 返回元素的子节点的 NodeList | 5 | 1 | 9 | Yes |
firstChild | 返回元素的首个子节点 | 5 | 1 | 9 | Yes |
lastChild | 返回元素的最后一个子节点 | 5 | 1 | 9 | Yes |
nextSibling | 返回元素之后紧跟的节点 | 5 | 1 | 9 | Yes |
nodeName | 返回节点的名称,依据其类型。 | 5 | 1 | 9 | Yes |
nodeType | 返回节点的类型 | 5 | 1 | 9 | Yes |
ownerDocument | 返回元素所属的根元素 (document 对象) | 5 | 1 | 9 | Yes |
parentNode | 返回元素的父节点 | 5 | 1 | 9 | Yes |
previousSibling | 返回元素之前紧随的节点 | 5 | 1 | 9 | Yes |
tagName | 返回元素的名称 | 5 | 1 | 9 | Yes |
textContent | 设置或返回元素及其后代的文本内容 | No | 1 | No | Yes |
text | 返回节点及其后代的文本 (IE-only) | 5 | No | No | No |
2、常用 Element 对象方法
方法 | 描述 | IE | Firefox | Opera | W3C |
getAttribute() | 返回属性的值。 | 5 | 1 | 9 | Yes |
getElementsByTagName() | 找到具有指定标签名的子孙元素。 | 5 | 1 | 9 | Yes |
hasChildNodes() | 返回元素是否拥有子节点。 | 5 | 1 | 9 | Yes |
四、Node 对象成员
1、常用 Node 对象属性
属性 | 描述 | IE | Firefox | Opera | W3C |
childNodes | 返回节点到子节点的节点列表。 | 5 | 1 | 9 | Yes |
firstChild | 返回节点的首个子节点。 | 5 | 1 | 9 | Yes |
lastChild | 返回节点的最后一个子节点。 | 5 | 1 | 9 | Yes |
nextSibling | 返回节点之后紧跟的同级节点。 | 5 | 1 | 9 | Yes |
nodeName | 返回节点的名称,根据其类型。 | 5 | 1 | 9 | Yes |
nodeType | 返回节点的类型。 | 5 | 1 | 9 | Yes |
nodeValue | 设置或返回节点的值,根据其类型。 | 5 | 1 | 9 | Yes |
ownerDocument | 返回节点的根元素(document 对象)。 | 5 | 1 | 9 | Yes |
parentNode | 返回节点的父节点。 | 5 | 1 | 9 | Yes |
previousSibling | 返回节点之前紧跟的同级节点。 | 5 | 1 | 9 | Yes |
textContent | 设置或返回节点及其后代的文本内容。 | No | 1 | No | Yes |
text | 返回节点及其后代的文本(IE 独有的属性)。 | 5 | No | No | No |
2、常用 Node 对象方法
方法 | 描述 | IE | Firefox | Opera | W3C |
hasAttributes() | 判断当前节点是否拥有属性。 | No | 1 | 9 | Yes |
hasChildNodes() | 判断当前节点是否拥有子节点。 | 5 | 1 | 9 | Yes |
五、NodeList 对象成员
1、常用 NodeList 对象属性
属性 | 描述 | IE | Firefox | Opera | W3C |
length | 可返回节点列表中的节点数目。 | 5 | 1 | 9 | Yes |
2、常用 NodeList 对象方法
方法 | 描述 | IE | Firefox | Opera | W3C |
item() | 可返回节点列表中处于指定的索引号的节点。 | 5 | 1 | 9 | Yes |
六、Text 对象成员
常用 Text 对象属性>
属性 | 描述 | IE | Firefox | Opera | W3C |
data | 设置或返回元素或属性的文本 | 6 | 1 | 9 | Yes |
length | 返回元素或属性的文本长度 | 6 | 1 | 9 | Yes |
七、NamedNodeMap 对象成员
1、常用 NamedNodeMap 对象属性
属性 | 描述 | IE | Firefox | Opera | W3C |
length | 可返回列表中的节点数目 | 5 | 1 | 9 | Yes |
2、常用 NamedNodeMap 对象方法
方法 | 描述 | IE | Firefox | Opera | W3C |
getNamedItem() | 可返回指定的节点(通过名称) | 5 | 1 | 9 | Yes |
item() | 可返回处于指定索引号的节点 | 5 | 1 | 9 | Yes |
八、Attr 对象成员
常用 Attr 对象的属性
属性 | 描述 | IE | Firefox | Opera | W3C |
isId | 如果属性是 id 类型,则返回 true,否则返回 false。 | No | No | No | Yes |
name | 返回属性的名称。 | 5 | 1 | 9 | Yes |
nodeName | 返回节点的名称,依据其类型。 | 5 | 1 | 9 | Yes |
nodeType | 返回节点的类型。 | 5 | 1 | 9 | Yes |
nodeValue | 设置或返回节点的值,依据其类型。 | 5 | 1 | 9 | Yes |
ownerDocument | 返回属性所属的根元素(document对象)。 | 5 | 1 | 9 | Yes |
ownerElement | 返回属性所附属的元素节点。 | No | 1 | 9 | Yes |
textContent | 设置或返回属性的文本内容。 | No | 1 | 9 | Yes |
text | 返回属性的文本。IE-only。 | 5 | No | No | No |
value | 设置或返回属性的值。 | 5 | 1 | 9 | Yes |
九、应用实例
【例1】将开头的XML文件显示成下列表格
课程编号 | 课程名称 | 学分 | 开设专业 | 必修 |
C00001 | 高等数学 | 5.0 |
| 否 |
C00002 | 体育 | 4.0 |
| 是 |
C54001 | C#语言程序设计 | 6.0 | 54 | 是 |
<script language=javascript>
req = null;
function reqXML()
{
req = null;
if (window.XMLHttpRequest)
req = new XMLHttpRequest();
else if (window.ActiveXObject)
req = new ActiveXObject("MSXML2.XMLHTTP");
if (!req) return;
req.onreadystatechange=makeTable;
req.open("GET", "WebForm2.aspx", true);
req.send(null);
}
function makeTable()
{
if (!req || req.readyState!=4 || req.status!=200) return;
var xml = req.responseXML;
req = null;
var tb = document.createElement("table");
tb.border = tb.cellSpacing = tb.cellPadding = 1;
var c = ["课程编号","课程名称","学分","开设专业","必修"];
with(tb.insertRow())
for(var i=0; i<c.length; i++)
with (insertCell())
innerText=c[i];
var root = xml.documentElement;
for(var i=0; i<root.childNodes.length; i++)
{
var courseNode = root.childNodes[i];
var tr = tb.insertRow();
var node = courseNode.attributes.getNamedItem("编号");
var td = tr.insertCell();
td.innerText = node ? node.nodeValue : " ";
node = getChildNodeByName(courseNode,"名称");
td = tr.insertCell();
td.innerText = node ? node.firstChild.data : " ";
node = getChildNodeByName(courseNode,"学分");
td = tr.insertCell();
td.innerText = node ? node.firstChild.data : " ";
node = courseNode.attributes.getNamedItem("专业代码");
td = tr.insertCell();
td.innerText = node ? node.nodeValue : " ";
node = getAttributeByName(courseNode, "必修");
td = tr.insertCell();
td.innerText = node && node.nodeValue=="true" ? "是": "否";
}
container.appendChild(tb);
}
function getChildNodeByName(node, name)
{
for(var i=0; i<node.childNodes.length; i++)
if (node.childNodes.item(i).nodeName == name)
return node.childNodes.item(i);
return null;
}
function getAttributeByName(node, name)
{
for(var i=0; i<node.attributes.length; i++)
if (node.attributes.item(i).nodeName == name)
return node.attributes.item(i);
return null;
}
</script>
【例2】将上一节的【例2】改用 XML DOM 方式
GetPage.aspx 页面
int pageSize = 20;
private void Page_Load(object sender, System.EventArgs e)
{
this.Response.Expires = -1;
string pg = this.Request.QueryString["pg"];
int ipg = 1;
try
{
ipg = int.Parse(pg);
}
catch{}
daArticles.Fill(ds, (ipg-1)*pageSize, pageSize,"Articles");
this.Response.ContentType = "text/xml";
this.Page.Controls.Clear();
this.Response.Write(@"<?xml version=""1.0"" encoding=""utf-8""?>");
this.Response.Write("<articles>");
foreach(DataRow dr in ds.Articles)
{
this.Response.Write("<article>");
this.Response.Write("<id>");
this.Response.Write(dr["id"].ToString());
this.Response.Write("</id>");
this.Response.Write("<title>");
this.Response.Write(Server.HtmlEncode(dr["title"].ToString()));
this.Response.Write("</title>");
//...
this.Response.Write("</article>");
}
this.Response.Write("</articles>");
}
Subject.aspx 页面
function writePage()
{
if (!req || req.readyState!=4 || req.status != 200) return;
var xml = req.responseXML;
req = null;
var tb = document.createElement("table");
var a = xml.getElementsByTagName("article"); // article's nodes list
for(var i=0; i<a.length; i++)
{
var tr = tb.insertRow();
var td = tr.insertCell();
var lnk = document.createElement("a");
lnk.href = "article.aspx?id="+a[i].childNodes[0].firstChild.data; // id
lnk.innerHTML = a[i].childNodes[1].firstChild.data; // title
td.appendChild(lnk);
//...
}
a = xml.getElementsByTagName("btn"); // btn's nodes list
var f = a[0].firstChild.data;
var t = a[1].firstChild.data;
// 生成 f 到 t 的导航按钮
//-------------------
while (mainview.firstChild)
mainview.removeChild(mainview.firstChild);
mainview.appendChild(tb);
}
实现多选记录的指定操作
在进行数据库维护时,有时需要由用户根据列表选出多条记录进行操作,例如:
| 产品名称 | 规格 | 库存量 | ||||
| Chai | 10 boxes x 20 bags | 39 | ||||
| Chang | 24 - 12 oz bottles | 17 | ||||
| Aniseed Syrup | 12 - 550 ml bottles | 13 | ||||
| Chef Anton's Cajun Seasoning | 48 - 6 oz jars | 53 | ||||
| Chef Anton's Gumbo Mix | 36 boxes | 0 | ||||
|
| 产品名称 | 规格 | 库存量 | |||
| Chai | 10 boxes x 20 bags | 39 | |||
| Aniseed Syrup | 12 - 550 ml bottles | 13 | |||
|
| 产品名称 | 规格 | 库存量 | |||
| Chai | 10 boxes x 20 bags |
| |||
| Aniseed Syrup | 12 - 550 ml bottles |
| |||
|
一、生成能标识记录的表单元素(复选框、文本框等)
要让不同表单元素与“产品”记录一一对应,即标识不同“产品”,最好的办法是将产品的 ID 作为表单元素的“name”属性的一部分。为了区分不同(类型)的表单元素,需要在“name”属性前添加前缀,前缀与产品ID之间使用一个特殊字符(如“_”、“$”等)分隔,以便拆取(见二)。
foreach (DataRow dr in DataRows)
{
// ...
System.Web.UI.WebControls.CheckBox cb = new CheckBox();
cb.ID = "Chk_" + dr["ProductID"].ToString();
// 服务器将自动生成与ID相同的 name 属性
// ...
TextBox tb = new TextBox();
tb.ID = "UIS_" + dr["ProductID"].ToString();
tb.Text = dr["UnitsInStock"].ToString();
// ...
}
二、获取用户选定要操作的记录
for (int i=0; i<Request.Form.Keys.Count; i++)
{
// 取得表单元素的“name”
string kn = Request.Form.Keys[i];
// 将其拆分成“前缀”和“产品ID”
string[] ChkID = kn.Split(new char[]{'_'});
// 若“name” 形如 前缀_nnn,则 nnn 为产品 ID
if (ChkID.Length == 2 && ChkID[0] == "Chk")
{
// 记录下 ChkID[1] ——产品ID,或对 ID 为 ChkID[1] 的产品进行指定操作(删除/修改等)
}
}
三、完整实例
default.aspx
1、样式表
<style type="text/css">
.DsBtn { COLOR:silver; TEXT-DECORATION:underline }
.EnBtn { CURSOR:hand; COLOR:blue; TEXT-DECORATION:underline }
</style>
2、客户端脚本
<script language="javascript" type="text/javascript">
//检测是否选定了记录
function CheckSelected()
{
var cc = 0;
for (var i=0; i<Form1.all.length; i++)
if (Form1.all[i].getAttribute("type") =="checkbox" && Form1.all[i].checked)
cc++;
return cc>0;
}
//将“操作”存入“opr”并提交表单
function DoSubmit(o)
{
if (o == "DeleteRecs" || o == "ModifyRecs" || o == "ConfirmDeleteRecs")
{
if (!CheckSelected())
{
window.alert("请选定要删除/修改的记录。");
return
}
}
Form1.opr.value = o;
Form1.submit();
}
//单击复选框时,根据是否选定了记录来设置按钮的样式
function CheckOut()
{
var si = CheckSelected();
for (var i=0; i<document.all.length; i++)
if (document.all[i].id.indexOf("Btn") == 0)
document.all[i].className = si ? "EnBtn" : "DsBtn";
}
</script>
3、表单
<form id="Form1" method="post" runat="server">
<!-- 用于将要进行的“用户操作”传递给服务器 -->
<INPUT id="opr" type="hidden" name="opr">
<table>
<tr>
<td>
<asp:table id="ProductsList" runat="server" GridLines="Both">
<asp:TableRow>
<asp:TableCell> </asp:TableCell>
<asp:TableCell Text="产品名称"></asp:TableCell>
<asp:TableCell Text="规格"></asp:TableCell>
<asp:TableCell Text="库存量"></asp:TableCell>
</asp:TableRow>
</asp:table>
</td>
</tr>
<tr>
<td align="right">
<table cellspacing="10">
<tr>
<td id="PPBtn" runat="server" class="EnBtn" onclick="javascript:DoSubmit('PriorPage')">上一页</td>
<td id="NPBtn" runat="server" class="EnBtn" onclick="javascript:DoSubmit('NextPage')">下一页</td>
<td id="BtnDelSel" runat="server" class="DsBtn" onclick="javascript:DoSubmit('DeleteRecs')">删除选定记录</td>
<td id="BtnModSel" runat="server" class="DsBtn" onclick="javascript:DoSubmit('ModifyRecs')">修改选定记录</td>
<td id="BtnCfmDel" runat="server" class="DsBtn" onclick="javascript:DoSubmit('ConfirmDeleteRecs')">确认删除</td>
<td id="BtnCfmMod" runat="server" class="DsBtn" onclick="javascript:DoSubmit('ConfirmModifyRecs')">确认修改</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
default.aspx.cs
public class _default : System.Web.UI.Page
{
protected System.Data.SqlClient.SqlConnection sqlConnection1;
protected Shop.dsProducts dsProducts1;
protected System.Web.UI.WebControls.Table ProductsList;
protected System.Web.UI.HtmlControls.HtmlTableCell BtnDelSel;
protected System.Web.UI.HtmlControls.HtmlTableCell BtnModSel;
protected System.Web.UI.HtmlControls.HtmlTableCell BtnCfmDel;
protected System.Web.UI.HtmlControls.HtmlTableCell PPBtn;
protected System.Web.UI.HtmlControls.HtmlTableCell NPBtn;
protected System.Data.SqlClient.SqlCommand sqlSelectCommand2;
protected System.Web.UI.HtmlControls.HtmlTableCell BtnCfmMod;
protected System.Data.SqlClient.SqlDataAdapter dadpProducts;
protected System.Data.SqlClient.SqlDataAdapter dadpProductsCount;
protected System.Data.SqlClient.SqlCommand sqlSelectCommand1;
protected System.Data.SqlClient.SqlCommand sqlInsertCommand1;
protected System.Data.SqlClient.SqlCommand sqlUpdateCommand1;
protected System.Data.SqlClient.SqlCommand sqlDeleteCommand1;
// 当前显示记录页
public int CurrentPage
{
get
{
if (ViewState["CurrentPage"] == null)
return 1;
else
return (int)ViewState["CurrentPage"];
}
set
{
ViewState["CurrentPage"] = value;
}
}
// 记录页大小
int PageSize = 10;
// 总记录页数
int TotalPages = 0;
// 是修改还是删除
bool IsModify = false;
private void Page_Load(object sender, System.EventArgs e)
{
// 取得所要进行的“操作”opr
string opr = "";
if (IsPostBack) opr = Request.Form["opr"];
// 计算产品列表的总记录页数
DataTable dt = new DataTable();
dadpProductsCount.Fill(dt); // select count(*) from products
int rc = (int)dt.Rows[0][0];
TotalPages = rc/PageSize;
if (rc%PageSize != 0) TotalPages++;
// 根据 opr 执行相应的操作
switch(opr)
{
// 第一次打开页面
default:
ShowRecords(); // 显示当前页记录
break;
// “下一页”
case "NextPage":
CurrentPage++; // 当前页增一
ShowRecords();
break;
// “上一页”
case "PriorPage":
if (CurrentPage > 1)
CurrentPage--;
ShowRecords();
break;
// “删除”
case "DeleteRecs":
ShowSelected();
break;
// 确认删除
case "ConfirmDeleteRecs":
DeleteSelected();
break;
// 修改
case "ModifyRecs":
IsModify = true;
ShowSelected();
break;
// 确认修改
case "ConfirmModifyRecs":
ModifySelected();
break;
}
}
// 显示 CurrentPage 页 记录
private void ShowRecords()
{
dsProducts1.Products.Clear();
dadpProducts.Fill(dsProducts1, (CurrentPage-1)*PageSize, PageSize, "Products");
ShowDataRows(dsProducts1.Products.Select()/*显示当前页所有记录*/);
BtnCfmDel.Visible = false;
BtnCfmMod.Visible = false;
BtnDelSel.Visible = true;
BtnModSel.Visible = true;
}
// 显示 选定记录
private void ShowDataRows(DataRow[] DataRows)
{
foreach(DataRow dr in DataRows)
{
TableRow tr = new TableRow();
ProductsList.Rows.Add(tr);
TableCell tc = new TableCell();
tr.Cells.Add(tc);
System.Web.UI.WebControls.CheckBox cb = new CheckBox();
// 用产品ID作为复选框的ID,以便 PostBack 后识别
cb.ID = "Chk_" + dr["ProductID"].ToString();
cb.Attributes.Add("onclick","CheckOut()");
tc.Controls.Add(cb);
tc = new TableCell();
tc.Text = dr["ProductName"].ToString();
tr.Cells.Add(tc);
tc = new TableCell();
tc.Text = dr["QuantityPerUnit"].ToString();
tr.Cells.Add(tc);
tc = new TableCell();
if (IsModify)// 是修改则修改规格的添加文本框
{
TextBox tb = new TextBox();
tb.ID = "UIS_"+dr["ProductID"].ToString();
tb.Text = dr["UnitsInStock"].ToString();
tc.Controls.Add(tb);
}
else // 列表或删除则只显示规格
tc.Text = dr["UnitsInStock"].ToString();
tr.Cells.Add(tc);
}
// 通过样式来显示是否可“上下翻页”
PPBtn.Attributes["class"] = CurrentPage>1 ? "EnBtn":"DsBtn";
if (CurrentPage == 1) PPBtn.Attributes.Remove("onclick");
NPBtn.Attributes["class"] = CurrentPage < TotalPages ? "EnBtn":"DsBtn";
if (CurrentPage == TotalPages) NPBtn.Attributes.Remove("onclick");
}
// 显示用户选定记录,以确认“删除”/“修改”
private void ShowSelected()
{
DataRow[] sdr = GetSelectedRecs();
ShowDataRows(sdr);
BtnCfmDel.Visible = !IsModify;
BtnCfmMod.Visible = IsModify;
if (sdr.Length>0) BtnCfmDel.Attributes["class"] = "EnBtn";
if (sdr.Length>0) BtnCfmMod.Attributes["class"] = "EnBtn";
BtnDelSel.Visible = false;
BtnModSel.Visible = false;
}
// 取得用户选定记录
private DataRow[] GetSelectedRecs()
{
dsProducts1.Products.Clear();
dadpProducts.Fill(dsProducts1, (CurrentPage-1)*PageSize, PageSize, "Products");
string fltr = "";
// 取得用户选定记录的产品ID
// 并将所有选定的产品的 ID 生成 IN 表达式
for (int i=0; i<Request.Form.Keys.Count; i++)
{
string[] ChkID = Request.Form.Keys[i].Split(