One handy feature of Internet Explorer is the ability to use data islands to link data to html controls on a page. This feature is not readily built into Mozilla, but one can easily mimic this behavior to build cross-browser web applications.
IE有个很灵活的特性,就是能使用数据岛(data islands)把数据绑定到html组件上。这个特性不会马上嵌入到Mozilla,但是有些人可以很容易地跨浏览器模仿这种行为。
The basic data island we are going to use is a simple xml element either linked to the page or explicitly coding the xml into the page. For instance, let us illustrate a simple example:
我们要使用的数据岛是一个连接到页面或直接写在页面中的一个简单的xml元素。例如,下面就是一个简单的例子:
<xml id="xmlDataIsland">
<loaninfo>
<borrower id="1">
<firstname>Brian</firstname>
<middlename>Ellis</middlename>
<lastname>Johnson</lastname>
</borrower>
</loaninfo>
</xml>
With this data island, we can populate any number of controls on a page simply by linking the data island to the controls via some JavaScript and the DOM.
有了这个数据岛,我们就可以很轻松的使用JavaScript和DOM连接数据岛,来为页面上的组件填充数据了。
To link this, all we need to do is have a function to handle populating the controls such as:
要做连接,我们唯一要做的事就是像下面这样用一个函数来操作组件的数据填充:
function loadFields()
{
var xmlNode = window.document.getElementsByTagName('xml');
var borrowerNode = xmlNode[0].childNodes[1];
if(borrowerNode.hasChildNodes())
{
var i = 0;
var xmlChildNode, nodeVal=;
while(borrowerNode.childNodes[i])
{
// get node
xmlChildNode = borrowerNode.childNodes[i];
// check nodetype
if(xmlChildNode.nodeType != 3) // #text == 3
{
// get nodeValue (aka text)
nodeVal += xmlChildNode.firstChild.nodeValue + ' ';
}
i++;
}
// set control value to nodeValue
window.document.getElementById('txtBorrowerName').value = nodeVal;
}
}
Here is another example of an XML DataIsland for use in Mozilla or IE:
这里是另一个在Mozilla或IE中使用的XML数据岛的例子:
<xml id="mxxdataisland">
<mxxdataisland>
<rowset tagid="DATES"></rowset>
<rowset tagid="SUBJPRP"></rowset>
<rowset tagid="PRODUCT"></rowset>
</mxxdataisland>
</xml>
This dataisland's purpose is to inform the Application Server what tables this page is going to need access to or be requesting information from.
这个数据岛的目的是要通知应用服务器当前页面要访问什么样的表格或是从什么样的表格请求相关信息。
The controls on the page are then linked by way of custom attributes MXXOBJECT and MXXPROPERTY, much like the DATASRC and DATAFLD attributes used by IE. This allows the XML data returned to be parsed and linked or "bound" to the controls.
页面上的组件被自定义的属性MXXOBJECT和MXXPROPERTY所连接,很像IE中使用的DATASRC和DATAFLD属性。这样就能让返回的XML数据被解析并连接或是“绑定”到组件上。
Note: MXXOBJECT and MXXPROPERTY are just attributes that I made up, these actually could be any attribute.
注意:MXXOBJECT和MXXPROPERTY仅仅是我定义的属性,您可以把它们换成其他名称。
Binding the controls:
绑定组件:
<input
type="text"
id="PropertyStAddr1"
name="PropertyStAddr1"
style="height:21px;width:302px;text-align:left;"
maxlength="35"
class="fldDefault"
mxxobject="SUBJPRP" mxxproperty="PropertyStAddr1" <-- here are our "binding" tags
>
<input
type="text"
class="fldZipCode"
name="PropertyZip"
id="PropertyZip"
size="10"
style="height:21px;width:69px;"
mxxobject="SUBJPRP" mxxproperty="PropertyZip" <-- here are our "binding" tags
mxxxmlnode="xmldef_PropertyZip" <-- this links to a control-level data island
mxxtype="MXXZipCodeAutoLoadEdit" <-- optional custom type for control handling
>
Since we are passing XML to the server, we can also send the server some additional info that a particular control may need, or alert the server of other controls on the page related to or driven by a control. The following is an example of a custom dataisland for a specific control type:
我们可以把XML传递到服务器,同样,我们也可以服务器发送某个特定的控件所需要的额外信息,或是通知相关页面上的其他组件所在的或由组件驱动的服务器。下面是为特定组件定义的一个数据岛的例子。
<select
id="PropertyState"
name="PropertyState"
style="height:20px;width:48px;"
class="cmbDefault"
mxxtype="GFXStateList"
mxxxmlnode="xmldef_PropertyState"
mxxobject="GOXSUBJPRP" mxxproperty="PropertyState"
>
</select>
<div style="width:0px; height:0px; visibility:hidden;z-index:1">
<xml id="xmldef_PropertyState">
<mxxstatelist>
<status value="initialize"></status>
<contenttype value="abbrev"></contenttype>
<controls>
<control type="countylist" tagid="PropertyCounty" contenttype="name"
valuetype ="name"></control>
</controls>
</mxxstatelist>
</xml>
</div>
These XMLDataIslands don't do us any good just like this. In order for them to work we need to do 2 things.
这样的数据岛不能为我们带来任何好处。为了能让它们起作用,我们必须做两件事情。
1. Build control handlers to handle the updating and rendering of different control types.
第一,建立组件句柄来控制不同类型的组件的更新与表现。
(Note: Control types can be anything. Form objects, tables, spans, divs, iFrames, anything that you can access via the DOM and an ID is eligible)
(注意:组件类型可以是您通过DOM和有效的ID能够访问的表单对象、表格、span、div、iFrame等类型)
2. Build a handler to build a dom to send to the server and parse the return back out to the controls.
建立句柄来创建一个dom并发给服务器,并且分析返到组件的信息。
All a control handler has to do is be able to updata a control value. This means all Text Inputs can share a handler, selects another, and so on. One way to do this is to scrape the controls on a given page into an associative array. Then, when a response is returned, we can parse out the xml via an id attribute to match up the xml payload with a control.
一个组件句柄要做的就是更新组件的值。这就意味着所有的文件输入框可以共享一个句柄,
然后,当响应返回我们可以通过XML的id属性匹配到对应的组件。
<input type="text" id="FirstName" ...>
Sample Object collector function:
简单的队形收集器函数:
// grab all the elements for parsing
var tags = window.document.body.getElementsByTagName("*");
var pPrevElem = null;
var pNextElem = null;
for (var i = 0; i < tags.length; i++)
{
pHTMLElement = tags[i];
switch (pHTMLElement.tagName.toLowerCase())
{
case "span":
case "table":
// this indexes by controlID and stores the elementObject
m_MXXPageObjectsArray[pHTMLElement.id] = pHTMLElement;
break;
case "input":
case "select":
case "textarea":
case "button":
// this indexes by controlID and stores the elementObject
m_MXXPageObjectsArray[pHTMLElement.id] = pHTMLElement;
break;
case "div":
// this indexes by controlID and stores the elementObject
m_MXXPageObjectsArray[pHTMLElement.id] = pHTMLElement;
break;
}
}
The xml payload going out might be:
Xml格式如下:
<page id="NewUser">
<formcontrols>
<control id="FirstName">
<value />
</control>
</formcontrols>
</page>
The return would then be:
返回内容如下:
<page id="NewUser">
<formcontrols>
<control id="FirstName">
<value>Dennis</value>
</control>
</formcontrols>
</page>
The parsing handler would then take the response, load it into an XML DOM, then pass out each node to the appropriate control handler.
分析句柄接收响应并加载到XML DOM,然后把每个节点传递到对应的组件。
processTextControl(control, xmlNode);
Sample parsing of returned xml:
返回的xml的简单传递:
// parseout to controls
var formControlNodes = xmlDoc.getElementsByTagName('formcontrols');
for(i=0; i<formControlNodes.length;++i)
{
var pFormControlNode = formControlNodes[i];
var pPageObject = m_MXXPageObjectsArray[pFormControlNode.getAttribute('id')];
if(!pPageObject)
continue;
processTextControl(pPageObject, pBoundControlNode);
}
The control handler would then rip out the necessary data to populate the control. In this case the value nodevalue would be used to set control.value. A select could have the options to loop through and create new Options() with or even just replace the node or innerHTML with the new payload.
组件句柄将必要的数据填充到相关组件中。这里,节点值将被用于设置组件的值。SELECT标签通过循环遍历来创建OPTION。
Finally here is a small table sample using XML Data Islands that works in both IE6 and Mozilla.
最后,这个是一个在IE6和Mozilla里都能运行的XML数据岛的表格例子。
For any of the above to do us any good, we need to get this info to the server. We can do this a number of ways, including ASP, JSP, and CGI. I'm going to use XMLHTTP since it allows for me to update a page without having to reload it and it allows for the controls to update other controls and act like a regular 2 tier application by providing instant updates and event handling.
我们可以用很多方式来实现,包括ASP、JSP和CGI。我将用XMLHTTP,因为这样可以不重新加载页面来更新页面内容,并且可以像两层应用程序那样,即时更新其他组件和进行事件控制。
Original Document Information
- Author(s): Thad Hoffman (phiori@mindspring.com, phiori@mac.com)
- Other Contributors: Heikki Toivonen (heikki@netscape.com)
- Last Updated Date: June 21, 2005
- Copyright Information: Copyright (C) Thad Hoffman, Heikki Toivonen