利用DOM来处理XML文档(zz)

XML文件1
< xml version=”1.0″ standalone=”yes”  >
<Tree>
<TreeNode>
<NodeId>0</NodeId>
<Title>代號 </Title>
<NodeXmlSrc>Content.xml</NodeXmlSrc>
</TreeNode>
<TreeNode>
<NodeId>0</NodeId>
<Title>品牌</Title>
<NodeXmlSrc>BrandList.xml</NodeXmlSrc>
</TreeNode>
<TreeNode>
<NodeId>0</NodeId>
<Title>型體</Title>
<NodeXmlSrc>SpecContent.xml</NodeXmlSrc>
</TreeNode>
<TreeNode>
<NodeId>0</NodeId>
<Title>客戶</Title>
<NodeXmlSrc>BuyerList.xml</NodeXmlSrc>
</TreeNode>
<TreeNode>
<NodeId>0</NodeId>
<Title>規格</Title>
<NodeXmlSrc>SpecList.xml</NodeXmlSrc>
</TreeNode>
<TreeNode>
<NodeId>0</NodeId>
<Title>中國</Title>
<NodeXmlSrc>aa.xml</NodeXmlSrc>
</TreeNode>
</Tree>

XML文件2
< xml version=”1.0″ standalone=”yes”  >
<Tree>
<TreeNode NodeId=”0″ Title=”客戶” NodeXmlSrc=”BuyerList.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”品牌” NodeXmlSrc=”Sample.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”型體” NodeXmlSrc=”msdnlib587_.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”規格” NodeXmlSrc=”msdnlib3_.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”代號” NodeXmlSrc=”msdnlib3_.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”產地” NodeXmlSrc=”msdnlib587_.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”中國” NodeXmlSrc=”123456.xml”></TreeNode>
</Tree>

我說的是它們的結構,為什麼不一樣,但是出到一個TABLE里面卻是一樣的啊,
文件2變成文件1的形式

两个文件的结构明显不同么,还用说有什么不同吗?
主要的问题是如何转换。
可以用DOM解析第二个文件,然后再构造出第一个文件。

try:
/*** a.htm ***/
<SCRIPT LANGUAGE=”javaScript”>
function transXML()
{
var oXML, oXSL ;
var sXML ;

oXML= new ActiveXObject(“MSXML2.DOMDocument.3.0”) ;
oXSL= new ActiveXObject(“MSXML2.DOMDocument.3.0”) ;
oXML.async = false ;
oXML.load(“a.xml”) ;
oXSL.async = false ;
oXSL.load(“a.xsl”) ;

alert(oXML.xml);//转换前

sXML= oXML.transformNode(oXSL)

alert(sXML);//转换后
}

function window.onload()
{
transXML();
}
</SCRIPT>

/*** a.xml ***/
< xml version=”1.0″ encoding=”utf-8″  >
<Tree>
<TreeNode NodeId=”0″ Title=”客戶” NodeXmlSrc=”BuyerList.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”品牌” NodeXmlSrc=”Sample.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”型體” NodeXmlSrc=”msdnlib587_.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”規格” NodeXmlSrc=”msdnlib3_.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”代號” NodeXmlSrc=”msdnlib3_.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”產地” NodeXmlSrc=”msdnlib587_.xml”></TreeNode>
<TreeNode NodeId=”0″ Title=”中國” NodeXmlSrc=”123456.xml”></TreeNode>
</Tree>

/*** a.xsl ***/
< xml version=”1.0″ encoding=”utf-8″  >
<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform“>
<xsl:output method=”xml” encoding=”utf-8″ indent=”yes”/>

<xsl:template match=”/”>
<Tree>
<xsl:apply-templates select=”Tree/TreeNode” />
</Tree>
</xsl:template>

<xsl:template match=”TreeNode”>
<xsl:element name=”{name()}”>
<xsl:for-each select=”@*”>
<xsl:element name=”{name()}”>
<xsl:value-of select=”.” />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>

</xsl:stylesheet>

在/Tree/TreeNode下,
“XML文件1″以element来描述当前TreeNode的各特性
“XML文件2″以attribute来描述当前TreeNode的各特性
这导致结构差异

element和attribute在DOM中都可定义为XmlNode但NodeType不同,其内容处理方式也有不同

有关网站UI实现的几种方式的讨论

抛砖引玉,提出一些知道的做法,欢迎大家提出更多做法。

  对于网站来说,UI最终的形式无非是(X)HTML + 脚本 + 样式,现在的问题是怎么样生成这些前端的元素,在以下几个方面达到平衡:

  (假设有开发和前端两种角色,前端负责表现逻辑和表现,而开发负责业务逻辑和业务数据)

  1) 开发人员的工作量,工作难度

  2) 前端开发人员(后面省略为前端)的工作量,工作难度

  3) 产品(假设前端属于产品部)对UI的改动需求能否快速落实(能否只依靠前端实现)

  4) 服务端的压力(客户端的性能问题暂时不考虑)

  (怎么发现自从翻译了《微软应用架构指南》之后,写什么都是翻译的口气了)

  第一种方式:XML + XSLT

  数据源是XML,由开发人员提供,XSL可以一开始由开发人员写,以后由前端参与开发和维护。

  T的过程可以在服务端进行,优点是搜索引擎友好,缺点是服务端压力大。

  T的过程也可以在客户端进行,和服务端进行的优缺点互反。

  这种方式比较适用访问量大(特别是客户端进行T)、交互简单的系统,比如论坛,因为服务端只需要提供数据源,而XSL则是静态资源可以在客户端缓存。

  这种方式的优点是,如果前端直接维护XSL,那么在开发不介入的情况下可以直接对页面布局等进行调整,并且可以做到最好的性能。

  而缺点则是,学习成本比较大,如果在客户端进行转换那么搜索引擎支持会不好,而且XSL相对比较难以维护,实现复杂逻辑成本比较大。

  第二种方式:ASP.NET Webform

  最常见的方式,基于控件,由控件生成HTML,开发也可以直接操作服务端控件。这是一种开发人员主导的方式。

这是一种普适的方式,什么应用都可以支持。缺点是不太利于实现UI快速改动,前端很难参与aspx的维护,因为很多UI都是由控件进行,开发人员很可能在后端操作控件进行一些UI的修改。

  第三种方式:纯粹的javascript + 服务端数据源

  所有和呈现相关的逻辑,都由javascript来写(可以依赖jquery,jtemplate等组件),以AJAX方式从服务端获取数据进行数据的填充和一些业务逻辑的实现。

  这是一种前端主导的方式,会写大量的脚本来实现逻辑,需要的数据从服务端获取。

  这种方式比较适合前端互动比较丰富的应用,比如网页游戏。

  优点是,前端对页面的布局、行为有很大的自主权,并且服务端的压力也比较小。

  缺点是,需要写大量的脚本代码,难度大并且容易出错,并且容易出现安全问题。

  第四种方式:模板引擎

  模板引擎通过基于HTML的模板加上各种预定义的占位符来实现数据的动态填充。在保证了UI灵活性的同时也保证了非常高的性能。

  这种方式对于需要有多界面的新闻系统、博客系统,甚至每一个版块布局都不同的论坛系统来说很适用。

  虽然足够灵活,但是前端和开发的配合还是双向的,也就是前端还是需要知道开发提供的数据结构。

  并且,对于交互比较复杂的应用来说,可能需要用模板引擎预定义的脚本来写很多逻辑,造成难以维护。

  第五种方式:ASP.NET MVC

  这同样是一种普适的方式,只不过更适用于面向互联网的网站,而不是面向局域网的内部应用。

  虽然MVC已经在UI和UI逻辑方面实现了很好的分离,但是我觉得还是很难在开发没有介入的情况下直接对页面的布局等进行调整。

  第六种方式:在服务端为HTML的适当位置动态注入数据

  这是一种比较新颖的方式,在服务端加载HTML作为模板文件,然后写代码修改HTML中的dom元素,为元素填充数据。

比如一个a.html配合a.shtml,a.shtml(httphandler)加载a.html然后解析HTML文档,从数据库加在数据填充到HTML中,输出这个HTML。

  前端提供的HTML文件可以直接使用,不需要加任何模板标签,不需要加任何控件,所有数据由代码填充进去。

  可以像jquery一样支持各种方式来搜索数据的填充路径,也可以把一段html作为模板,循环复制成一个列表页面。

  优点是,前端维护HTML/脚本/样式,开发人员写代码生成数据,填充数据,彻底的分离。

  缺点是,前端不能改变一些涉及到路径的元素(比如我们通过className来定位元素,前端改变了className就不行),还有性能可能会差一点。

  第七种方式:在服务端为HTML动态载入数据,在客户端注入数据

  还是以HTML作为模板文件,只不过这个数据组装的过程在客户端进行,相比第六种方式有更好的性能。

  也就是服务端不用解析HTML文档,直接为HTML文档中加上一个JSON数据片段,这些数据是这个页面需要的所有数据。

  然后,在服务端使用ScriptSharp等框架编译时生成填充数据到HTML的脚本,这个填充过程由客户端执行。

  代码还是像第六种方式一样写,但是这段代码会完成两个工作,一个是把部分代码生成脚本文件,第二是把部分代码生成json数据写到页面上。

  好像还没看到过有现成的框架是这么干的,难道这种方式不太实用?

  其实演变一下的话,也可以是直接写脚本,不用ScriptSharp来生成,但是在服务端写的很大的一个好处是可以直接利用强类型的实体。

  想象一下这样的伪代码:Document.FindElement(“path”).Fill(product.Take(10), product => product.Name);

这样,product这个List的前10项就会以json输出在页面上,而定位元素以及赋值的代码也会以jquery/javascript代码输出在页面上。

  优缺点和第六种方式一致。

  第八种方式:由服务端生成HTML

  这是一种比较极端的方式,所有HTML由代码生成,可以拼字符串也可以利用SharpDom之类的框架。

适合UI随着业务逻辑变化非常大的流程系统,或者一些模板生成工具,不太适合业务系统。

在XSL/XSLT中实现随机排序

和数据库排序一样,XSL/XSLT也可以实现随机排序,原理也很简单,下面就是代码。

< xml version=”1.0″ >
<xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform
  xmlns:msxsl=”urn:schemas-microsoft-com:xslt”
  xmlns:eMeng=”http://dotnet.aspx.cc/
  version=”1.0″>
<msxsl:script language=”JavaScript” implements-prefix=”eMeng”>
 function Random() {
  return Math.random();
 }
</msxsl:script>

<xsl:template match=”/”>
<xsl:for-each select=”/*/node()”>
<xsl:sort select=”eMeng:Random()”/>
<xsl:value-of select=”.”/>
<br/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

 

acl之xml流解析器

  现在 XML 解析器比较多,其实本没有必要在ACL中添加新的XML解析库,象JAVA、PHP、C#的开发者大都习惯于使用XML数据,因为他们有比较好用的XML解析库,而C/C++的程序员可能使用非XML数据的情形比较多,数据格式也各式各样。当然,如果C/C++程序员使用XML数据也有一些成熟的XML解析库,最丰富的解析库之一如libxml2,比较小型的如tinyxml等,这些库功能都比较丰富,但对流的支持可能有些局限性,象libxml2,接口使用起来还比较复杂,也不太容易掌握。经过再三考虑,决定在ACL中添加XML解析库,希望能满足如下功能:

  1、接口丰富而简单(看似是矛盾的,呵呵)

  2、很好地支持流的处理(可以支持同步网络流及异步网络流)

  3、可以比较容易进行查询、添加、删除、遍历等操作,最好能象JS一样进行操作。

  经过几个周末努力,终于算是完成了XML解析库并添加进ACL中。为了很好支持异步流,该XML库采用了有限状态机的方式(效率虽可能不是最好,但也不会差),下面对主要的编程接口进行介绍。

 

一、API 介绍

1、XML容器对象的创建、XML解析树的生成以及XML容器对象的释放

 

/**
* 创建一个 xml 容器对象
* @return {ACL_XML*} 新创建的 xml 对象
*/
ACL_API ACL_XML *acl_xml_alloc(void);

  当进行XML解析前,首先必须调用 acl_xml_alloc 创建一个XML容易对象。

 

/**
 * 解析 xml 数据, 并持续地自动生成 xml 结点树
 * @param xml {ACL_XML*} xml 对象
 * @param data {const char*} 以 '\0' 结尾的数据字符串, 可以是完整的 xml 数据;
 *  也可以是不完整的 xml 数据, 允许循环调用此函数, 将不完整数据持续地输入
 */
ACL_API void acl_xml_parse(ACL_XML *xml, const char *data);

  将 xml 源数据输入,通过 acl_xml_parser进行解析,因为该函数支持数据状态缓冲(采用有限状态机的好处),所以可以非常容易地支持流数据。

 

/**
 * 释放一个 xml 对象, 同时释放该对象里容纳的所有 xml 结点
 * @param xml {ACL_XML*} xml 对象
 */
ACL_API int acl_xml_free(ACL_XML *xml);

  最后需要调用 acl_xml_free 来释放 XML 容易对象。

 

2、XML数据结点的查询

  XML数据结点的查询非常方便,有点类似于JAVASCRIPT中的方式(这也是作者的本意,如果象libxml2那样估计别人用起来就会比较麻烦)。在ACL的XML库里提供了非常丰富的查询方式,如下:

/**
 * 从 xml 对象中获得所有的与所给标签名相同的 xml 结点的集合
 * @param xml {ACL_XML*} xml 对象
 * @param tag {const char*} 标签名称
 * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则
 *  表示没有符合条件的 xml 结点
 */
ACL_API ACL_ARRAY *acl_xml_getElementsByTagName(ACL_XML *xml, const char *tag);

 

/**
 * 从 xml 对象中获得所有给定属性名及属性值的 xml 结点元素集合
 * @param xml {ACL_XML*} xml 对象
 * @param name {const char*} 属性名
 * @param value {const char*} 属性值
 * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则
 *  表示没有符合条件的 xml 结点
 */
ACL_API ACL_ARRAY *acl_xml_getElementsByAttr(ACL_XML *xml,
	const char *name, const char *value);

 

/**
 * 从 xml 对象中获得所有的与给定属性名 name 的属性值相同的 xml 结点元素集合
 * @param xml {ACL_XML*} xml 对象
 * @param value {const char*} 属性名为 name 的属性值
 * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则
 *  表示没有符合条件的 xml 结点
 */
ACL_API ACL_ARRAY *acl_xml_getElementsByName(ACL_XML *xml, const char *value);

 

  以上三个函数的返回结果都是一个数组对象(ACL中数组对象库的使用请参考ACL中的 acl_array.h),这些数组元素的类型为ACL_XML_NODE,提取这些数组元素的方式如下:

 

void test(const char *xml_data)
{
  ACL_XML *xml = acl_xml_create();
  ACL_ARRAY *a;
  ACL_ITER iter;

  acl_xml_parse(xml, xml_data);

  a = acl_xml_getElementsByTagName(xml, "user");
  if (a) {
    acl_foreach(iter, a) {
      ACL_XML_NODE *node = (ACL_XML_NODE*) iter.data;
      printf("tagname: %s\n", acl_vstring_str(node->ltag));
    }
    /* 释放数组对象 */
    acl_xml_free_array(a);
  }

  acl_xml_free(xml);
}

   最后,得注意使用 acl_xml_free_array 来释放数组结果集。

 

  另外,还有一些函数用来获得单个结果,如下:

/**
 * 从 xml 对象中获得指定 id 值的 xml 结点元素的某个属性对象
 * @param xml {ACL_XML*} xml 对象
 * @param id {const char*} id 值
 * @return {ACL_XML_ATTR*} 某 xml 结点的某个属性对象, 若返回 NULL 则表示
 *  没有符合条件的属性
 */
ACL_API ACL_XML_ATTR *acl_xml_getAttrById(ACL_XML *xml, const char *id);

/**
 * 从 xml 对象中获得指定 id 值的 xml 结点元素的某个属性值
 * @param xml {ACL_XML*} xml 对象
 * @param id {const char*} id 值
 * @return {const char*} 某 xml 结点的某个属性值, 若返回 NULL 则表示没有符合
 *  条件的属性
 */
ACL_API const char *acl_xml_getAttrValueById(ACL_XML *xml, const char *id);

/**
 * 从 xml 对象中获得指定 id 值的 xml 结点元素
 * @param xml {ACL_XML*} xml 对象
 * @param id {const char*} id 值
 * @return {ACL_XML_NODE*} xml 结点元素, 若返回 NULL 则表示没有符合
 *  条件的 xml 结点
 */
ACL_API ACL_XML_NODE *acl_xml_getElementById(ACL_XML *xml, const char *id);

/**
 * 从 xml 结点中获得指定属性名的属性对象
 * @param node {ACL_XML_NODE*} xml 结点
 * @param name {const char*} 属性名称
 * @return {ACL_XML_ATTR*} 属性对象, 为空表示不存在
 */
ACL_API ACL_XML_ATTR *acl_xml_getElementAttr(ACL_XML_NODE *node, const char *name);

/**
 * 从 xml 结点中获得指定属性名的属性值
 * @param node {ACL_XML_NODE*} xml 结点
 * @param name {const char*} 属性名称
 * @return {const char*} 属性值, 为空表示不存在
 */
ACL_API const char *acl_xml_getElementAttrVal(ACL_XML_NODE *node, const char *name);

  这些查询接口也非常类似于JAVASCRIPT的查询方式。因为查询结果具有唯一性,所以仅返回一个结果。

 

3、XML树结点的遍历

  XML树结点的遍历遵循ACL框架库中定义的统一遍历方式,所以遍历XML树也非常容易,示例如下:

ACL_XML *xml;
ACL_XML_NODE *node;
ACL_ITER iter;

/*......*/
/* 假设 XML 解析树已经创建完毕 */

/* 遍历整个XML容器对象的所有数据结点 */
acl_foreach(iter, xml) {
  node = (ACL_XML_NODE*) iter.data;
  printf("tagname: %s, text: %s\n", acl_vstring_str(node->ltag),
    acl_vstring_str(node->text));
}

/* 遍历某个XML结点的下一级子结点 */
node = acl_xml_getElementById(xml, "id_test");
if (node) {
  acl_foreach(iter, node) {
    ACL_XML_NODE *node2 = (ACL_XML_NODE*) iter.data;
    printf("tagname: %s, text: %s\n", acl_vstring_str(node->ltag),
        acl_vstring_str(node->text));
  }
}

 

4、其它函数

/**
 * 从 xml 结点删除某个属性对象, 如果该属性为 id 属性, 则同时会从 xml->id_table 中删除
 * @param node {ACL_XML_NODE*} xml 结点
 * @param name {const char*} 属性名称
 * @return {int} 0 表示删除成功, -1: 表示删除失败(有可能是该属性不存在)
 */
ACL_API int acl_xml_removeElementAttr(ACL_XML_NODE *node, const char *name);

/**
 * 给 xml 结点添加属性, 如果该属性名已存在, 则用新的属性值替换其属性值, 否则
 * 创建并添加新的属性对象
 * @param node {ACL_XML_NODE*} xml 结点
 * @param name {const char*} 属性名称
 * @param value {const char*} 属性值
 * @return {ACL_XML_ATTR*} 返回该属性对象(有可能是原来的, 也有可能是新的)
 */
ACL_API ACL_XML_ATTR *acl_xml_addElementAttr(ACL_XML_NODE *node,
        const char *name, const char *value);

/**
 * 将 xml 对象转储于指定流中
 * @param xml {ACL_XML*} xml 对象
 * @param fp {ACL_VSTREAM*} 流对象
 */
ACL_API void acl_xml_dump(ACL_XML *xml, ACL_VSTREAM *fp);

 

   当然,还有更多的函数未列出,以上仅可能是用户在使用XML库过程中常用的函数接口。

 

二、举例

    下面举一个完整的例子以结束本文。

#include "lib_acl.h"

#define STR	acl_vstring_str

static void parse_xml(int once)
{
	ACL_XML *xml = acl_xml_alloc();
	const char *data =
		"< xml version=\"1.0\" >\r\n"
		"< xml-stylesheet type=\"text/xsl\"\r\n"
		"\thref=\"http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl\" >\r\n"
		"\t<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.1.2//EN\"\r\n"
		"\t\"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd\" [\r\n"
		"	<!ENTITY xmllint \"<command>xmllint</command>\">\r\n"
		"]>\r\n"
		"<root name='root' id='root_id_1'>\r\n"
		"	<user name='user1' value='zsx1' id='id1'> user zsx1 </user>\r\n"
		"	<user name='user2' value='zsx2' id='id2'> user zsx2 \r\n"
		"		<age year='1972'>my age</age>\r\n"
		"	</user>\r\n"
		"	<user name='user3' value='zsx3' id='id3'> user zsx3 </user>\r\n"
		"</root>\r\n"
		"<root name='root' id='root_id_2'>\r\n"
		"	<user name='user1' value='zsx1' id='id1'> user zsx1 </user>\r\n"
		"	<user name='user2' value='zsx2' id='id2'> user zsx2 \r\n"
		"		<!-- date should be the date of the latest change or the release version -->\r\n"
		"		<age year='1972'>my age</age>\r\n"
		"	</user>\r\n"
		"	<user name='user3' value='zsx3' id='id3'> user zsx3 </user>\r\n"
		"</root>\r\n"
		"<root name = 'root2' id = 'root_id_3'>\r\n"
		"	<user name = 'user2_1' value = 'zsx2_1' id = 'id2_1'> user zsx2_1 </user>\r\n"
		"	<user name = 'user2_2' value = 'zsx2_2' id = 'id2_2'> user zsx2_2 </user>\r\n"
		"	<user name = 'user2_3' value = 'zsx2_3' id = 'id2_3'> user zsx2_3 \r\n"
		"		<age year = '1978' month = '12' day = '11'> bao bao </age>\r\n"
		"	</user>\r\n"
		"	<!-- still a bit buggy output, will talk to docbook-xsl upstream to fix this -->\r\n"
		"	<!-- <releaseinfo>This is release 0.5 of the xmllint Manual.</releaseinfo> -->\r\n"
		"	<!-- <edition>0.5</edition> -->\r\n"
		"	<user name = 'user2_2' value = 'zsx2_2' id = 'id2_4'> user zsx2_2 </user>\r\n"
		"</root>\r\n";
	const char *ptr;
	ACL_ITER iter1;
	int   i, total, left;
	ACL_ARRAY *a;
	ACL_XML_NODE *pnode;

	ptr = data;
	if (once) {
		/* 一次性地分析完整 xml 数据 */
		acl_xml_parse(xml, ptr);
	} else {
		/* 每次仅输入一个字节来分析 xml 数据 */
		while (*ptr != 0) {
			char  ch2[2];

			ch2[0] = *ptr;
			ch2[1] = 0;
			acl_xml_parse(xml, ch2);
			ptr++;
		}
	}

	if (acl_xml_is_complete(xml, "root")) {
		printf(">> Yes, the xml complete\n");
	} else {
		printf(">> No, the xml not complete\n");
	}

	total = xml->node_cnt;

	/* 遍历根结点的一级子结点 */
	acl_foreach(iter1, xml->root) {
		ACL_ITER iter2;

		ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data;
		printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text));

		/* 遍历一级子结点的二级子结点 */
		acl_foreach(iter2, node) {
			ACL_ITER iter3;
			ACL_XML_NODE *node2 = (ACL_XML_NODE*) iter2.data;

			printf("\ttag> %s, text: %s\n", STR(node2->ltag), STR(node2->text));

			/* 遍历二级子结点的属性 */
			acl_foreach(iter3, node2->attr_list) {
				ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter3.data;
				printf("\t\tattr> %s: %s\n", STR(attr->name), STR(attr->value));
			}
		}
	}

	printf("----------------------------------------------------\n");

	/* 从根结点开始遍历 xml 对象的所有结点 */

	acl_foreach(iter1, xml) {
		ACL_ITER iter2;
		ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data;

		for (i = 1; i < node->depth; i++) {
			printf("\t");
		}

		printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text));

		/* 遍历 xml 结点的属性 */
		acl_foreach(iter2, node->attr_list) {
			ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter2.data;

			for (i = 1; i < node->depth; i++) {
				printf("\t");
			}

			printf("\tattr> %s: %s\n", STR(attr->name), STR(attr->value));
		}
	}

	/* 根据标签名获得 xml 结点集合 */

	printf("--------- acl_xml_getElementsByTagName ----------\n");
	a = acl_xml_getElementsByTagName(xml, "user");
	if (a) {
		/* 遍历结果集 */
		acl_foreach(iter1, a) {
			ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data;
			printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text));
		}
		/* 释放数组对象 */
		acl_xml_free_array(a);
	}


	/* 查询属性名为 name, 属性值为 user2_1 的所有 xml 结点的集合 */

	printf("--------- acl_xml_getElementsByName ------------\n");
	a = acl_xml_getElementsByName(xml, "user2_1");
	if (a) {
		/* 遍历结果集 */
		acl_foreach(iter1, a) {
			ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data;
			printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text));
		}
		/* 释放数组对象 */
		acl_xml_free_array(a);
	}

	/* 查询属性名为 id, 属性值为 id2_2 的所有 xml 结点集合 */
	printf("----------- acl_xml_getElementById -------------\n");
	pnode = acl_xml_getElementById(xml, "id2_2");
	if (pnode) {
		printf("tag> %s, text: %s\n", STR(pnode->ltag), STR(pnode->text));
		/* 遍历该 xml 结点的属性 */
		acl_foreach(iter1, pnode->attr_list) {
			ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data;
			printf("\tattr_name: %s, attr_value: %s\n",
				STR(attr->name), STR(attr->value));
		}

		pnode = acl_xml_node_next(pnode);
		printf("----------------- the id2_2's next node is ---------------------\n");
		if (pnode) {
			printf("-------------- walk node -------------------\n");
			/* 遍历该 xml 结点的属性 */
			acl_foreach(iter1, pnode->attr_list) {
				ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data;
				printf("\tattr_name: %s, attr_value: %s\n",
						STR(attr->name), STR(attr->value));
			}

		} else {
			printf("-------------- null node -------------------\n");
		}
	}

	pnode = acl_xml_getElementById(xml, "id2_3");
	if (pnode) {
		int   ndel = 0, node_cnt;

		/* 删除该结点及其子结点 */
		printf(">>>before delete %s, total: %d\n", STR(pnode->ltag), xml->node_cnt);
		ndel = acl_xml_node_delete(pnode);
		node_cnt = xml->node_cnt;
		printf(">>>after delete id2_3(%d deleted), total: %d\n", ndel, node_cnt);
	}

	acl_foreach(iter1, xml) {
		ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data;
		printf(">>tag: %s\n", STR(node->ltag));
	}

	pnode = acl_xml_getElementById(xml, "id2_3");
	if (pnode) {
		printf("-------------- walk %s node -------------------\n", STR(pnode->ltag));
		/* 遍历该 xml 结点的属性 */
		acl_foreach(iter1, pnode->attr_list) {
			ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data;
			printf("\tattr_name: %s, attr_value: %s\n",
					STR(attr->name), STR(attr->value));
		}
	} else {
		printf("---- the id2_3 be deleted----\n");
	}

	/* 释放 xml 对象 */
	left = acl_xml_free(xml);
	printf("free all node ok, total(%d), left is: %d\n", total, left);
}

static void parse_xml_file(const char *filepath, int once)
{
	char *data = acl_vstream_loadfile(filepath);
	ACL_VSTREAM *fp;
	char *ptr;
	ACL_XML *xml;
	struct timeval  begin, end;

	if (data == NULL)
		return;

	gettimeofday(&begin, NULL);

	/* 创建 xml 对象 */
	xml = acl_xml_alloc();

	ptr = data;

	if (once) {
		/* 一次性地分析完整 xml 数据 */
		acl_xml_parse(xml, ptr);
	} else {
		/* 每次仅输入一个字节来分析 xml 数据 */
		while (*ptr) {
			char  ch2[2];

			ch2[0] = *ptr;
			ch2[1] = 0;
			acl_xml_parse(xml, ch2);
			ptr++;
		}
	}

	gettimeofday(&end, NULL);

	printf("------ok, time: %ld seconds, %ld microseconds -------\r\n",
		end.tv_sec - begin.tv_sec, end.tv_usec - begin.tv_usec);


	fp = acl_vstream_fopen("dump.txt", O_RDWR | O_CREAT | O_TRUNC, 0600, 4096);

	/* 将 xml 对象转储至指定流中 */
	acl_xml_dump(xml, fp);

	acl_vstream_fclose(fp);
	acl_xml_free(xml);
	acl_myfree(data);
}

static void usage(const char *procname)
{
	printf("usage: %s -h[help] -f {xml_file} -s[parse once]\n", procname);
}

int main(int argc, char *argv[])
{
	int   ch, once = 0;
	char  filepath[256];

	acl_init();
	snprintf(filepath, sizeof(filepath), "xmlcatalog_man.xml");

	while ((ch = getopt(argc, argv, "hf:s")) > 0) {
		switch (ch) {
		case 'h':
			usage(argv[0]);
			return (0);
		case 'f':
			snprintf(filepath, sizeof(filepath), "%s", optarg);
			break;
		case 's':
			once = 1;
			break;
		default:
			break;
		}
	}

	parse_xml(once);
	parse_xml_file(filepath, once);

#ifdef	ACL_MS_WINDOWS
	printf("ok, enter any key to exit ...\n");
	getchar();
#endif
	return 0;
}

个人微博:http://weibo.com/zsxxsz

javascript操作xml

avascript操作xml 转自soar的专栏

=======================================================================

1.xml文件如下:

< xml version=”1.0″ encoding=”UTF-8″ >
<zip>
<city>
mycity</city>
<state>mystate</state>
</zip>

2.读此xml的javascript例子:

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>
<html>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
<title>Insert title here</title>
<script language=”javascript”  type=”text/javascript”>

var url = “NewFile.xml”;
String.prototype.Trim = function() { return this.replace(/(^\s*)|(\s*$)/g, “”); }

var xmlDoc;

 var moz = (typeof document.implementation != ‘undefined’)
   && (typeof document.implementation.createDocument != ‘undefined’);
 var ie = (typeof window.ActiveXObject != ‘undefined’);

function importXML(file) {

 if (moz) {
   xmlDoc = document.implementation.createDocument(“”, “doc”, null);

 } else if (ie) {
   xmlDoc = new ActiveXObject(“MSXML2.DOMDocument.3.0”);
   xmlDoc.async = false;
   while(xmlDoc.readyState != 4) {};
 }
 
 xmlDoc.load(file);
}
importXML(url);

function updateCityState(){
if (moz) {
 var zip = xmlDoc.getElementsByTagName(“zip”)[0];
 var city;
    var _city = zip.getElementsByTagName(“city”)[0].firstChild.nodeValue;
      if (_city)   city = _city.Trim();
     
     var state;
     var _state=zip.getElementsByTagName(“state”)[0].firstChild.nodeValue;
     if(_state) state = _state.Trim();

      document.getElementById(‘city’).value = city;
      document.getElementById(‘state’).value = state;
     
} else if (ie) {
    var city;
    var _city = xmlDoc.selectSingleNode(“/zip/city”);
      if (_city) city = _city.text;
     var state;
     var _state=xmlDoc.selectSingleNode(“/zip/state”);
     if(_state) state = _state.text;
       document.getElementById(‘city’).value = city;
      document.getElementById(‘state’).value = state; 
  }   
}
</script>
</head>
<body>
<form action=”post”>

  <p>
  ZIP code:
  <input type=”text” size=”5″ name=”zip” id=”zip” onblur=”updateCityState();” />

  </p>
  City:
  <input type=”text” name=”city” id=”city” />

  State:
  <input type=”text” size=”2″ name=”state” id=”state” />

</form>
</body>
</html>

======================================================================= 

在网络浏览器软件中,可以Internet Explorer (IE)现在是一种标准的软件。可以看到,运行不同版本的Windows操作系统(和很多其他的操作系统)的每一台机器几乎都使用IE。微软已经通过ActiveX控件将IE的功能包含在执行成熟的XML处理技术中。

在本篇文章中,我们将讲述如何在IE中使用ActiveX功能来访问并解析XML文档,由此允许网络冲浪者操纵它们。

网上冲浪
我们以一个标准的顺序文档而开始,如表A所示。这一文档包含简单的顺序数据以提供网络冲浪者浏览之用。不仅仅为了显示这些数据,我们还提供了一个简单的用户界面,网上冲浪都可以使用这一界面来浏览XML文档。

表A: order.xml
< xml version=”1.0″  >
<Order>
<Account>9900234</Account>
<Item id=”1″>
  <SKU>1234</SKU>
  <PricePer>5.95</PricePer>
  <Quantity>100</Quantity>
  <Subtotal>595.00</Subtotal>
  <Description>Super Widget Clamp</Description>
</Item>
<Item id=”2″>
  <SKU>6234</SKU>
  <PricePer>22.00</PricePer>
  <Quantity>10</Quantity>
  <Subtotal>220.00</Subtotal>
  <Description>Mighty Foobar Flange</Description>
</Item>
<Item id=”3″>
  <SKU>9982</SKU>
  <PricePer>2.50</PricePer>
  <Quantity>1000</Quantity>
  <Subtotal>2500.00</Subtotal>
  <Description>Deluxe Doohickie</Description>
</Item>
<Item id=”4″>
  <SKU>3256</SKU>
  <PricePer>389.00</PricePer>
  <Quantity>1</Quantity>
  <Subtotal>389.00</Subtotal>
  <Description>Muckalucket Bucket</Description>
</Item>
<NumberItems>1111</NumberItems>
<Total>3704.00</Total>
<OrderDate>07/07/2002</OrderDate>
<OrderNumber>8876</OrderNumber>
</Order>

我们使用一个网络表单以访问这一XML文档,这一表单将显示SKU,价格,数量,各部分的小计,以及顺序中的每一选项的描述。我们的表单还包含向前和向后浏览选项的按钮。

网页的构成
网页的重要部分是在于表单,我们将使用一个表以易读的方式在屏幕上显示。下面是显示HTML表的代码片段:

<form>
<table border=”0″>
  <tr><td>SKU</td><td><input type=”text” name=”SKU”></td></tr>
  <tr><td>Price</td><td><input type=”text” name=”Price”></td></tr>
  <tr><td>Quantity</td><td><input type=”text” name=”Quantity”></td></tr>
  <tr><td>Total</td><td><input type=”text” name=”Total”></td></tr>
  <tr><td>Description</td><td><input type=”text”
name=”Description”></td></tr>
</table>
<input type=”button” value=” << ” onClick=”getDataPrev();”> <input
type=”button” value=” >> ” onClick=”getDataNext();”>
</form>

请注意到,我们在表的下面包含了两个按钮,即通过getDataNext() 和getDataPrev()函数来浏览前一个和后一个的记录,这也是我们所要讨论的问题。

脚本
其实,我们网页的实质部分不是在于表单,而是在于控制表单的脚本。在我们的脚本中包括四个部分。首先,我们通过载入XML文档而初始化网页。第二部分是导航到下一个记录。第三步是导航到前一个记录。第四部分是从XML文档中提取单一的值。表B显示了我们的网页的全部内容。

表B: jsxml.html
<html>
<head>
  <script language=”JavaScript”>
<!–
  vari = -1;
  varorderDoc = new ActiveXObject(“MSXML2.DOMDocument.3.0”);
  orderDoc.load(“order.xml”);
  var items = orderDoc.selectNodes(“/Order/Item”);
   
  function getNode(doc, xpath) {
   varretval = “”;
   var value = doc.selectSingleNode(xpath);
   if (value) retval = value.text;
   return retval;
  }
 
  function getDataNext() {
   i++;
   if (i > items.length – 1) i = 0;

   document.forms[0].SKU.value = getNode(orderDoc, “/Order/Item[” +
i + “]/SKU”);
   document.forms[0].Price.value = getNode(orderDoc, “/Order/Item[“
+ i + “]/PricePer”);
   document.forms[0].Quantity.value = getNode(orderDoc,
“/Order/Item[” + i + “]/Quantity”);
   document.forms[0].Total.value = getNode(orderDoc, “/Order/Item[“
+ i + “]/Subtotal”);
   document.forms[0].Description.value = getNode(orderDoc,
“/Order/Item[” + i + “]/Description”);
  }
 
  function getDataPrev() {
   i–;
   if (i < 0) i = items.length – 1;
  
   document.forms[0].SKU.value = getNode(orderDoc, “/Order/Item[” +
i + “]/SKU”);
   document.forms[0].Price.value = getNode(orderDoc, “/Order/Item[“
+ i + “]/PricePer”);
   document.forms[0].Quantity.value = getNode(orderDoc,
“/Order/Item[” + i + “]/Quantity”);
   document.forms[0].Total.value = getNode(orderDoc, “/Order/Item[“
+ i + “]/Subtotal”);
   document.forms[0].Description.value = getNode(orderDoc,
“/Order/Item[” + i + “]/Description”);
  }
 
// –>
  </script>
</head>
<body onload=”getDataNext()”>
<h2>XML order Database</h2>
<form>
<table border=”0″>
  <tr><td>SKU</td><td><input type=”text” name=”SKU”></td></tr>
  <tr><td>Price</td><td><input type=”text” name=”Price”></td></tr>
  <tr><td>Quantity</td><td><input type=”text”
name=”Quantity”></td></tr>
  <tr><td>Total</td><td><input type=”text” name=”Total”></td></tr>
  <tr><td>Description</td><td><input type=”text”
name=”Description”></td></tr>
</table>
<input type=”button” value=” << ” onClick=”getDataPrev();”> <input
type=”button” value=” >> ” onClick=”getDataNext();”>
</form>
</body>
</html>

运行
这一网页将传入并运行脚本的初始化。你一定确保order.xml文档与jsxml.html在相同的相同的路径上。

初始化部分将一个新的ActiveX对象例示为MSXML2.DOMDocument.3.0对象类型,然后脚本传入order.xml文档到内存中,并选择所有的/Order/Item节点。我们使用/Order/Item节点以识别文档已经包含的选项。

文档中的<body>标准有一个onLoad属性,这一属性能够使得网页调用getDataNext()而初始化。这一功能可用于从XML文档中获得下一个值并显示在表单中。我们使用一个简单的索引来访问特定的选项。

向前(>>)和向后(<<)按钮都使用相同的机制。首先响应onClick事件而调用getDataNext() 或者getDataPrev(),这两个函数使用了逻辑方法以避免文档以外的范围访问我们的记录。
==========================================================================

<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>

==============================================================================

一般从服务端的返回可以得到一个XML对象。
例如服务器返回的:XMLHttpRequest.ResponseXML
这里的XMLHttpRequest就是ajax的核心对象。
在IE下可以这样创建:xmlHttp = new ActiveXObject(“Microsoft.XMLHTTP”).
javascript操作XML先创建一个XML DOM对象:var dom = new ActiveXObject(“Microsoft.XMLDOM”);
然后dom.loadXML(ResponseXML)就ok了。
接下来就可以操作xml,获取内容了。
一些常用的函数如下(一些在网上收集的,一些时平时老大教的):
Microsoft.XMLDOM 对象常用的属性:
1、attributes 属性,返回当前节点的属性列表
2、childNodes 属性,返回当前节点的所有子节点列表
3、documentElement 属性,返回xml文件的根节点,通过Microsoft.XMLDOM对象名来调用
4、firstChild 属性、lastChild 属性,返回当前节点的第一个子(最后一个)元素(如果没有子节点是不是返回
第一个属性?)
5、nextSibling (previousSibling )属性,下一个兄弟节点。
6、nodeName 属性,返回节点的标签名字
7、nodeValue 属性,传回指定节点相关的文字(不是属性,就是*号的这个内容 **)
8、ownerDocument 属性,根节点
9、parentNode 属性,传回目前节点的父节点。只能应用在有父节点的节点中。
搞一个例子:
function Add()
{
var dom = new ActiveXObject(“Microsoft.XMLDOM”);
dom.loadXML(ret);
if (dom.documentElement != null)
{
var nodes = dom.documentElement.selectNodes(“//SelectItem”); //得到根节点下所有SelectItem节点
if (nodes != null)
{
for(var i=0;i
一些常用的函数:
1、AppendChild 方法,加上一个节点当作指定节点最后的子节点。
2、cloneNode(deep)方法,deep 是一个布尔值。如果为true,此节点会复制以指定节点发展出去的所有节
点。如果是false,只有指定的节点和它的属性被复制。
3、createAttribute(name)方法,建立一个指定名称的属性。
4、createElement 方法,建立一个指定名称的元素。
5、xmlDocument.createNode(type, name, nameSpaceURI);type 用来确认要被建立的节点型态,name 是一个字符
串来确认新节点的名称,命名空间的前缀则是选择性的。nameSpaceURI 是一个定义命名空间URI 的字
符串。如果前缀被包含在名称参数中,此节点会在nameSpaceURI 的内文中以指定的前缀建立。如果不
包含前缀,指定的命名空间会被视为预设的命名空间。
6、getElementsByTagName 方法,传回指定名称的元素集合。
7、haschildnodes 方法,要解释吗?
8、insertBefore 方法,在指定的节点前插入一个子节点。xmlDocumentNode.insertBefore
(newChild,refChild);refChild 是参照节点的地址。新子节点被插到参照节点之前。如果refChild 参数没有包含
在内,新的子节点会被插到子节点列表的末端。
9、load 方法和loadXML 方法,前这从url,后者从字符串片断。
10、nodeFromID 方法,传回节点ID 符合指定值的节点。
11、removeChild 方法和replaceChild(newChild,oldChild),顾名思义
12、selectNodes和selectSingleNode 方法,传回所有符合提供样式的节点。参数为一包含XSL 样式的字符串。
以下收集了一些MSDN的例子
(1)
var xmlDoc = new ActiveXObject(“Msxml2.DOMDocument.3.0”);
var rootElement=xmlDoc.createElement(“memo”);
xmlDoc.appendChild(rootElement);(2) var xmlDoc = new ActiveXObject(“Msxml2.DOMDocument.3.0”);
var rootElement=xmlDoc.createElement(“memo”);
rootElement.setAttribute(“author”, “Pat Coleman”); //属性author的值为Pat Coleman
xmlDoc.appendChild(rootElement);
(3) var xmlDoc = new ActiveXObject(“Msxml2.DOMDocument.3.0”);
var rootElement=xmlDoc.createElement(“memo”);
var memoAttribute=xmlDoc.createAttribute(“author”);
var memoAttributeText=xmlDoc.createTextNode(“Pat Coleman”);
memoAttribute.appendChild(memoAttributeText);
rootElement.setAttributeNode(memoAttribute);
xmlDoc.appendChild(rootElement);
//这个例子和(2)同样效果,但是用不同的方法,这里把attribute也当做一个节点,attribute node的
子节点只可以是textnode,所以这里要先创建一个textnode在赋给他。
(4)
var xmlDoc = new ActiveXObject(“Msxml2.DOMDocument.3.0”);
var rootElement=xmlDoc.createElement(“memo”); //创建一个元素
var memoAttribute=xmlDoc.createAttribute(“author”); //创建一个属性
var memoAttributeText=xmlDoc.createTextNode(“Pat Coleman”); //创建一个文本节点
var toElement=xmlDoc.createElement(“to”); //再创建一个元素
var toElementText=xmlDoc.createTextNode(“Carole Poland”); //再创建一个文本节点
memoAttribute.appendChild(memoAttributeText);
xmlDoc.appendChild(rootElement);
rootElement.setAttributeNode(memoAttribute);
rootElement.appendChild(toElement);
toElement.appendChild(toElementText);

属性:
attributes
Contains the list of attributes for this node. Read-only.
baseName
*Returns the base name for the name qualified with the namespace. Read-only.
childNodes
Contains a node list containing the children nodes. Read-only.
dataType
*Specifies the data type for this node. Read/write.
definition
*Returns the definition of the node in the document type definition (DTD) or schema. Read-only.
firstChild
Contains the first child of the node. Read-only.
lastChild
Returns the last child node. Read-only.
name
Contains the attribute name. Read-only.
namespaceURI
*Returns the Uniform Resource Identifier (URI) for the namespace. Read-only.
nextSibling
Contains the next sibling of this node in the parent’s child list. Read-only.
nodeName
Contains the qualified name of the element, attribute, or entity reference, or a fixed string for other node types. Read-only.
nodeType
Specifies the XML Document Object Model (DOM) node type, which determines valid values and whether the node can have child nodes. Read-only.
nodeTypedValue
*Contains the node value expressed in its defined data type. Read/write.
nodeTypeString
*Returns the node type in string form. Read-only.
nodeValue
Contains the text associated with the node. Read/write.
ownerDocument
Returns the root of the document that contains the node. Read-only.
parentNode
Contains the parent node. Read-only.
parsed
*Indicates the parsed status of the node and child nodes. Read-only.
prefix
*Returns the namespace prefix. Read-only.
previousSibling
Contains the previous sibling of this node in the parent’s child list. Read-only.
specified
Indicates whether the node (usually an attribute) is explicitly specified or derived from a default value in the document type definition (DTD) or schema. Read-only.
text
Represents the text content of the node or the concatenated text representing the node and its descendants. Read/write.
value
Contains the attribute value. Read/write.
xml
Contains the XML representation of the node and all its descendants. Read-only.
方法:
appendChild
Appends new child node as the last child of this node.
cloneNode
Clones a new node.
hasChildNodes
Provides a fast way to determine whether a node has children.
insertBefore
Inserts a child node to the left of the specified node or at the end of the list.
removeChild
Removes the specified child node from the list of children and returns it.
replaceChild
Replaces the specified old child node with the supplied new child node.
selectNodes
Applies the specified pattern-matching operation to this node’s context and returns the list of matching nodes as IXMLDOMNodeList.
selectSingleNode
Applies the specified pattern-matching operation to this node’s context and returns the first matching node.
transformNode
Processes this node and its children using the supplied XSL Transformations (XSLT) style sheet and returns the resulting transformation.
transformNodeToObject
Processes this node and its children using the supplied XSL Transformations (XSLT) style sheet and returns the resulting transformation in the supplied object.  

Javascript+xsl实现把网页中翻页的Table标签内容导入到excel

JS

 

function getXlsFromTbl(inTblId) {

    try {

        inTblId = "demo";

        var xml = new ActiveXObject("Microsoft.XMLDOM")
        xml.async = false
        xml.load(inTblId + ".xml")

        // Load XSL
        var xsl = new ActiveXObject("Microsoft.XMLDOM")
        xsl.async = false
        xsl.load( inTblId +  ".xsl")
        var d = " " + xml.transformNode(xsl);
        
        //去掉 xml 头
        var arr = d.split(" >");
        //获得文件名
        var fileName = getExcelFileName(inTblId);
        //导出
        doFileExport(fileName, arr[1]);



    }

    catch (e) {

        alert("导出发生异常:" + e.name + "->" + e.description + "!");

    }

}

//获得一个文件名
function getExcelFileName(inTblId) {

    var d = new Date();



    var curYear = d.getYear();

    var curMonth = "" + (d.getMonth() + 1);

    var curDate = "" + d.getDate();

    var curHour = "" + d.getHours();

    var curMinute = "" + d.getMinutes();

    var curSecond = "" + d.getSeconds();



    if (curMonth.length == 1) {

        curMonth = "0" + curMonth;

    }

    if (curDate.length == 1) {

        curDate = "0" + curDate;

    }

    if (curHour.length == 1) {

        curHour = "0" + curHour;

    }

    if (curMinute.length == 1) {

        curMinute = "0" + curMinute;

    }

    if (curSecond.length == 1) {

        curSecond = "0" + curSecond;

    }



    var fileName = inTblId + "_" + curYear + curMonth + curDate + "_"

            + curHour + curMinute + curSecond + ".csv";

    //alert(fileName);

    return fileName;

}

//导出Excel
function doFileExport(inName, inStr) {

    var xlsWin = null;



    if (!!document.all("glbHideFrm")) {

        xlsWin = glbHideFrm;

    }

    else {

        var width = 6;

        var height = 4;

        var openPara = "left=" + (window.screen.width / 2 - width / 2)

                + ",top=" + (window.screen.height / 2 - height / 2)

                + ",scrollbars=no,width=" + width + ",height=" + height;

        xlsWin = window.open("", "_blank", openPara);

    }



    xlsWin.document.write(inStr);

    xlsWin.document.close();

    xlsWin.document.execCommand('Saveas', true, inName);

    xlsWin.close();

}

 

html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title></title>

    <script src="ToExcel.js" type="text/javascript"></script>
</head>
<body>
    <input id="Button1" type="button" onclick="javascript:getXlsFromTbl('demo');" value="button" />
</body>
</html>

 

Xsl

 

xml version="1.0" encoding="utf-16" >

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
     Title&#9;Artist&#9;country&#9;company&#9;price&#9;year&#9;
    <xsl:for-each select="catalog/cd">
      <xsl:value-of select="title"/>&#9;<xsl:value-of select="artist"/>&#9;<xsl:value-of select="country"/>&#9;<xsl:value-of select="company"/>&#9;<xsl:value-of select="price"/>&#9;<xsl:value-of select="year"/>&#9;
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

 

XML

xml version="1.0" encoding="utf-8" >
<catalog>
  <cd>
    <title>Empire Burlesque</title>
    <artist>Bob Dylan</artist>
    <country>USA</country>
    <company>Columbia</company>
    <price>10.90</price>
    <year>1985</year>
  </cd>
  <cd>
  <title>Hide your heart</title> 
  <artist>Bonnie Tyler</artist> 
  <country>UK</country> 
  <company>CBS Records</company> 
  <price>9.90</price> 
  <year>1988</year> 
  </cd>  
</catalog>

JavaWeb开发构想【转载】

http://www.i170.com/Forum/3238
Java Web开发构想
1.背景、形势
能够进行Web开发的编程语言和技术很多

(1) 动态解释语言

PHP; Perl; Python (Zope, Plone); Ruby (Ruby on Rails);

(2) 编译语言

Java; .net

 

Java Web开发远非一枝独秀:

除了受到来自.net 这个重量级对手的最大挑战之外,更受到Zope, Ruby on Rail 等新式轻骑兵的冲击(当然,也继续受到老式轻步兵PHP, Perl的冲击)。

 

官方Java走的是复杂路线,Servlet -> JSP -> Taglib。.net走的也是复杂路线,依靠成熟友好的集成化开发环境取胜。Java阵营好容易应对过来,从纷纭复杂的各种开发框架基础上,发展出了重量级Web开发框架JSF,以及相应的集成化开发环境;渴望以此应对.net的攻势。胜负未分,前途未卜。这时,另一个方向又杀来了新式轻骑Zope, Ruby on Rail。

Python, Ruby等动态解释语言,面向对象特性更好,先天支持 动态绑定、AOP、函数式编程、“编程即配置”等时髦概念。开发速度更快,代码量更小,达到killer级别。

 

传统的HTML Web开发领域里面,Java已经是腹背受敌。领域外也展开了征战,Rich Client Architecture的兴起:AJAX(XMLHttp), Flash RIA, XUL, XAML, Smart Client(以及从前的ActiveX, Applet, Web Start)。

 

Web的发展趋势是 语义Web,最终目的是让整个Web成为一个巨大的数据库。

这意味着,未来的Web应用将更加的面向文本内容数据,更加搜索引擎友好 – Search Engine Friendly.

二进制的客户端插件,如Flash RIA,  ActiveX, Applet, Web Start等,虽然交互性能最好,但不是以文本内容数据为中心,搜索引擎不友好。所以,我只是保持适当关注。我更关注基于文本的UI表现,如HTML, XUL, XAML等。XUL, XAML还没有广泛流行,只是保持一种有兴趣的关注。

当下关注的重点,还是 XHTML + CSS +  Javascript少量的 AJAX(XMLHttp)增加更好的交互性。

 

我一直认为:轻量、简洁、高效 才是硬道理。后面阐述我对Java Web开发的理解和构想。

2. Web开发框架层次概述
从上到下,Web开发框架的层次如下:

(1) HTML, JavaScript, CSS等页面资源。

(2) 页面模板层。

如JSP, Freemarker, Velocity, XSL,fastm等。用来生成HTML, JavaScript, CSS等页面资源。

(3) Web框架。把HTTP Request调度分派到对应的Service Entry。

(4) Business Logic.

(5) O/R Mapping.

(6) JDBC

(7) DB

 

根据我的经验,一个典型的Web应用中的代码比例如下:

页面逻辑约占 50%,商业逻辑约占30%,  O/R 约占20%。

 

但事实上,页面却是最不受重视的部分,从来都被认为是脏活,累活,杂活。典型的开发过程通常是这样:

页面设计人员迅速的用Dreamweaver等生成一堆文本杂乱无章的页面,然后交给JSP程序员加入更加杂乱无章的Java代码和Taglib。

当页面布局风格需要改变的时候,页面设计人员用Dreamweaver等生成一堆新的页面。JSP程序员再重新加入更加杂乱无章的Java代码Taglib。

至于页面中的脚本逻辑调试,更是一门精深的工夫了。

 

根据社会规则,通常来说,工作内容越轻松,收入越高;工作内容越脏月累,收入越低;Web开发也是如此:做着最脏最累的活的页面程序员,工资一般比不上后台业务逻辑程序员。

 

开发框架通常会带来这样的结果:让简单的东西,变得更简单;让复杂的东西,变得更复杂。

这其中的原因在于:

一般来说,一个应用中简单重复的东西占80%,复杂特殊的东西占20%。

简单重复的东西很容易摸清规律,进行包装,通用化。但是,在包装的同时,经常就阻挡住了底层的一些灵活强大的控制能力。在复杂特殊的需求中,确实又需要这些底层控制能力,那么为了绕开框架的限制,付出的努力要比不用框架 大得多。

打个比方,一个比较极端的例子。编译语言比汇编语言的开发效率高很多,但是却无法直接操作寄存器。当需要在编译语言中操作寄存器的时候,就非常的痛苦。比如Java,也许需要JNI,写C代码,还要在C代码里面嵌入汇编。编译、连接都很麻烦。

所以,一个框架的开发效率,就在于这个80%简单 与 20%复杂之间的平衡。

假如,不用框架来开发,简单的80%要消耗 80个资源数,复杂的20%要消耗20个资源数,总资源数是100;使用了某个框架,简单的80%只要消耗10个资源数,复杂的20%要消耗40个资源数,总资源数是50。那么,我们说,这个开发框架是有效率的。

 

我的思路是,同时应对复杂和简单。当然,为了应对复杂,简单的东西可能就应对得不那么好。比如,做这样一个开发框架,简单的80%要消耗20个资源数,复杂的20%要消耗10个资源数,总资源数是30。

这种开发框架是有可能实现的。而且是很有意义的。尤其是在复杂部分的比例提高的时候。越复杂的系统,这种开发框架就越有意义。

 

后面的关于Web各层开发的论述,主要就按照这个“应对复杂、让复杂更简单”的思路展开。

3.页面资源
也许有人会说,页面资源,不就是HTML吗?太简单,太低极了,没劲。Dreamweaver、Frontpage多简单阿。随便找个人来用就可以了。文本内容乱糟糟不要紧,浏览器里面显示出来的效果好看就行。要增加炫的、酷的动画效果,那就写JavaScript呗。写在HTML里面,看看在IE里面能不能运行就可以了呗。

这也正是大多数公司开发页面资源的方式。因为页面的需求变化是最多、最快的,而页面的制作成本很低,人们不愿意在上面投入更多的资源。

 

我的看法是,万丈高楼平地起。应用程序的每一个部分都应该完善管理,结构优美。越是需求变化多的地方,越是脏乱差的地方,越应该加大力度处理好。

 

页面结构方面,Javaeye论坛的Dlee做了很多工作。

 

(1) 在 2005 年我们如何写 JavaScript

http://forum.iteye.com/viewtopic.php t=12973 

 

[quote="Dlee"]

Ten good practices for writing JavaScript in 2005
http://www.bobbyvandersluis.com/articles/goodpractices.php
在这篇文档中提到的“unobtrusive techniques”是需要高度关注的一种技术。
http://www.kryogenix.org/code/browser/aqlists/

 

还有这篇:Unobtrusive Javascript
http://www.onlinetools.org/articles/unobtrusivejavascript/
是主要介绍如何以更有效的方式来写 JavaScript 的。

[/quote]

 

(2)使用 Unordered Lists 制作的下拉菜单和树

http://forum.iteye.com/viewtopic.php t=12995 

 

[quote="Dlee"]

Unobtrusive DHTML, and the power of unordered lists
http://www.kryogenix.org/code/browser/aqlists/

 

我再说一下把页面的 structure、presentation 和 behavior 分离开的意义。一般的人很容易理解把 structure 和 presentation 分离的意义,但是对于为什么需要把 presentation 和 behavior 分离开不是很清楚。
这三部分分离开,页面开发才有可能实现真正的重用,从而最终降低开发和维护的工作量。JS 代码是可以做自动测试的,使用 JsUnit 来做。Web 表示层代码测试困难是公认的,直到今天所有介绍 TDD 的经典教材也没有提出一个好方法。所以我问过一些朋友,都是倾向于不对表示层的代码做自动测试。为什么不做自动测试?没有重用价值的代码值得做自动测试吗?而且我们以前有个误区,认为如果做自动测试,表示层的所有东西都需要测试,其实这个想法是错误的。我们需要做自动测试的仅仅是 behavior 这一部分。以前的测试为什么很困难?就是因为 presentation 和 behavior 没有分离开,我们在 JS 代码中直接操作页面的样式(直接设置元素的 style)。我们不应该再这样做下去,我们应该把 presentation 的工作完全交给 CSS 来做。实现 presentation 和 behavior 的分离有两种方法,通过改变元素的 id 或者使用更通用的方法,通过改变元素的 className。而关于这个 id 或者这个 className 具体的样式在外部的 CSS 文件中设置。JS 文件可以生成新的 structure(createElement,etc.),但是不应该直接改变元素的 style。改变了 style,一切效果你都需要用眼睛看到了才算测试成功,这哪里可以做自动测试?而且假如用户对这个 style 不满意,你还需要去修改 JS 代码。你如果只改变元素的 id 或者 className,做自动测试就要容易得多,你只需要测试最终这个元素的 id 或者 className 是否变成了期望的值。而最终的样式是不是也是你期望的,那是 CSS 文件保证的事情,这只需要在第一次开发 CSS 的时候做一下人工测试就足够了。而这样以来,CSS 文件可以由美工来维护,他完全不需要知道 JS 是什么东西。界面程序员可以去做一些更加重要的事情。

所以在这里我们看到,把 presentation 和 behavior 彻底分离开是做 Web 表示层代码自动测试的关键。把这两部分分离开以后,自动测试的难题就迎刃而解了。再强调一下,只有 behavior 有可能做自动测试,presentation 是不需要也不大可能做自动测试的。

相关资料:
http://www.onlinetools.org/articles/unobtrusivejavascript/cssjsseparation.html 

[/quote]

 

从上面的Dlee的论述和给出的资料。可以看出,页面资源分为三部分:

(1) XHTML。结构,Structure。

XHTML里面的Tag部分只应该包括 <ul> <table> <p> <div><span>等结构布局Tag,或者<strong><emphasis>表示语义的Tag。

XHTML里面不应该包括风格信息,比如字体、颜色、大小、粗细等,也不应该包括<font> <b> <i> <h> 等字体信息。

XHTML里面不应该包括Javascript的定义和调用。

 

(2) JavaScript。行为,behavior。

JavaScritp应该存在于一个独立于XHTML文件的独立文件中。这样可以做自动化单元测试。JavaScript应该只改变HTML DOM的结构和内容,而不应该改变它的风格。

 

(3) CSS。Style,风格。或者说,Presentation,表现。

前面说了,XHTML里面不应该包括JavaScript的调用。那么,XHTML的元素是如何JavaScript事件绑定起来?就是在CSS里面指定的。

当然,众所周知,CSS的本职工作是处理页面风格。

 

页面资源方面,我完全认同Dlee的观点。从技术和资源积累的长远目标看来,这方面的初期投入的回报将是非常丰厚的。

即使将来HTML消亡了,进入了XAML, XUL, RSS时代,这些结构清晰的各部分,重用的可能性都非常巨大。JavaScript + CSS + XML UI的这种经典设计思路,将留存很久。混杂成一团的HTML的命运只能是全盘被抛弃。

4.页面模板层
页面模板层是指Server端运行的用来生成HTML(或JavaScript,CSS)的Server Side Template Engine。

这一层也是著名的脏乱差楼层。著名的HTML的Java代码污染事件,就发生在这个楼层。不仅JSP有这个问题,其他的template, 如freemarker, velocity, tapestry等含有逻辑的脚本,都不同程度上有HTML的Script Logic污染问题。

 

Dlee的做法很美。直接就不要页面模板层,不用Server Side Template Engine。直接用JavaScript更改HTML DOM的结构、内容、数据。同时,会用到少量的浏览器端XSL。

这样带来的结果,Template就是很干净纯粹的HTML,不含有任何Server Side Script。这个效果,和Servier Side Template 的 Jivan,XMLC达到的一样。只是一个是在浏览器端执行,一个是在Server端执行。

 

我研究比较了几乎所有的Server Side Template Engine,力图采众家之长,避众家之短,写了一个Server Side Template Engine -- fastm, 能够最优雅方便的实现页面模板层。关于fastm,我的Blog上有不少文章论述。

我的Blog,里面专门有个fastm 分类。

http://blog.csdn.net/buaawhl  

http://buaawhl.blogdriver.com

 

Fastm发布在java.net上。

https://fastm.dev.java.net

 

 

我仍然对Server Side Template Engine持肯定态度。基于如下原因:

(1) JavaScript代码量大、文件多的时候,不容易管理,不容易进行语法检查,不容易跟踪调试。

这里有人会争辩,Server Side Template Engine也用到了很多脚本阿,比如Freemarker, Velocity, 而且嵌在HTML中,怎么管理,怎么调试?即使是JSP,也是Java Code嵌在HTML里面,怎么管理,怎么调试?

这里我要说,Jivan, XMLC, fastm,Wicket等Template Engine的逻辑都是在Java Code里面。

 

(2) 用JavaScript生成文本内容,搜索引擎不友好。

一般的网络蜘蛛程序,只根据URL获取HTML文本,搜索里面的文本内容,而不会执行里面的JavaScript脚本。

 

(3) JavaScript代码重用还是有些局限

比如,有两个HTML文件,一个是Table布局,一个是List布局。

我有同样的一批数据,要在这两种布局中显示。

这时候,就要给这两个HTML分别写两套JavaScript。这里面的DOM层次,元素,属性都不同,再怎么定义ID,Class,也无法用完全相同的一套JavaScript处理。

这里有人会争辩,Server Side Template Engine也无法做到。别说JSP, Velocity, Freemarker等要在两套HTML里面嵌入相同的代码,就是Jivan, XMLC, Wicket也要分别写不同的两套Java Code,因为它们的XML DOM Node / Model View (Table, List) 都是不同的。

这里我要说。fastm可以做到只用一套代码逻辑。而且只有fastm可以。fastm的代码重用率是最高的。

 

关于Ajax(XMLHttp),我的意见是必要时才用,而且最好采用粗粒度的用法 -- JavaScript发出一个URL请求,返回一整段HTML,直接替换到页面的某一块,而不是用JavaScript来做这样的把数据填充到HTML DOM中。如果你直接在浏览器里面输入那个URL,也可以获取那整段的HTML内容。

典型的应用场合是Portal。Portal页面的每个Portlet都含有这样的 Ajax(XMLHttp) javascript代码 -- 发出一个Portlet URL请求,返回一整段Portlet的内容,直接替换当前的Portlet块。

这样做的好处是:

(1) 减少JavaScript代码的量和复杂度。

(2) 搜索引擎友好。网络蜘蛛程序可以辨别JavaScript中的URL,并根据这个URL,获取整段处理好的HTML文本,进行内容搜索。

有人可能会争辩:如果URL请求返回的是XML数据,不是整段处理好的HTML,搜索引擎也可以进行内容搜索。

这点我同意。前提是XML数据的内容是足够连贯的,而不是散落的。比如,你返回的XML数据是“中国”。这个“中国”要放在HTML中的一个{country}位置,{country}足球。这个时候,结果HTML的内容含有“中国足球”。而XML数据中只含有“中国”。如果用户用“中国足球”作为关键字来搜索,就找不到这个URL。

 

从前面给出的fastm资料的连接中,可以得知。如同Jivan, XMLC, Wicket一样,fastm的template里面不含有逻辑,所有的逻辑都写在Java里面。

有人会争辩说:页面逻辑写在Java里面,我改变了页面逻辑,还需要重新编译。这也太不方便了。Velocity, Freemarker, JSP就不用重新编译。

这里我的看法是:业务逻辑代码改变了,不也需要重新编译吗?页面逻辑就不是逻辑了吗?HTML里面的脚本怎么语法检查、跟踪调试?业务逻辑需要语法检查、跟踪调试,页面逻辑就不需要语法检查、跟踪调试了吗?

对方可能会说:在我的应用中,页面逻辑的改动需求非常频繁,而且这些页面逻辑非常简单,不需要语法检查、跟踪调试。

这里我的意见是:

(1) 那就使用JSP, Velocity, Freemarker等脚本。

(2) fastm, Jivan, XMLC, Wicket的Java代码部分也可以写在脚本里面,比如,Server Side JavaScript, Jython(Python),  Groovy, Bean Shell 等脚本语言都可以很方便的和Java相互调用。

 

fastm的生命周期将很长。

HTML, XUL, XAML都是,或将是可以在浏览器或可视化编辑工具里面显示的XML UI定义语言。Microsoft Office的Word, Excel, Powerpoint等格式都提供了相应的XML格式。这些XML文件都可以在Office里面显示,并编辑。

Adobe公司也提供了PDF的XML格式 -- XDP。可以在Adobe Designer里面显示并编辑。

由于fastm是Designer Friendly的XML UI所见即所得的模板技术。这方面具有很大的潜力。

根本不需要第三方花大力气专门做个IDE,来显示自定义的Tag。目标文件格式提供商自己的阅读编辑工具就可以直接用了,而且效果就是运行后产生的结果文件的效果。

 

即使没有可视化要求的场合。比如,Web Service需要的XML数据。fastm同样有用武之地。比如,

<!-- BEGIN DYNAMIC: users -->

<user>

  <name>{name}</name>

  <address>{name}</address>

</user>

<!-- END DYNAMIC: users -->

 

可以很容易的把一个Java Object List转化为XML数据。

 

另外,我不得不承认。浏览器端的JavaScript的页面逻辑,可移植性要高于Server Side Template Engine。因为Server Side Template Engine通常是特定语言相关的。

目前fastm是用Java实现的。由于实现很简单,移植到其它的语言,也很简单。如果是移植到Python, Ruby等动态解释语言,那就更简单了。我是有这个考虑,因为Zope, Ruby on Rails 的模板还是Logic 和 HTML混杂的,fastm这个思路有很大的用武之地。

 

前面讲了这么多。清理了两层有名的脏乱差的老大难的楼层 -- 页面资源层和页面模板层。让这两层变得和下面的楼层同样的优雅、清洁。

 

下面该讲到Web框架层了。在向下讲之前,由于前面提到了脚本,我想先插入一段关于“可配置”、“可编程”、“可热部署”、“脚本逻辑 vs XML Tag逻辑”的话题。把这个人们比较关心、讨论比较多的话题,先讲清楚。

5.可配置、可编程、可热部署、脚本逻辑 vs XML Tag逻辑
由于Java是编译语言,人们通常把变化的参数部分抽取出来,放到配置文件中。

这些配置文件通常是XML文件。这很好,没什么问题。XML很适合用来表达数据结构。

但是,对于某一种技术的狂热,通常引起对这种技术的过度使用,或者误用。

人们开始觉得,XML能够表达一切东西,包括for, if, else等逻辑。这方面的典型例子有 Workflow XML Definition,Logic TagLib, XSL Logic Tag等。

这点我不敢苟同。我的看法是,XML不适合表达逻辑,XML表达逻辑非常蹩脚。XML表达逻辑相当于自定义一门XML格式的脚本语言。

 

比如,Logic Tablib,很难自然的支持 if else, switch。只能蹩脚地支持一堆 <logic:if> <logic:ifNot> <logic:exists> <logic:notExists> <logic:ifNull> <logic:notNull>。

(注,好久没有接触过Taglib了。这些Tag Name都是凭以前的使用印象写的,也许名字不对,但表达这些意思的TagLib都还是有的)

如果要表达if () else if() else 就更蹩脚了。要进行非常麻烦的嵌套。

 

再比如,XSL 支持if, else 也非常蹩脚。非要多出来一个层次才行。

<xsl:choose>

<xsl:when test="…">

   …. If ….

</xsl:when>

<xsl:otherwise>

    … else …

</xsl:otherwise>

</xsl:choose>

 

同样,如果要表达if () else if() else 就更蹩脚了。

<xsl:choose>

<xsl:when test="…">

   …. If ….

</xsl:when>

<xsl:otherwise>

<xsl:choose>

<xsl:when test="…">

   …. If ….

</xsl:when>

<xsl:otherwise>

    … else …

</xsl:otherwise>

</xsl:choose>

</xsl:otherwise>

</xsl:choose>

 

可以看到,XML Tag 表达逻辑,非常麻烦,可读性很差,完全是一种误用,没有半点优势。当然,逻辑简单的情况下,还是可以接受的。

有人会说:XML表达逻辑,可以免编译阿。

那么我说:语法检查呢,跟踪调试呢?

对方说:只是一些简单的逻辑,不需要语法检查、跟踪调试。

我说:如果只是为了免编译,前面列出的那么多的解释执行的脚本语言更适合。XML表达的逻辑,比Java等编译语言还要麻烦很多,而脚本语言比Java等编译语言简洁多了,可读性非常好,而且脚本语言和Java语言有很好的交互性,可以相互调用。重用、结构方面都具有优势。

 

有人会举出Spring IoC为例子,说:你看,Spring IoC的配置文件不都是XML格式吗?

我说:

(1) Spring IoC的配置文件基本都是属性设置,Bean ID声明。没有逻辑。

(2) 我也不是很赞同Spring IoC在XML配置文件里面引用Java类的做法。这方面,其它的容器如 Pico, Nano都支持多种配置方式,其中包括了不少脚本方式。我觉得,在脚本里面定义生成Java Object,比在XML中要好。当然,Web.xml里面也引用了Java Class名字。但那是非常简单的情况。没有嵌套引用、属性赋值、构造参数等复杂的定义方式。XML适合描述一些通用的资源、数据、结构。比如,HTML, XUL, XAML,RSS就是XML用的恰当的例子。

 

所以,我的基本观点是这样。

(1) 纯数据,不用说,应该定义在XML中。

(2) 如果是系统中一些Java Object要用到的基本属性。比如,连接池大小等。定义在properties, XML, Script中都可以。如果定义中没有出现具体的Java Class名,倾向于定义在properties, XML文件中。如果出现了具体的Java Class名,倾向于定义在Script中。这个界限不那么明显,两者皆可。

(3) 复杂结构的Java Bean的构造生成,那是肯定会出现具体的Java Class名,应该定义在Script中。

 

关于“可配置 vs 可编程”,有一点要明确:只要是可编程的,一定是可配置的。但如果是可配置的,却不一定是可编程的。

这里的可编程,是指框架给程序员提供了API;可配置,是指框架给程序员提供了配置文件的格式写法。

“可编程”一定是“可配置”的。

(1) 用户至少可以自己定义配置文件,读取参数,调用API。

(2) 有那么多的解释脚本可以直接和Java互操作,完全可以直接用来当作配置文件,定义参数。

“可配置” 却不一定“可编程”的。

如果框架只给你提供了配置方式,而没有API,那意味着,你只能进行参数的静态配置。很难在动态期间改变这些参数了。你总不能尝试着用代码去改变配置文件的内容吧?即使你改动了,如果框架不进行文件的时间戳检查,就是一开始装载进来,就不再检查更改了,你不就一点办法都没有了吗?

比如,Struts Tiles的XML定义,你只能静态配置,你想在运行期间改变布局,没有办法。Site Mesh也是如此。而我们可以在运行期间任意操作XML DOM Node,别说布局了,任何东西都可以改变。

所以,一个框架首要注重的是提供API,而不是提供配置方式。这是一个重要的原则。

 

讨论完了“可编程”、“可配置”问题,我们来看“热部署”问题。

XML配置文件、脚本文件支持“热部署”当然要比编译语言程序的热部署容易得多。只要解释执行前,检查一下时间戳就可以了。要注意的问题,只是做好测试,因为没有编译期的语法检查。

不过,Java程序也是可以“热部署”的。只是稍微麻烦一点。典型的例子是JSP, EJB Jar等。JSP修改之后,会自动编译执行;EJB Jar丢到EJB Container里面,会被检测到并装载到JNDI命名空间。

编译语言Java程序的热部署的一个可能的技术难点是,Class或者Jar已经存在,如何监测到Class或者Jar的更改,并装载这个新版本,替换旧版本。

这个问题我具体没有研究过。从道理上讲,应该在Class Loader上下功夫。如果需要,可以参阅开源EJB Container的相关实现部分。Java还有一种“Hot Swap”技术,专门解决这个问题,可以搜索查阅一下。

 

这段小插曲,就到这里。下面讨论Web框架。

6.Web框架
Web框架层是一个清洁的楼层。很多优秀的程序员在这一层大展身手,做出了很多好作品。我感觉不错的有Spring MVC, Web Work。

对于Web应用来说,Web框架层是最重要的一层。SOA、Semantic Web等效果都要在这一层实现。

首先,我们来讨论,框架的编程结构。

我的Blog中有一篇《Java Web框架综述》的文章。讲解了一些流行的Web框架的编程结构,很多重复的内容不再赘述。

http://blog.csdn.net/buaawhl

 

Java Web框架综述

http://blog.csdn.net/buaawhl/archive/2004/12/21/224069.aspx

 

Spring MVC的编程接口是最清晰的。大多数简单情况下,Web Work的用法是最简单有效的,编程结构比较特殊,可以说具有一定的变革意义。

Spring MVC的Controller接口相当于Struts Action,也具有Request, Response两个参数,虽然编程接口非常清晰优雅,但是本质上没有什么变化。

WebWork的Action则失去了Controller的身份,只相当于FormBean的身份,或者说相当于ActionBean的身份。WebWork Action不具有Request, Response两个参数,它只具有属性,并通过属性Setter获取HTTP Request的参数,通过属性getter把结果数据输出到HTTP Response。

可以说,WebWork的这个把握是相当到位的。95%以上的情况下,程序员是不需要Request, Response参数的。当需要这些参数的时候,WebWork并没有挡住路,可以通过实现RequestAware,ResponseAware等接口来获取,或者通过一个Thread Local获取。这种情况下,编程结构的约定,就不那么清晰了。

 

我从Canonical的帖子和Blog受到了很多启发。

http://canonical.blogdriver.com

 

jsplet:对Model 2模式的批判

http://canonical.blogdriver.com/canonical/591479.html

 

jsplet与webwork的概念对比

http://canonical.blogdriver.com/canonical/594671.html

 

从级列理论看MVC架构

http://canonical.blogdriver.com/canonical/579747.html

 

从Canonical的文章可以看出。JSPLet用JSP文件作为Dispatcher,然后在JSP里面注册并调用对应的Object。这个寻访Object的过程,完全是根据丰富的URL定义来做的。URL里面包括Object Scope, Object Name, Method Name, Method Parameters,天生就对事件机制有良好的支持。

 

Zope的一些做法也有异曲同工之妙。

Zope Object Publishing

http://www.zope.org/Documentation/Books/ZDG/current/ObjectPublishing.stx

http://www.plope.com/Books/2_7Edition/ZopeArchitecture.stx#2-3

 

这种通过URL获取Published Object的服务的思路,是一种实现SOA效果的有效思路。

 

我们首先来看Web Service的现状。目前Web Service主要分为两大阵营。SOAP和REST。关于REST,请参阅

http://www.xfront.com/REST-Web-Services.html

关于SOAP和REST的比较、互操作,网上有很多文章。如果需要请搜索查阅。

 

我个人比较倾向于REST风格的Web Service。

因为SOAP是一门固定的协议,如果用SOAP来编写Web Service程序,需要一个SOAP协议的解析库 ,也许还需要一些专门的“SOAP 数据 -- 编程语言”映射库,如同CORBA IDL的多语言映射一样。如果你要让自己的Web应用支持SOAP,你需要把发布的服务对象、方法都包装为SOAP协议,这需要一些编程语言相关的数据结构的映射工作。

REST则只是一种风格,而不是一个协议。中心思想是简单的通过丰富的URI定义 (如XLink + XPointer等) 获取资源。如果你要让自己的Web应用支持REST,那么很简单,只要在URI上下功夫就可以了,比如,多增加一个参数format=REST,在程序中多增加一种XML输出格式就可以了。(从道理上来说,SOAP也可以这么实现,但SOAP的输入和输出都要遵守SOAP协议,SOAP的输入参数一般都包装在SOAP信封里面)

 

关于HTTP Get和Post,我表述一下自己的看法。

我认为,Web的精髓在于Get,而不是Post,在于获取服务器的输出,而不是输入到服务器。即,Web的精髓在于以小搏大,四两拨千斤。最经典的用法就是用一个URL,获取一个长篇的文本内容,这个内容里面充满了其他更多的资源连接。这也是超文本连接HTML发明的初衷。

至于HTTP Post,则是这上面的一个扩展。B/S结构如此流行,很多应用都要转移到Web上面,怎么办,应用总是交互的,总要让用户输入数据吧,就增加了HTTP Post协议。

HTTP Get经典、简单、有效。可以用丰富的URI定义把这个优势发挥到极致。这个实现也比较简单、优雅。就不多说了。主要的难点在于HTTP Post。下面的讨论主要应对“HTTP Post”这个复杂现象。

HTTP Post从来就不让人们满意。当输入逻辑复杂到一定程度,表单数据的繁杂、凌乱、散落,到了服务器端很难组织起来。输入方面B/S结构确实和C/S结构难以匹敌。于是,出现了XMLHttp,能够把参数在浏览器里面组织成为一个统一的XML数据结构(或其他格式),发送到服务器端,一次解析出来。SOAP做这个方面,更是拿手好戏。所以,很多XMLHttp程序直接采用SOAP作为通信协议。而REST风格的HTTP Post则和HTML Form Post没有太大的本质区别。

REST在HTTP Get方面更胜一筹,SOAP在HTTP Post方面更胜一筹。可以根据Web应用的特点,根据HTTP Get / HTTP Post 页面的比例,选择适合的技术。

我们再进一步分析HTTP Post的数据内容。HTTP Post的数据,可能包含三种类型:

(1) 需要存档在服务器的数据

比如,用户注册时候,输入的基本信息,用户名、密码、电子邮件等。这些信息要存放到服务器的数据库。

对于这种基本信息,HTTP Post,XMLHttp,SOAP处理起来,难度都不大,没有很大区别。

B2B的数据交换,也属于这个类别。用何种技术区别不大。一般采用SOAP,因为SOAP是一种流行的标准协议。

 (2) 服务调用参数

比如,用户进行复合条件查询的时候,输入的查询条件。这个时候,HTTP Post处理起来就非常蹩脚。而XMLHttp,SOAP则具有很大的优势。可以把复杂的查询条件很好组织成XML数据,发送到服务器端统一处理。SOAP里面甚至可以定义对象名、方法名等详细的调用信息。

(3) 指令

这种情况比较少见。上面的参数类别中提到的“对象名、方法名等详细的调用信息”,和这个指令类别有些交叉。

假如一个SOAP调用方法里面的参数也是一个自定义的对象,这个自定义对象的属性数据在SOAP信息中进行了定义。到了服务器端之后,服务端程序首先调用这个自定义参数的构造函数,生成这个参数对象,然后调用对应的服务对象,把这个参数传给服务。这个过程可以看作是一个顺序指令:[1]构造参数[2]调用服务。

这只是最简单的情况。而目前的Web Service一般也就支持到这个程度。

我的看法是,一不做,而不休。既然都把调用信息定义到这个程度了,不如做的更彻底一些,全面完善的支持指令。这个指令则意味着逻辑。前面讲过了,我不赞成用XML Tag表示逻辑,而赞成脚本。这里比较适合的脚本是JavaScript,因为JavaScript比较通用,客户端、服务器端都可以解释执行。注意,这里和一般的做法正好相反:一般的Web应用总是把JavaScript从服务器传到浏览器里面执行,而这里是把JavaScript在浏览器里组织好,发给服务器端处理;这个JavaScript将会在服务器端执行,调用服务器端的对象。举个SOAP含有JavaScript指令的例子 (只是示意,非标准格式) :

<soap envelope>

  <XML Data>

          <a>

               <b>12</b>

          </a>

          <c>

               <d>21</d>

          </c>

          <e>

               <e>16</e>

          </e>

  </XML Data>

 

  <script>

        final_result = default;

        result1 = service1.service(a.b);

        if(result1.ok){

             result2 = service2.service(c.d);

             if(result2.ok)

                  final_result = service3.service(e.f);

        }

  </script>

< /soap envelope >

 

这个好处是:

[1] 发布了更多的基本Service。给客户提供了更大的灵活度。

比如,这里就发布了3个Service。由用户自己组织逻辑。

按照传统的做法,上述流程将整个包装在服务器端执行。发布给用户的Service只有最外面的一个Service,而且高度耦合(if, else, if, else流程hard code在服务器端),不灵活,不通用。

这里的方法,就可以让客户端随意组织service1, service2, service3的调用顺序和方式。

[2] 减少了通信次数。

假如这段Script在客户端执行,那么和服务器要进行3次通信。

 

传统Web的权限控制一般在URL级别,这种script -> server方式的权限控制则要在对象级别、方法级别、Code片断级别了,复杂很多,也许要大量应用Java的Code权限认证机制。

 

以上展开讨论了 Web Service,  HTTP Get/Post。下面我们回到Web框架层。

前面说了,JSPLet给了我很大的启发。很多思路可以借鉴。

当然,我并不赞成用JSP作Dispatcher, Controller。(1) 因为JSP要编译成Servlet,而Servlet是Web Server管理的比较昂贵的资源。一个Web系统中JSP达到几千个,就会遇到性能瓶颈。(2) JSP中的代码重用很成问题。一般只能通过include file的方式。

可以借鉴的思路。(1) JSPLet 的入口是JSP文件,这一步的URL到处理程序的映射是Servlet/JSP Container自然支持的。这是免配置的。(2) 丰富的URL参数定义,良好的对象方法寻址能力。

 

我开发的开源Web框架lightweb,将具备如下特性:

(1) 支持两个层次的编程接口。

interface Action {  void service(request, response, servletContext);  }

这个Action比Struts Action, Spring MVC Controller高一个级别。相当于Dispatcher, 相当于JSPLet的JSP控制文件。这个用来做最外层的入口控制。

同时,也支持简单的JavaBean.method的直接调用。相当于WebWork Action,JSPLet Registered Object。这个用来做具体的事情。

 

(2) 支持丰富的对象寻址URI,比如 http://my.com/myProject/myModule/myEntry.action object=calculator&method=add&p1=1&p2=3

这表示要通过 myEntry.acion这个入口,调用caculator.add(1, 2)方法。

如果用URL Rewriter可以美化为

http://my.com/myProject/myModule/myEntry/calculator/add/1/3

看起来就很象XLink + XPointer了。

 

(3) 免配置。或者说极少的配置。

框架根据一定的匹配准则,把myModule/myEntry.action映射到

com.mycompany.mymodule.MyEntryAction 这个类的service方法。

这个service方法负责根据object, method的名字,寻找到对应的bean,并根据参数进行属性设置验证,并执行对应的bean.method。然后,把这个bean作为Model和template结合,输出结果。

同样,template的获取也是根据一定的匹配准则,根据myModule/myEntry找到

Mymodule/myentry.html 或者Mymodule/myentry/calculator.html。

 

这样的lightweb就能够同时对应简单和复杂。复杂控制的需求交给Action接口来做,简单的一般具体任务交给普通Java Bean去做。

Web框架层可以做的非常复杂,可以做的非常简单。Lightweb的目标,就是分成多个简单的部分;各部分合起来就能够完成从非常简单到非常复杂的需求。

接下来,我们来看O/R。

7.O/R
Hibernate, EJB Entity Bean产品,JDO产品,iBatis是比较流行的几种O/R Mapping Framework。

我做的一些工作中,经常涉及到复杂的优化过的native SQL,并且涉及到大量的批量复杂逻辑处理,现有的O/R框架都不能满足功能和性能要求。

 

我做出这样一个lightor框架,思路借鉴了Martin Fowler的《企业架构模式》里面讲述的一些O/R的Row Mapper,  Column Mapper等概念。

 

最经典的用法是:

ResultSet rs = ps.executeQuery( a long complex native sql);

//will return a lot of records

A a = new A();

B b = new B();

IMapper aMapper = MapperService.getMapper(A.class);

IMapper bMapper = MapperService.getMapper(B.class);

 

While(rs.next()){

   aMapper.populate(a, rs);

 bMapper.populate(b, rs);

 

  businessLogic(a, b);

}

 

可以看到,Lightor不需要一下子把所有纪录都放到一个Object List里面。完全可以随取随用。整个过程中,a, b只有一份,极大的节省了空间、时间,也极大的提高了开发效率,减少了重复代码。

没有任何一个其它O/R能够支持这种用法。这里面,lightor的mapper的populate方法需要ResultSet参数。一般的O/R不屑于这么做的,别说ResultSet,连Connection都想包装起来不给你看。

 

Lightor的设计思路也是同时应对简单和复杂。Lightor的Mapper实体部分是自动生成代码。类似于JDO的静态Enhance。不同的是,JDO静态Enhance直接修改bean class。而Lightor则不动原有的bean,只是多生成了对应的Mapper Source/Class。这种方式是最利于跟踪调试的。至于发布部署,和JDO的情况差不多,不如Hibernate的动态代码增强。

这里我很羡慕Python, Ruby等动态解释语言的特性,根本不需要这些麻烦事。

 

这一层我主要关注的是性能,缓存策略等等,而不是简便。我觉得,一个应用系统的瓶颈主要存在于O/R, DB层。不应该单纯为了追求OO结构的优雅,或者编程的方便,而牺牲了一些可能优化的地方。

 

关于Lightor的缓存策略, 我的Blog上有几篇文章。

http://blog.csdn.net/buaawhl

 

数据库对象的缓存策略

http://blog.csdn.net/buaawhl/archive/2004/12/21/224184.aspx

 

分页 & QueryKey & 定长预取

http://blog.csdn.net/buaawhl/archive/2005/01/08/245005.aspx

8.总结
我理想中的Web开发架构是这样的:

开发速度快,运行速度快,结构清晰优雅。

具体到每一层。

Web框架层主要追求 开发速度快。

O/R层主要追求 运行速度快。

页面资源层和页面模板层主要追求 结构清晰优雅。

 

PHP错误总结

1. Data too long for column `Title` at row 1 错误解决方法:
  (1). 确保数据库结构是 utf-8 的, php 文件是 utf-8 格式的.
  (2). 在php 顶部加上: header(‘Content-type: text/html; charset=utf-8’);
  (3). 发生以上错误可能是因为你要插入的字符集是 GB2312, 所以需要我们把改字符转为 utf-8的。
      所以: $title = mb_convert_encoding($title,”UTF-8″, “GBK”); 即可解决该问题。

 

2. Smarty 错误:

    Smarty 3 抛出 Uncaught exception ‘Exception’ with message ‘Syntax Error in template  ….. – Unexpected ” }”, expected one of: “}” , “*” , “/” , “%” 

   可能是是由于 {if …. }  在 } 之前多了一个空格的原因。 (如果带空格在 smarty 3中会被看作 javascript的代码片段)

3. Class ‘XSLTProcessor’ not found in…… 错误

    (1).  启用 PHP 对 xslt 的支持, 在 php.ini 文件中取消 php_xsl.dll 前的注释.

4. file_get_contents() 访问远程文件或者类似 http://www.example.com 这样的文件不会有问题,但如果访问本地文件,比如访问 b.php ,可以这样:
   $data = eval(‘ ‘.’>’.file_get_contents(‘b.php’,1).'<‘.’ ‘);  
   echo $data;

[转]IE到Mozilla迁移指南(把应用从IE迁移到Mozilla)[英文]

Internet Explorer To Mozilla Migration Guide
  • Introduction
    • What is Mozilla
    • Mozilla Philosophy (standards compliant, etc)
  • General Cross Browser Coding Tips
    • Browser Detection the Right Way (capabilities VS browser specific checks)
    • Abstracting Out Browser Differences
  • DHTML
    • DOM Differences
      • document.all/global namespace VS document.getElementById
      • Document Fragments
      • Table of mappings from IE -> Standards/Mozilla (innerhtml)
    • JavaScript Differences
      • getYear() VS getFullYear
      • execution – adding code to the end won’t mean everything else has completed – use onload handlers
      • window.open is async!
    • CSS
      • Units matter
      • Image spacing
    • Events
      • IE event model VS Netscape/W3C model
      • Table of mappings
  • Rich Text Editing
    • Differences between Designmode in IE and Mozilla
  • XML
    • whitespace differences in XML
      • nodeType == 3 for text nodes
    • XML Data Islands
    • XSLT
      • XSLT JS Interface
    • XML Web Services
      • XMLHttpRequest
      • SOAP
      • WSDL ( )
  • Quirks VS Standard Modes
    • Doctypes
  • Furthur reading
    • Books
    • Mozilla.org
    • DevEdge

General Cross Browser Coding Tips

Even though Web Standards exist, different browsers behave differently, sometimes even the same browser may behave so on different platforms.

Since different browsers sometimes use different apis for the same function, it is common to find multiple if() else() blocks throughout code to differentiate between browsers.

    . . .
    
    var elm;

    if (ns4)
      elm = document.layers["myID"];
    else if (ie4)
      elm = document.all["myID"];
  

The problem with doing this is that if a new browser is going to be supported, all these blocks need to be updated.

Therefore, when developing for multiple browsers, the easiest way to avoid the need to recode for a new browser is to abstract out functionality. Rather than multiple if() else() blocks throughout code, it is more efficient to take common tasks and abstract them out into their own functions. Not only does it make the code easier to read, it simplifies adding support for new clients.

    var elm = getElmById("myID");
    
    function getElmById(aID){
      var rv = null;
    
      if (isMozilla || isIE5)
        rv = document.getElementById(aID)
      else if (isNetscape4)
        rv = document.layers[aID]
      else if (isIE4)
        rv = document.all[aID];

      return rv;
    }
  

However, there is still a issue with the code: the browser sniffing. Usually, browser sniffing is done via the useragent, such as:

      Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031016

While useragent sniffing provides detailed information on what browser is being used, code handling useragents can make mistaked when new versions of browsers arrive, thus requiring code changes.

If the type of browser doesn’t matter (say non-supported browser have already been blocked from accessing the web application), it is better to sniff by browser capability.

Rather than

       if (isMozilla || isIE5)

it should be:

       if (document.getElementById)

This would allow other browsers that support that command, like Opera or Safari, to work without any changes.

Useragent sniffing however does make sense when accuracy is important, such as verifying that a browser meets the version requirements of the web application or to workaround a bug in a certain version.

JavaScript allows inline conditional statements, which can help readability of code:

       var foo = (condition)   conditionIsTrue : conditionIsFalse;

For example, to retrieve an element:

       function getElement(aID){
         var rv = (document.getElementById)   document.getElementById(aID) : document.all[aID];
         return rv;
       }

DOM Differences

The Document Object Model (DOM) is the tree structure holding the elements inside the document. DHTML’s biggest use is to modify the DOM by JavaScript, and the most often used task is to get a reference to an element.

Accessing Elements

The cross-browser way to get an reference to an element is via document.getElementById(aID). This works in IE5.5+ and Mozilla-based browsers, and is part of the DOM Level 1 specification.

Mozilla does not support accessing an element via document.elementName or even just via its name, which Internet Explorer does. Mozilla also does not support the Netscape 4 document.layers method and Internet Explorer’s document.all.

It is also sometimes needed to get references to all elements with the same tagname, and in Mozilla, the DOM Level 1 getElementsByTagName() is the way to do so It returns in JavaScript an array, and can be called on the document element or other nodes to access only their subtree. To get an array of all elements in the DOM tree, getElementsByTagName(*) can be used.

One common use of these methods is to move an element to a certain position and toggling its visibility (menus, animations). Netscape 4 used the <layer> tag, which mozilla does not support. For Mozilla, the <div> tag is used, as does IE.

Traversing the DOM

Mozilla supports the W3C DOM standard way of traversing the DOM tree. Children of an node can be accessed via node.childeNodes, which returns an array. Other methods available are firstChild and lastChild.

Nodes can access their parents via node.parentNode. Nodes can also acces their siblings via the node.nextSibling and node.previousSibling.

Generating and Manipulating Content

Mozilla supports the legacy methods for adding content into the DOM dynamically, such as document.write, document.open and document.close.

Mozilla also supports Internet Explorer’s InnerHTML method, which can be called on almost any node. It does not however, support OuterHTML and innerText.

Internet Explorer has several content manipulation methods that are non-standard and not supported in Mozilla, such as retrieving the value, inserting text or inserting elements adjacent to an node such as getAdjacentElement and insertAdjacentHTML. Below is the chart of the W3C standard and Mozilla support ways of manipulation content, all of which are mehotds of any DOM node:

Method
Description
appendChild( aNode ) Creates a new child node. Returns a reference to the new child node.
cloneNode( aDeep ) Makes a copy of the node it is called on and returns the copy. If aDeep is true, it recursively clones the subtree as well.
createElement( aTagName ) Creates and returns a new, parentless DOM node of the type specified by aTagName.
createTextNode( aTextValue ) Creates and returns a new, parentless DOM textnode with the data value specified by aTextValue.
insertBefore( aNewNode, aChildNode ) Inserts aNewNode before aChildNode, which must be a child of the current node.
removeChild( aChildNode ) Removes aChildNode and returns a reference to it.
replaceChild( aNewNode, aChildNode ) Replaces aChildNode with aNewNode and returns a reference to the removed child node.
Document Fragments

For performance reasons, it can be usefull to create documents in memory, rather than working on the existing document’s DOM. In DOM Level 1 Core, document fragments were introduced. They are “lightweight” documents, as they contain a subset of a normal document’s interfaces. For example, getElementById does not exit, but appendChild does. Document fragments are also easily added to existing documents.

In Mozilla, document fragments are created via document.createDocumentFragment(), which returns an empty document fragment.

Internet Explorer’s implementation of document fragments however does not comply with the W3C standard, and simply returns a full document.

Element Dimensions

width/height of an element, offsetWidth for exp.

JavaScript

Most differences between Mozilla and Internet Explorer are due to the DOM interfaces exposed to JavaScript. There are very few core JavaScript differences, and issues encountered are often timing related.

JavaScript Date Differences

The only Date difference is the getYear method. In Mozilla, per the specification, it is not Y2k compliant, and running new Date().getYear() in 2004 will return “104”. Per the ECMA specification, getYear returns the year minus 1900, originally meant to return “98” for 1998. getYear was deprecated in ECMAScript v3 and replced with getFullYear().

JavaScript Execution Differences

Different browsers execute JavaScript differently. For example, the following code:

    ...
    <div id="foo">Loading...</div>
    
    <script>
      document.getElementById("foo").innerHTML = "Done.";
    </script>
    

assumes that the div node exists already in the DOM by the time the script block gets executed. This is however not garantueed. To be sure that all elements exist, it is best to use the onload event handler on the <body> tag.

    <body onload="doFinish()">    
    
    <div id="foo">Loading...</div>
    
    <script>
      function doFinish(){
        document.getElementById("foo").innerHTML = "Done.";
      }  
    </script>
    ...
    

Such timing-related issues are also hardware related – slower systems can reveal bugs that faster systems hide. One concrete example is window.open, which opens a new window.

    <script>
      function doOpenWindow(){
        var myWindow = window.open("about:blank");
        myWindow.location.href = "http://www.ibm.com";
      }  
    </script>
    

The problem with the code is that window.open is asyncronous – it does not block the JavaScript execution until the window has finished loading.

Debugging JavaScript

Mozilla provides several ways to debug JavaScript related issues. The first tool is the built-in JavaScript console, where errors and warnings are logged. It can be opened by going to Tools -> Web Development -> JavaScript Console.

The JavaScript console can show the full log list, or just errors/warnings/messages. The error message in the screenshot says that at aol.com, line 95 tries to access an undefined variable called is_ns70. Clicking on the link will open Mozilla’s internal view source window with the offending line highlighted.

The console also allows for evaluating JavaScript. Typing in 1+1 into the input field and pressing the “Evaluate” button will evaluate the entered JavaScript syntax.

Mozilla’s JavaScript engine has built in support for debugging, and thus can provide powerfull tools for JavaScript developers. The Mozilla JavaScript Debugger (called Venkman) is a powerfull, cross platform JavaScript debugger that integrates with Mozilla. It is usually bundled with Mozilla releases and can be found in Tools -> Web Development -> JavaScript Debugger. It can be downloaded and installed from http://www.mozilla.org/projects/venkman/. Tutorials can be found at the development page, located at http://www.hacksrus.com/~ginda/venkman/.

The JavaScript debugger can debug JavaScript running in the Mozilla browser window. It supports such standard debugging features such as breakpoint management, call stack inspection, and variable/object inspection. All features are accessible via the User Interface or via the debugger’s interactive console. The console also allows to execute arbitrary JavaScript in the same scope as the JavaScript currently being debugged.

Event Differences

Events is one of the few areas where Mozilla and Internet Explorer are nearly completly different.

The Mozilla Event Model

The Mozilla event model is completly different from the Internet Explorer model. It follows the W3C and Netscape model.

In Internet Explorer, if a function is called from an event, itcan access the event object via window.event. In Mozilla, event handlers get passed an event object, and they must specifically pass it on to the function called via an argument. A cross-browser event handling example:

    <div onclick="handleEvent(event)">Click me!</div>

    <script>
      function handleEvent(aEvent){
        // if aEvent is null, means the IE event model, so get window.event.
        var myEvent = aEvent   aEvent : window.event;
      }  
    </script>
    

The properties and functions the event object exposes are also often named differently between Mozilla and IE. A table can be found below:

IE Name
Mozilla Name
Description
altKey altKey Boolean property which returns wether the alt key was pressed during the event.
cancelBubble stopPropagation() Used to stop the event from bubbling furthur.
clientX clientX The X coordinate of the event, in relation to the client area.
clientY clientY The Y coordinate of the event, in relation to the content window.
ctrlKey ctrlKey Boolean property which returns wether the ctrl key was pressed during the event.
fromElement relatedTarget For mouse events, this is the element that the mouse moved away from.
keyCode keyCode For keyboard events, this is a number representing the key that was pressed. Is 0 for mouse events.
returnValue preventDefault() Used to prevent the default action of the event from occuring.
screenX screenX The X coordinate of the event, in relation to the screen.
screenX screenY The Y coordinate of the event, in relation to the screen.
shiftKey shiftKey Boolean property which returns wether the shift key was pressed during the event.
srcElement target The element to which the event was originally dispatched.
toElement relatedTarget For mouse events, this is the element that the mouse moved towards.
type type Returns the name of the event.
Attaching Event Handlers

Mozilla supports two ways to attach events via JavaScript. The first way, supported by all browers is to set event properties directly on objects. To set an click event handler, a function reference is passed to the object’s onclick property.

    <div id="myDiv">Click me!</div>

    <script>
    
      function handleEvent(aEvent){
        // if aEvent is null, means the IE event model, so get window.event.
        var myEvent = aEvent   aEvent : window.event;
      }  
      
      function onPageLoad(){
        document.getElementById("myDiv").onclick = handleEvent;
      }
      
    </script>
    

The W3C standard way of attaching listeners to DOM nodes is fully supported in Mozilla. The addEventListener() and removeEventListener() methods are used, and have the benefit of being able to set multiple listeners for the same event type. Both methods require three parameters – the event type, a function reference and a boolean denoting if the listener should catch events in their capture phase. If the boolean is set to false, it will only catch bubbling events. W3C events have three “phases” – capturing, at target and bubbling, and every event object has a eventPhase attribute indicating the phase numerically (0 indexed). Every time an event is triggered, the event starts at the outermost element of the DOM, the element at top of the DOM tree. It then walks the DOM using the most direct route towards the target, which is called the capturing phase. After arriving at the target, it walks up the DOM tree back to the outermost node, called bubbling. Internet Explorer’s event model only has the bubbling phase, therefore setting the third parameter to false will result in IE-like behavior.

    <div id="myDiv">Click me!</div>

    <script>
    
      function handleEvent(aEvent){
        // if aEvent is null, means the IE event model, so get window.event.
        var myEvent = aEvent   aEvent : window.event;
      }  
      
      function onPageLoad(){
        document.getElementById("myDiv").addEventListener("click", handleEvent, false);
      }
      
    </script>
    

One advantage of addEventListener() and removeEventListener() over setting properties is that one can have multiple event listeners for the same event, each calling another function. Due to this, removing an event listener requires all three parameters to be the same as the ones used when adding the listener.

Mozilla does not support Internet Explorer’s method of converting <script> tags into event handlers, which extends <script> with for and event attributes. It also does not support the attachEvent and detachEvent methods. Instead, the addEventListener and removeEventListener methods should be used. Internet Explorer does not support the W3C Events specification at all.

IE Method
Mozilla Method
Description
attachEvent(aEventType, aFunctionReference) addEventListener(aEventType, aFunctionReference, aUseCapture) Adds an event listener to an DOM element.
detachEvent(aEventType, aFunctionReference) removeEventListener(aEventType, aFunctionReference, aUseCapture) Removes an event listener to an DOM element.

CSS Differences

Mozilla has the strongest support for Cascade Style Sheets (CSS) compared to all other browsers, including most of CSS1, CSS2 and parts of CSS3.

Mimetypes (CSS file not applying)

The most common CSS-related issue is that CSS definitions inside referenced CSS files are not applied. This is usually due to the server sending the wrong mimetype for the CSS file. The CSS specification states that CSS files should be served with the text/css mimetype. Mozilla will respect this and only load CSS files with that mimetype if the webpage is in strict standards mode. Web pages are considered in strict standards mode when they start with a strict doctype. The solution is to make the server send the right mimetype or to remove the doctype. More about doctypes in the next section.

CSS and Units

A lot of web applications do not use units with their CSS, especially when JavaScript is used to set the CSS. Mozilla is tolerant of this, as long as the page is not rendered in strict mode. If the page is in strict standards mode, and no units are used, then the command is ignored.

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html>
        <body>
          <div style="width:40px; border:1px solid black;">Click me!</div> // works in strict mode

          <div style="width:40; border:1px solid black;">Click me!</div>   // will fail in strict mode
        </body>  
      </html>  

In the above example, since there is a strict doctype, the page is rendered in strict standards mode. The first div will have a width of 40px, since it uses units, but the second div won’t get a width, and thus will default to 100% width. The same would apply if the width were set via JavaScript.

JavaScript and CSS

Since Mozilla supports the CSS standards, it also supports the CSS DOM standard for setting CSS via JavaScript. An element’s CSS rules can be accessed, removed and changed via the element’s style member.

      <div id="myDiv" border:1px solid black;">Click me!</div>

      <script>
        var myElm = document.getElementById("myDiv");
        myElm.style.width = "40px";
      </script>

Every CSS attribute can be reached that way. Again, if the web page is in strict mode, setting a unit is required, else the command will be ignored.

In Mozilla and other browsers, when querying a value, say via .style.width, the returned value will contain the unit, meaning a string is returned. The string can be converted into a number via parseFloat("40px").

Overflow differences

CSS added the notion of overflow, which allows one to define how overflow should be handled. An example of overflow would be a div with a specified height, and its contents are taller than that height. The CSS standard defines that if this happens and no overflow behavior is set, the contents of the div will overflow. However, Internet Explorer does not comply with this, and will expand the div beyone its set height inorder to hold the contents. Below is an example:

     <div style="height:100px; border: 1px solid black;">
       <div style="height:150px; border: 1px solid red; margin:10px;">a</div>
     </div>

As can be seen in the below screenshots, Mozilla acts like the standard specifies and the inner div overflows to the bottom. If the IE behavior is desired, simply don’t specify a height on the outer element.

Quirks vs Standards Mode

Older legacy browsers such as versions 4 of Netscape and IE had so called quirks in their rendering under certain conditions. While Mozilla aims to be a standards compliant browser, in order to support older webpages written to the quirky behaviors, Mozilla has 3 modes when it comes to rendering a webpage, and the content and way the page is delivered to the browser determine which mode is used. To find out what mode a page is rendered in, View -> Page Info (or ctrl-i) in Mozilla will list the Render Mode mozilla is using.

Doctypes (short for document type declaration) look like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

The section in blue is called the public identifier, the green part is the system identifier, which is a URI.

Standards Mode

Standards mode is the most strict rendering mode – it will render pages per the W3C HTML and CSS specifications and will not support any quirks at all.

Standards mode is used for the following conditions:

  • If a page is sent with an text/xml mimetype, or any other XML or XHTML mimetype
  • Any “DOCTYPE HTML SYSTEM” doctype (<!DOCTYPE HTML SYSTEM "http://www.w3.org/TR/REC-html40/strict.dtd"> for example), except for the IBM doctype
  • Unknown doctypes or doctypes without DTDs
Almost Standards Mode

Almost standards mode was introduced into Mozilla for one reason: a section in the CSS 2 specification breaks designs based on a precise layout of small images in table cells. Instead of forming one image to the user, each small image ends up with gap. An example is the IBM homepage:

Almost standards mode behaves almost exactly as standards mode does. It makes an exception though for image gap issue, as it occurs quite often that pages call themselves standards compliant, yet are hosed due to the image gap situation.

Standards mode is used for the following conditions:

  • Any “loose” doctype (<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">, <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> for example)
  • The IBM doctype (<!DOCTYPE html SYSTEM "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd">)

Reference: DevEdge

Quirks Mode

Currently, the web is full of invalid HTML markup, as well as markup that only functions to do to bugs in browsers. The old Netscape browers, when they were the market leaders, had bugs. When Internet Explorer came, it mimicked those bugs so that it would work with content at that time. As newer browsers came, most of these original sins were kept for backwards compatability, usually called quirks. Mozilla supports many of these quirks in its quirks rendering mode. Note that due to these quirks, pages will render slower than if they were fully standards compliant. Most web pages will be rendered under this mode.

Quirks mode is used for the following conditions:

  • No doctype is specified
  • Doctypes without an system identifier (<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> for example)

List of Quirks
List of Doctypes and what modes they cause

Rich Text Editing

While Mozilla prides itself with being the most W3C standards compliant browser, it does support non-standard functionality if there is no W3C equivalent. innerHTML is one example, another is rich text editing.

Mozilla 1.3 introduced an implementation of Internet Explorer’s designMode feature. Mozilla supports the designMode feature which turns an HTML document into an rich-text editor field. Once turned into the editor, commands can be run on the document via the execCommand command. Mozilla does not support IE’s contentEditable attribute for making any widget editable.

The best way of adding an richt-text editor is by using an iframe and making that become the rich text editor.

Differences

Since iframes are the most convinient ways of having part of a page be a rich text editor, one needs to be able to access the document object of the iframe. Mozilla supports the W3C standard of accessing it via IFrameElm.contentDocument, while IE requires you to go via document.frames["name"] and then access the result’s document.

      function getIFrameDocument(aID){
        var rv = null;
      
        // if contentDocument exists, W3C compliant (Mozilla)
        if (document.getElementById(aID).contentDocument){
          rv = document.getElementById(aID).contentDocument;
        } else {
          // IE
          rv = document.frames[aID].document;
        }
        
        return rv;
      }

Another difference between Mozilla and Internet Explorer is the HTML that the rich text editor creates. Mozilla defaults to using CSS for the generated markup. However, Mozilla allows one to toggle between HTML and CSS mode using the useCSS execCommand and toggling it between true and false.

      Mozilla (CSS):
        <span style="color: blue;">Big Blue</span>

      Mozilla (HTML):
        <font color="blue">Big Blue</font>

      Internet Explorer:
        <FONT color="blue">Big Blue</FONT>
Command Name
Description
Argument
bold Toggles the bold attribute of the selection.
createlink Generates an HTML link from the selected text. The URL to use for the link
delete Deletes the selection
fontname Changes the font used in the selected text. The font name to use (Arial for example)
fontsize Changes the font size used in the selected text. The font size to use
fontcolor Changes the font color used in the selected text. The color to use
indent Indents the block where the caret is.
inserthorizontalrule Inserts an <hr> element at the position of the cursor.
insertimage Inserts an image at the position of the cursor. URL of the image to use
insertorderedlist Inserts an ordered list (<ol>) element at the position of the cursor.
insertunorderedlist Inserts an unordered list (<ul>) element at the position of the cursor.
italic Toggles the italicize attribute of the selection.
justifycenter Centers the content at the current line.
justifyleft Justifies the content at the current line to the left.
justifyright Justifies the content at the current line to the right.
outdent Outdents the block where the caret is.
redo Redoes the previously undo command.
removeformat Removes all formatting from the selection.
selectall Selects everything in the rich text editor.
strikethrough Toggles the strikethrough of the selected text.
subscript Converts the current selection into subscript.
superscript Converts the current selection into superscript.
underline Toggles the underline of the selected text.
undo Undoes the last executed command.
unlink Removes all link information from the selection.
useCSS Toggles the usage of CSS in the generated markup. Boolean value

Reference: DevEdge

XML

Mozilla has strong support for XML and XML-related technologies such as XSLT and web services. It also supports some non-standard extensions such as XMLHttpRequest.

Handling XML

As with standard HTML, Mozilla supports the W3C XML DOM specification, which allows one to manipulate almost any aspect of an XML document. Differences between IE’s XML DOM and Mozilla usually are caused by IE’s non-standard behaviors lsited below:

The probably most comment difference is in the handling whitespace text nodes. Often when XML is generated, it contains whitespaces between XML nodes. In IE, when using XMLNode.childNodes[], it will not contain these whitespace nodes. In Mozilla, those nodes will be in the array.

      XML:
        < xml version="1.0" >      
        <myXMLdoc xmlns:myns="http://myfoo.com">
          <myns:foo>bar</myns:foo>
        </myXMLdoc>   

      JavaScript:
        var myXMLDoc = getXMLDocument().documentElement;
        alert(myXMLDoc.childNodes.length);

The first line of JavaScript loades the XML document and accesses the root element (myXMLDoc) by retrieving the documentElement. The second line simply alerts the number of child nodes. Per the W3C specification, the whitespaces and new lines get merged into 1 text node if the follow eachother, so for Mozilla, the myXMLdoc node has three children: first a text node containing a newline and two spaces, then the myns:foo node, and finally another text node with a new line. Internet Explorer however does not abide by this and will return “1” for the above code, namely only the myns:foo node. Therefore, in order to walk the child nodes and disregard text nodes, it is nessessary to distinguish such nodes.

Every node has a nodeType attribute representing the type of the node. For example, an element node has type 1, while a document node is of type 9. In order to disregard text nodes, one has to check for type’s 3 (text node) and 8 (comment node).

      XML:
        < xml version="1.0" >      
        <myXMLdoc xmlns:myns="http://myfoo.com">
          <myns:foo>bar</myns:foo>
        </myXMLdoc>   

      JavaScript:
        var myXMLDoc = getXMLDocument().documentElement;
        var myChildren = myXMLDoc.childNodes;
        for (var run = 0; run < myChildren.length; run++){
          if ( (myChildren[run].nodeType != 3) && (myChildren[run].nodeType != 8) ){
            // not a text or comment node
          }
        }
XML Data Islands

Internet Explorer has a non-standard feature called XML Data Islands. It allows the embedding of XML inside a HTML document using the non-standard HTML tag <xml>. Mozilla does not support XML Data Islands, and will handle them as unknown HTML tags. The same functionality could be achieved using XHTML, however since Internet Explorer’s support for XHTML is weak, this is usually not a choice.

One cross-browser solution would be to use DOM parsers. DOM parsers parse a string that contains a serialzed XML document, and generate the document for the parsed XML. In Mozilla, the DOMParser class is used, which takes the serialized string and created an XML document out of it. In Internet Explorer, the same functionality can be achieved using ActiveX. A new Microsoft.XMLDOM is generated, and it has a loadXML method that can take in a string and generated a document from it. The following example shows how it can be done:

      IE XML Data Island:
        ..
        <xml id="xmldataisland">
          <foo>bar</foo>
        </xml>  

      Cross Browser Solution:
        var xmlString = "<xml id=\"xmldataisland\"><foo>bar</foo></xml>";
        var myDocument;
      
        if (document.implementation.createDocument){
          // Mozilla, create a new DOMParser
          var parser = new DOMParser();
          myDocument = parser.parseFromString(xmlString, "text/xml");
        } else if (window.ActiveXObject){
          // IE, create a new XML document using ActiveX
          // and use loadXML as a DOM parser.
          myDocument = new ActiveXObject("Microsoft.XMLDOM")
          myDocument.async="false";
          myDocument.loadXML(xmlString);      
        } 
XML HTTP Request

Internet Exploer allows sending and retrieving of XML files using MSXML’s XMLHTTP class, which is instantiated via ActiveX using new ActiveXObject("Msxml2.XMLHTTP") or new ActiveXObject("Microsoft.XMLHTTP"). Since there used to be no standard method of doing this, Mozilla provides the same functionality in the global JavaScript XMLHttpRequest object. It generates asynchronous requests by default.

After instantiating it using new XMLHttpRequest(). the open method is used to specifiy what type of request (GET or POST) should be used, which file to load and if it should be asynchronous or not. If the call is asynchronous, then the onload member should be given a function reference which will be called once the request has completed.

    Synchronous request:

      var myXMLHTTPRequest = new XMLHttpRequest();
      myXMLHTTPRequest.open("GET", "data.xml", false);
      myXMLHTTPRequest.send(null);
      
      var myXMLDocument = myXMLHTTPRequest.responseXML;

    Asynchronous request:
    
      var myXMLHTTPRequest;
  
      function xmlLoaded(){    
        var myXMLDocument = myXMLHTTPRequest.responseXML;
      }
    
      function loadXML(){
        myXMLHTTPRequest = new XMLHttpRequest();  

        myXMLHTTPRequest.open("GET", "data.xml", true);
        myXMLHTTPRequest.onload = xmlLoaded;

        myXMLHTTPRequest.send(null);      
      }

XSLT

Mozilla supports the 1.0 specification of XSL Transformations (XSLT). Mozilla also allows JavaScript to perform XSLT transformations as well as running XPATH on an document.

Mozilla requires that the XML and XSLT file holding the stylesheet be sent with an XML mimetype (text/xml or application/xml). This is the most common reason for XSLT not running in Mozilla, as Internet Explorer is not as strict.

Internet Explorer 5.0 and 5.5 supported the working draft of XSLT, which is substantially different than the final 1.0 recommendation. The easiest way to distinguish what version an XSLT file was written against is to look at the namespace. The namespace for the 1.0 recomendation is http://www.w3.org/1999/XSL/Transform, while the working draft used http://www.w3.org/TR/WD-xsl. Internet Explorer 6 supports the working draft for backwards compatability, but Mozilla does not support the working draft, only the final recommendation.

If distinguishing the browser is required from within XSLT, the “xsl:vendor” system property can be queried. Mozilla’s XSLT engine will report itself as “Transformiix”, and Internet Explorer will return “Microsoft”.

    <xsl:if test="system-property('xsl:vendor') = 'Transformiix'">
      <!-- Mozilla specific markup -->
    </xsl:if>
    <xsl:if test="system-property('xsl:vendor') = 'Microsoft'">
       <!-- IE specific markup -->
    </xsl:if>    

Mozilla also provides JavaScript interfaces for XSLT, allowing a web site to complete XSLT transformation in memory. This is done using the global XSLTProcessor JavaScript object. XSLTProcessor requires one to load the XML and XSLT files, as it requires their DOM documents. The XSLT document is imported by the XSLTProcessor, and allows manipulation of XSLT parameters. XSLTProcessor can generate a standalone document using transformToDocument(), or can create a Document Fragment using transformToFragment() which can be easily appened into another DOM document. Below is an example:

    var xslStylesheet;
    var xsltProcessor = new XSLTProcessor();   

    // load the xslt file, example1.xsl
    var myXMLHTTPRequest = new XMLHttpRequest();
    myXMLHTTPRequest.open("GET", "example1.xsl", false);
    myXMLHTTPRequest.send(null);
 
    // get the XML document and import it
    xslStylesheet = myXMLHTTPRequest.responseXML;      
    xsltProcessor.importStylesheet(xslStylesheet);

    // load the xml file, example1.xml
    myXMLHTTPRequest = new XMLHttpRequest();
    myXMLHTTPRequest.open("GET", "example1.xml", false);
    myXMLHTTPRequest.send(null);

    var xmlSource = myXMLHTTPRequest.responseXML;
 
    var resultDocument = xsltProcessor.transformToDocument(xmlSource);

After creating an XSLTProcessor, the XSLT file is loaded using XMLHttpRequest. Its responseXML member contains the XML document of the XSLT file, which is passed to importStylesheet. XMLHttpRequest is then used again to load the source XML document that is to be transformed, which is then passed to XSLTProcessor‘s transformToDocument method. Below is a list of XSLTProcessor‘s methods:

Method
Description
void importStylesheet(Node styleSheet) Imports the XSLT stylesheet. The styleSheet argument is the root node of an XSLT stylesheet’s DOM document.
DocumentFragment transformToFragment(Node source, Document owner) Transforms the Node source by applying the stylesheet imported using the importStylesheet method and generates a DocumentFragment. owner specifies what DOM document the DocumentFragment should belong to, making it appendable to that DOM document.
Document transformToDocument(Node source) Transforms the Node source by applying the stylesheet imported using the importStylesheet method and returns a standalone DOM document.
void setParameter(String namespaceURI, String localName, Variant value) Sets a parameter in the imported XSLT stylesheet.
Variant getParameter(String namespaceURI, String localName) Gets the value of an parameter in the imported XSLT stylesheet.
void removeParameter(String namespaceURI, String localName) Removes all set parameters from the imported XSLT stylesheet and makes them default to the XSLT-defined defaults.
void clearParameters() Removes all set parameters and sets them to defaults specified in the XSLT stylesheet.
void reset() Removes all parameters and stylesheets.

XML语法

转自:文章大全

http://www.itlearner.com/article/2005/1684.shtml

 

 

 

第四章 XML语法

提纲:

一.XML语法规则

二.元素的语法

三.注释的语法

四.CDATA的语法

五.Namespaces的语法

六.entity的语法

七.DTD的语法


我们就开始学习XML的语法规范,动手写自己的XML文档。

一.XML语法规则

XML的文档和HTML的原代码类似,也是用标识
来标识内容。创建XML文档必须遵守下列重要规则:


规则1:必须有XML声明语句
这一点我们在上一章学习时已经提到过。声明是XML文档的第一句,其

格式
如下:


< xml version=”1.0″ standalone=”yes/no” encoding=”UTF-8″ >
声明的作用
是告诉浏览器或者其它

处理

程序
:这个文档是XML文档。声明语句中的version表示文档遵守的XML规范的版本;standalone表示文档是否附带DTD文件,如果有,参数为no;encoding表示文档所用的语言编码,默认是UTF-8。

规则2:是否有DTD文件
如果文档是一个”有效的XML文档”(见上一章),那么文档一定要有相应DTD文件,并且严格遵守DTD文件制定的规范。DTD文件的声明语句紧跟在XML声明语句后面,格式如下:

<!DOCTYPE type-of-doc SYSTEM/PUBLIC “dtd-name”>
其中:
“!DOCTYPE”是指你要定义一个DOCTYPE;
“type-of-doc”是文档类型的名称,由你自己定义,通常于DTD文件名相同;
“SYSTEM/PUBLIC”这两个参数只用其一。SYSTEM是指文档使用
的私有DTD文件的网址,而PUBLIC则指文档调用一个公用的DTD文件的网址。


“dtd-name” 就是DTD文件的网址和名称。所有DTD文件的后缀名为”.dtd”。
我们还是用上面的例子,应该写成这样:

< xml version=”1.0″ standalone=”no” encode=”UTF-8″ >
<!DOCTYPE filelist SYSTEM “filelist.dtd”>

规则3:注意你的大小写
在XML文档中,大小写是有区别的。

是不同的标识。注意在写元素时,前后标识大小写要保持一样。例如:ajie,写成ajie是错误的。

你最好养成一种习惯,或者全部大写,或者全部小写,或者大写第一个字母。这样可以减少因为大小写不匹配产生的文档错误。

规则4:给属性值加引号
在HTML代码里面,属性值可以加引号,也可以不加。例如:<font color=red>word</font>和<font color=”red”>word</font>都可以被浏览器正确解释。
但是在XML中则规定,所有属性值必须加引号(可以是单引号,也可以是双引号),否则将被视为错误。

规则5:所有的标识必须有相应的结束标识

在HTML中,标识可能不是成对出现的,比如
。而在XML中规定,所有标识必须成对出现,有一个开始标识,就必须有一个结束标识。否则将被视为错误。

规则6:所有的空标识也必须被关闭

空标识就是标识对之间没有内容的标识。比如
,
等标识。在XML中,规定所有的标识必须有结束标识,针对
这样的空标识,XML中处理的方法是在原标识最后加/,就可以了。例如:




<br>应写为<br />;
<META name=”keywords” content=”XML, SGML, HTML”>应写为<META name=”keywords” content=”XML, SGML, HTML” />;
<IMG src= “cool.gif”>应写为<IMG src= “cool.gif” />

二.元素的语法

元素由一对标识以及其中的内容组成。就象这样:ajie。元素的名称和标识的名称是一样的。标识可以用属性来进一步描述。

在XML中,没有任何保留字,所以你可以随心所欲的用任何词语来作为元素名称。但是也必须遵守下列规范:

1.名称中可以包含字母、数字以及其它字母;
2.名称不能以数字或”_” (下划线)开头;
3.名称不能以字母 xml(或 XML 或 Xml ..)开头
4.名称中不能包含空格
5.名称中间不能包含”:”(冒号)

为了使元素更容易阅读理解和操作,我们还有一些建议:

1.名称中不要使用”.”。因为在很多程序语言中,”.”是作为对象的属性,例如:font.color。同样的原因”-“也最好不要用,必须使用的,以”_”代替;


2.名称尽量简短。
3.名称的大小写尽量采用同一标准。
4.名称可以使用非英文字符,比如用中文。但是有些软件可能不支持
。(IE5目前是支持中文元素的。)

另外,补充一点关于属性的说明。在HTML中,属性可以用来定义元素的显示格式,比如:word
将把word显示为红色。而在XML中,属性只是对标识的描述,与元素内容的显示无关。例如同样一句:word
,并不会将word显示为红色。(那么,有网友会问:如何在XML中将文字显示为红色呢?这就需要使用CSS或者XSL,我们在下面详细讲述。)

三.注释的语法

注释是为了便于阅读和理解,在XML文档添加的附加信息,将不会被程序解释或则浏览器显示。

注释的语法如下:

<!– 这里是注释信息 –>

可以看到,它和HTML中的注释语法是一样的,非常容易。养成良好的注释习惯将使你的文档更加便于维护,共享,看起来也更专业。

四.CDATA的语法

CDATA全称character data,翻译为字符数据
。我们在写XML文档时,有时需要显示字母,数字和其它的符号本身,比如”<“,而在XML中,这些字符已经有特殊的含义,我们怎么办呢?这就需要用到CDATA语法。语法格式如下:



<![CDATA[这里放置需要显示的字符]]>
例如:
<![CDATA[<AUTHOR sex=”female”>ajie</AUTHOR>]]>
在页面上显示的内容将是”<AUTHOR sex=”female”>ajie</AUTHOR>”

五.Namespaces的语法

Namespaces翻译为名字空间。名字空间有什么作用呢?当我们在一个XML文档中使用他人的或者多个DTD文件,就会出现这样的矛盾:因为XML中标识都是自己创建的,在不同的DTD文件中,标识名可能相同但表示的含义不同,这就可能引起数据混乱。





比如在一个文档<table>wood table</table>中<table>表示桌子,
而在另一个文档
namelist


表示表格。如果我需要同时处理这两个文档,就会发生名字冲突。



了解决这个问题,我们引进了namespaces这个概念。namespaces通过给标识名称加一个网址(URL)定位的方法来区别这些名称相同的标识。


Namespaces同样需要在XML文档的开头部分声明,声明的语法如下:
<document xmlns:yourname=’URL’>
其中yourname是由你定义的namespaces的名称,URL就是名字空间的网址。
假设上面的”桌子
“文档来自http://www.zhuozi.com,我们就可以声明为



<document xmlns:zhuozi=’http://www.zhuozi.com’>
然后在后面的标识中使用定义好的名字空间:


<zhuozi:table>wood table</table>
这样就将这两个
区分开来。注意的是:设置URL并不是说这个标识真的要到那个网址去读取,仅仅作为一种区别的标志而已。

六.entity的语法

entity翻译为”实体”。它的作用类似word中的”宏”,也可以理解为DW中的摸板,你可以预先定义一个entity,然后在一个文档中多次调用,或者在多个文档中调用同一个entity。

entity
可以包含字符,文字等等,使用entity的好处在于:1.它可以减少差错,文档中多个相同的部分只需要输入一遍就可以了。2.它提高维护效率。比如你有
40个文档都包含copyright的entity,如果需要修改这个copyright,不需要所有的文件都修改,只要改最初定义的entity语句就
可以了。


XML定义了两种类型的entity。一种是我们这里说的普通entity,在XML文档中使用;另一种是参数entity,在DTD文件中使用。


entity的定义语法为:
<!DOCTYPE filename [
<!ENTITY entity-name “entity-content”
]
>
例如我要定义一段版权信息:
<!DOCTYPE copyright [
<!ENTITY copyright “Copyright 2001, Ajie. All rights reserved”
]
>
如果我的版权信息内容和他人共享一个XML文件,也可以使用外部调用的方法,语法象这样:

<!DOCTYPE copyright [
<!ENTITY copyright SYSTEM “http://www.sample.com/copyright.xml”>
]
>
定义好的entity在文档中的引用语法为:&entity-name;
例如,上面定义的版权信息,调用时写作:&copyright;
完整的例子如下,你可以copy下来存为copyright.xml观看实例:
< xml version=”1.0″ encoding=”GB2312″ >
<!DOCTYPE copyright [
<!ENTITY copyright “Copyright 2001, Ajie. All rights reserved”>
]>
<myfile>
<title>XML</title>
<author>ajie</author>
<email>ajie@aolhoo.com</email>
<date>20010115</date>
&copyright;
</myfile>

七.DTD的语法

DTD是”有效XML文档”的必须文件,我们通过DTD文件来定义文档中元素和标识的规则及相互关系。如何建立一个DTD文件呢?让我们一起来学习:

1.设置元素

元素是XML文档的基本组成部分。你要在DTD中定义一个元素,然后在XML文档中使用。元素的定义语法为:<!—->

说明:

“<!ELEMENT” 是元素的声明,说明你要定义的是一个元素;

声明后面的”DESCRIPTION”,是元素的名称;

“(#PCDATA, DEFINITION)*>”则是该元素的使用规则。规则定义了元素可以包含的内容以及相互的关系。下面的表格概要列出了元素的规则:

2.元素规则表:

Symbol
含义
举例

#PCDATA

包含字符或文本数据

<MYFILE(#PCDATA)>
元素MYFILE包含一个文本数据

#PCDATA, element-name
包含文本和其它子元素
<MYFILE(#PCDTATA,TITLE)>
MYFILE元素必须包含文本和TITLE子元素

,

使用逗号分隔排序

<MYFILE (TITLE,AUTHOR,EMAIL)>
MYFILE元素必须依次包含TITILE,AUTHOR,EMAIL三个子元素

|
使用”|”表示或者

<MYFILE (TITLE | AUTHOR | EMAIL)>
MYFILE元素必须包含TITLE,或者AUTHOR或者EMAIL子元素。

name
只能使用一次

<MYFILE (TITLE)>
MYFILE元素必须包含TITLE子元素,而且只能使用一次。

name 

使用一次或者不使用

<MYFILE (TITLE,AUTHOR ,EMAIL )>
MYFILE元素必须包含TITLE子元素,而且只能使用一次;可以包含或者不包含AUTHOR和EMAIL子元素,但是如果使用,只能一次。

name+

使用至少一次或多次

<MYFILE (TITLE+,AUTHOR ,EMAIL)>
MYFILE元素必须包含TITLE子元素,而且使用至少一次;接下来可以跟随AUTHOR子元素,也可以不跟;最后必须包含EMAIL子元素,而且只能使用一次。

name*

使用一次,多次,或者根本不使用

<MYFILE (TITLE*)>
MYFILE元素可以包含一个,多个或者不包含TITLE子元素

( )

设置组,可以嵌套
<MYFILE(#PCDATA | TITLE)*>
元素MYFILE包含一个或者更多的文本或者TITLE子元素。

<MYFILE((TITLE*, AUTHOR , EMAIL)* | COMMENT)>
MYFILE元素必须包含一些内容,内容或者是一个注释;也或者是多个组,组里包含:一个,多个或者没有TITLE子元素,接着是一个或者没有AUTHOR子元素,再接着是一个必须的EMAIL子元素。

另外,我们还可以为元素定义属性,因为我们不推荐使用属性,在这里就不详细展开了。

 最后,我们来总结一些前四章学习的内容,写一个包含DTD,XML,以及Script的简单实例,便于读者理解:


1.将下面文件存为myfile.dtd
<!ELEMENT myfile (title, author)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>

2.然后建立XML文档myfile.xml:
< xml version=”1.0″ encoding=”GB2312″ >
<!DOCTYPE myfile SYSTEM “myfile.dtd”>
<myfile>
XML轻松学习手册

<author>ajie</author>
</myfile>

3.建立HTML文档myfile.html
<html>
<head>
<script language=”javascript” for=”window” event=”onload”>
var xmlDoc = new ActiveXObject(“Microsoft.XMLDOM”);
xmlDoc.async=”false”;
xmlDoc.load(“myfile.xml”);
nodes = xmlDoc.documentElement.childNodes;
title.innerText = nodes.item(0).text;
author.innerText = nodes.item(1).text;
</script>
在HTML中调用XML数据

</head>
<body bgcolor=”#FFFFFF”>
<b>标题: </b>
<span id=”title”></span><br>
<b>作者: </b>
<span id=”author”></span><br>
</body>
</html>

4.用IE5.0以上浏览器打开myfile.html就可以看到效果了。