实际上,XML是数据类型的良好抽象,并且为data binding提供了内在支持。当XML DOM(文档对象模型)的某一节点发生改动时,触发的事件被自动传播。事件既能被注册在该节点的handler处理,也能被注册在它的上级节点的handler处理。并且事件传播有capturing与bubbling两个阶段,上级节点能在capturing阶段阻止事件的传播。XML DOM不仅支持节点值更改或节点插入、删除的事件,而且也支持在节点上发生的用户自定义事件,如点击。
不仅如此,由于XML将DOM模型与编程语言的具体实现分开,使得XML库能够在内部采用更为高效的数据结构。例如,不为一个文本段落<p>内的子元素建立元素“实例”,而将段落的内部XML用字符串保存,但仍支持元素的遍历、更改、增删以及事件操作。
不过,与自定义数据类型相比,XML API仍然有较多欠缺。如缺少对按照schema的元素强类型值的支持及对操作的验证,以及对用户自定义的元素功能的支持。实际上,有可能扩展现有的API支持强类型的元素类型,即Document在构造元素时按照元素名称产生用户定制的元素类型。Java API中的javax.xml.parsers.DocumentBuilderFactory可能是为此留下的接口。
Data binding的主要用途是由模板根据数据生成UI内容。当数据重复(循环)时,相同的模板被用来产生多个UI实例。这些实例重复了较多不变的数据字段。编程语言如C#与Java缺少从对象继承的机制,即无法将固定多数字段(如模板中的大多数显示内容)的某组对象视作一类,该类的实例仅提供(补上)其余字段。(若用虚方法访问所有字段这一扩展可被支持。)Javascript的prototype继承机制原理上说能够支持这一功能,即重复显示某个元素(如<div>时),只要继承元素通过“覆盖”修改与父元素不同的内容即可。(实际上并不可行,浏览器不接受插入继承的元素对象。)从环境继承并补上属性的概念非常有用,与显示相关的元素类常有很多多数时候不被设置的继承属性(如字体、颜色等),以及大量很少被设置的事件字段。(JavaFX的Node类用style字符串字段绕开了添加过多显示属性的问题。)下面的javascript代码示例了对数组内容的覆盖。
aa = [ 1,2,3,4 ] bb = { __proto__: aa,2: 0 } // bb[2] = 0,aa[2] = 3,其余数组元素相同
我所看到的开源的Javascript网页端MVC库如AngularJS仍然以Javascript对象为数据模型,尽管将XML用作数据模型实现相同功能更为容易(我正在着手写一个很基本的基于XML的类似AnguarJS的MVC库)。顺便说一句,我未能看到这些开源库的很好的文档与示例。我认为一个产品必须有良好的文档与示例才值得一用(一学),即文档与示例是产品的重要组成部分,这实际上是受西方一再鼓励的标准(参见:www.w3schools.com,www.w3school.com.cn)。能学的知识非常多、可以改进的地方更多,这些是很好的考察方法。不能用限制文档的方式来考察人,这是人权的基准。应当鼓励分享知识,让个人的辛劳使他人收益、而不是重复学习。工作职位应当让员工成长,单位而不是个人应负责培训。
在web页面中最精简的数据表示莫过于只有数据(XML内容)本身,而把将数据转换为显示内容的职责交给浏览器来完成。实际上,对XML的转换可以用XSLT表示(其他转换模板可被翻译为XSLT),而浏览器(大约从2000年起)都支持显示带XSL stylesheet的XML文档。XSL stylesheet用processing instruction标出,例如:
<?xml-stylesheet type="text/xsl" href="show_book.xsl"?>
不过,浏览器并未支持在XML文档中将javascript用作用户交互或更改文档内容,或者支持对HTML页面内的XML块(Microsoft术语:XML data island)的自动XSLT转换。
当源XML发生改变时,对XSLT转换结果作增量改变的最简单的方法是重新生成,但在生成过程中根据依赖关系忽略未发生修改的目标节点。这要求转换器能够根据发生改变的源节点的xpath判断目标DOM中需要修改、插入或删除的目标节点的xpath。根据给出的生成函数(generating function)自动产生当源发生改变时对结果作增量修改的代码是一种理想。实际上,浏览器在处理来自同一url的(可能参数不同)相差不多的页面时,可以仅对此前的render结果作增量修改。早期的浏览器没有DOM标准的支持,但允许通过document.write()写入HTML源码来刷新页面,并且可能仅对更改部分作增量修改。(Javascript string的一些方法,如link()、bold()等可能是用以支持这些功能的“遗迹”。)