NuttyCoder's profile初级程序员BlogLists Tools Help

Blog


    5/6/2008

    NET USE

    NET USE
    [devicename | *] [\\computername\sharename[\volume] [password | *]]
    [/USER:[domainname\]username]
    [/USER:[dotted domain name\]username]
    [/USER:[username@dotted domain name]
    [/SMARTCARD]
    [/SAVECRED]
    [[/DELETE] | [/PERSISTENT:{YES | NO}]]
    NET USE {devicename | *} [password | *] /HOME
    NET USE [/PERSISTENT:{YES | NO}]
    NET USE 用于将计算机与共享的资源相连接,或者切断计算机与共享资源的
    连接。当不带选项使用本命令时,它会列出计算机的连接。
    devicename 指定一个名字以便与资源相连接,或者指定要切断的设备。有两种类型
    的设备名:磁盘驱动器 (D: 至 Z:) 和打印机 (LPT1: 至 LPT3:)。输入
    一个星号来代替一个指定的设备名可以分配下一个可用设备名。
    \\computername 指控制共享资源的计算机的名字。如果计算机名中包含有空字符,就要
    将双反斜线 (\\) 和计算机名一起用引号 (" ")括起来。计算机名可以
    有1 到 15 个 字符。
    \sharename 指共享资源的网络名字。
    \volume 指定一个服务器上的 NetWare 卷。用户必须安装 Netware 的客户服务
    (Windows 工作站) 或者 Netware 的网关服务(Windows 服务器) 并使之
    与 NetWare 服务器相连。
    password 指访问共享资源所需要的密码。
    * 进行密码提示。当在密码提示符下输入密码时,密码是不会显示。
    /USER 指定连接时的一个不同的用户名。
    domainname 指定另外一个域。如果缺省域,就会使用当前登录的域。
    username 指定登录的用户名。
    /SMARTCARD 指定连接使用在智能卡上的凭据。
    /SAVECRED 指定保留用户名和密码。此开关被忽略,除非命令
    提示输入用户名和密码。
    /HOME 将用户与他们的主目录相连。
    /DELETE 取消一个网络连接,并且从永久连接列表中删除该连接。
    /PERSISTENT 控制对永久网络连接的使用。其默认值是最近使用的设置。
    YES 在连接产生时保存它们,并在下次登录时恢复它们。
    NO 不保存正在产生的连接或后续的连接;现有的连接将在下次登录时
    恢复。可以使用 /DELETE 选项开关来删除永久连接。

    4/21/2008

    有关 JavaScript 及其它的一点点

    1、对其它对象的临时引用尽量不要用对象的属性,因为会长时间的占用资源,只有当对象消亡的时候才会释放。一般来说用var定义临时变量就好了。(当然更不能不用var而成为默认的全局变量......= =)

    2、不要乱用alert,调试的时候加上的try...catch、alert等代码要在发布或调试基本完成后及时清理。

    3、(编码习惯)用空格缩进,不要用Tab。Tab在不同的环境下的解释是不同的,可能造成排版的混乱。

    4、(GI)少用Layout,尽量用Block布局。Block在界面变化中耗费较多时间,一个Layout通常意味着存在三个Block,改为一个Block,可以节省两个Block。

    3/28/2008

    Use XSLT to Dispose Data in Matrix

    Both Matrix and Matrix.Column have a property named "jsxvaluetemplate". The value of this property should be a XSLT. JSX engine transform the CDF with this XSLT. So, sometimes we could dispose data in matrix with this property.

    <xsl:template xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:choose>
            <xsl:when test="@property1 = 'false' ">
                <span style="width:100%; height:100%; background-color: #FFFFFF; font-weight:bold">
                    <xsl:value-of select="{0}"/>
                </span>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:choose>
                        <xsl:when test="@property2 = 'false' ">
                            <span style="width:100%; height:100%; background-color: #FFFFFF; font-weight:bold">
                                <xsl:value-of select="{0}"/>
                            </span>
                        </xsl:when>
                        <xsl:otherwise>
                            <span style="width:100%; height:100%; background-color: #FFFFFF; font-weight:bold; padding-left:2px; cursor:pointer;cursor:hand; text-decoration:underline; color:blue;" onmousedown="function1('{@property3}');">
                                Remove
                            </span>
                        </xsl:otherwise>
                    </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    For example, the XSLT above will judge "property1" and "property2", only if they are all true, a "remove" link would be shown. "@property1" is a way to quote property "property1" of the record, while "{@property3}" is another way, in string argument, maybe. (I'm not clear on it now.)

    Sometimes we have to use data in JavaScript, but not only in CDF. In this condition, we could split the XSLT to some joint strings, then save as a JSS record, which is set to be evaluated. So each part of the XSLT could be replace with a section of JavaScript.

    Following is the value of "jsxtext" in a JSS record:

    '<xsl:template xmlns:xsl="http://www.w3.org/1999/XSL/Transform">    <xsl:choose>        <xsl:when test="@property1 = \'false\' ">            <span style="width:100%; height:100%; background-color: #FFFFFF; font-weight:bold">            <xsl:value-of select="{0}"/>            </span>        </xsl:when>        <xsl:otherwise>            <xsl:choose>                <xsl:when test="@property2 = \'false\' ">                    <span style="width:100%; height:100%; background-color: #FFFFFF; font-weight:bold">                        <xsl:value-of select="{0}"/>                    </span>                </xsl:when>                <xsl:otherwise>                    <span style="width:100%; height:100%; background-color: #FFFFFF; font-weight:bold; padding-left:2px; cursor:pointer;cursor:hand; text-decoration:underline; color:' + getDynamicProperty("@addin@Link Color") + '" onmousedown="function1(\'{@property3}\');">                        Remove                    </span>                </xsl:otherwise>            </xsl:choose>        </xsl:otherwise>    </xsl:choose></xsl:template>'

    There are 3 parts in it. The second one is JavaScript code and used for getting data in JS.

    Notify: "'" should be changed to "\'" when in JS string.

    3/26/2008

    Replace String whit Regular Expression in Editplus

    Sometimes we need to replace strings in the same pattern in Editplus. For example, I have to add post-fix to "jsxname" attribute for every component in a UI file(XML) just now. These attributes appear as '<record jsxname="......">'.

    Pattern: jsxname="([^"]*)"

    [^"]: any charactor except ".

    [^"]*: a string without ".

    (): Affects evaluation order of expression and also used for tagged expression.

    Replace With: jsxname="\1_100"

    \1: evaluate [^"]* in ().

    用PubSub传递List-Details形式的消息

    List-Details是一种很常见的界面表现形式。页面载入时,List首先被显示。当用户点击某条记录时(或其它动作),该条记录相关的Details显示出来。SPM的某些部分中,PubSub被用来完成List-Details消息的传递。

    例如在Rule Library中(文件位于rule/library/),当用户选择一条记录时,会触发RuleLibMaster中的publishSelect。此函数将必要的信息装入Message并publish。这条消息在RuleLibrary和RuleLibDetail中分别被订阅,他们会先后(?)先后接收到消息。作为顶层框架,RuleLibrary会检查右侧Detail Panel是否已经被载入,如果没有,RuleLibrary会将该Components载入。随后(?)RuleLibDetail会分析Message,并将Message中的Record信息显示在Detail Panel上。

    我在windowShadow的Alert中仿照了Rule Library中的这种处理方式。由List publish消息,顶层框架订阅消息装载Panel,Details Panel订阅消息并显示信息。

    List-Details形式的消息比较单纯,所以直接调用Detail Panel的相关函数并通过参数传递信息并不显得复杂。但是更多时候,PubSub可以使程序逻辑更清晰。从设计的角度看,PubSub机制为不同模块之间实现了更松散的耦合。据说PubSub使用全局变量的设计会消耗更多的内存,是这种方式的一个弊端,及时的unsubscribe也许可以缓解这个问题。

    3/26/2007

    [Nova@PHP]模版编译程序设计

    模版编译程序设计
    总体结构
    1,获取必要信息
    2,编译
    3,输出文件/缓存
    变量设计
    系统配置变量
    DATACACHE = 0 是否缓存数据项,默认为零,全部数据项重新读取.
    编译过程变量
    CacheSetup 缓存设置
    Cached data elements set(CDES[]) 缓存的数据项集,适用于CacheSetup=1
    Non-cached data elements set(NCDES[]) 不缓存的数据项集,适用于CacheSetup=2
    Instant data elements set(IDES[][2]) 即时获取的数据项集(AJAX)(0.Item/1.间隔)
    User-defined keywords(UDK) 是否自定义保留字
    User-defined keywords set(UDKS[][]) 自定义保留字集,适用于UDK=1
    Tp_Var 模版版本
    Tp_LastUpdate 模版最后更新时间
    Data_Var 数据版本
    ItemSet[][2] 数据标识及数据集(0.Item/1.Value)
    Sect[][4] 编译段落(0.All/1.类别/2.HTML段/3.编译后值)
    函数设计
    1.GetItems()
    功能:从模版中获取ItemSet[]
    返回:ItemSet[][0]
    2.GetSection()
    功能:从模版中获取编译段落
    返回:Sect[][0,1,2]
    3.ChkTpVar()
    功能:检查模版是否有更新
    返回:Bool value
    6.GetInfo()
    功能:获取必要信息主函数
    返回:设置所有必要信息

    4.GetValues()
    功能:获取每个Item对应的Value
    返回:Sect[][3]
    5.Compile()
    功能:编译模版
    返回:编译完成的模版

    6.Output()
    功能:输出缓存文件,刷新模版文件等
    返回:无
    7.Response()
    功能:向浏览器响应
    返回:无

    [Nova@PHP]模版结构v0.2

    模版文件结构
    <!--
    $$Rem
    {
    //注释信息,本区段不参与编译
    模版版本:
    相关说明:
    }
    $$Config

    //配置变量
    $$Cache={0|1|2|3};(不缓存|缓存某变量|不缓存某变量|全部缓存}
    如果Cache=1
    $$CacheSet={标识名,标识名,标识名...};
    如果Cache=2
    $$NoCacheSet={标识名,标识名,标识名...};
    如果自定义保留字
    $$User-Defined_Keywords={段开始符,段分隔符,段结束符,数据标识前导符},{段开始符,段分隔符,段结束符,数据标识前导符}...;
    }
    $$Compile
    {
    //编译信息,这部分由编译程序在模版最后添加
    $$Tp_Var=1;
    $$Tp_LastUpdate=2007-3-21 20:00:00;
    $$Data_Var=101010010110;
    $$Items=a,b,c,d;
    $$Values=A,B,C,D;
    }
    -->
    $$HTMLBEGIN
    模版体HTML内容
    其中编译段结构如下
    {
    段开始符 类型{单值|循环(最大循环次数)[,条件]} 段分隔符 含有数据标识的HTML 段结束符
    段开始符:可自定义,编译段开始的标志,从此位置到结束符之间的内容将被编译器解析.
    段结束符:可自定义,编译段结束的标志.
    段分割符:可自定义,分割编译段中的不同部分.
    类型:标识此编译段的类型,具体如下
    单值:编译器将根据此编译段中的数据标识找到唯一的数据替换到HTML串中
    循环(最大循环次数):编译器将根据数据标识找到一组数据,将每个分别替换到HTML段中得到一段HTML,合并后输出.当组中元素小于最大循环次数时,以组中元素个数为准.当最大循环次数为0时以组中元素个数为准.
    条件:输出单值的条件或循环中某次是否输出的条件,可以为常量或者单个数据标识
    含有数据标识的HTML:编译器将段落中的数据标识替换为相应数据拼接后输出.
    单值:single
    循环:iteration
    默认段开始符:{|
    默认段分隔符||
    默认段结束符|}
    默认数据标识前导符$$
    循环变量:Iter(从1开始)
    }
    $$HTMLEND
    3/21/2007

    [Nova@PHP]模版结构v0.1

    模版文件结构
    <!--
    $$Rem
    {
    //注释信息,本区段不参与编译
    模版版本:
    相关说明:
    }
    $$Config
    {
    //配置变量
    Cache={0|1|2|3}(不缓存|缓存某变量|不缓存某变量|全部缓存}
    如果Cache=1
    CacheSet={标识名,标识名,标识名...}
    如果Cache=2
    NoCacheSet={标识名,标识名,标识名...}
    如果自定义保留字
    User-Defined_Keywords={段开始符,段分隔符,段结束符,数据标识前导符},{段开始符
    ,段分隔符,段结束符,数据标识前导符}...
    }
    -->

    模版体HTML内容
    其中编译段结构如下
    {
    段开始符 类型{单值|循环(最大循环次数)[,条件]} 段分隔符 含有数据标识的HTML
    段结束符
    段开始符:可自定义,编译段开始的标志,从此位置到结束符之间的内容将被编译器解析
    .
    段结束符:可自定义,编译段结束的标志.
    段分割符:可自定义,分割编译段中的不同部分.
    类型:标识此编译段的类型,具体如下
    单值:编译器将根据此编译段中的数据标识找到唯一的数据替换到HTML串中
    循环(最大循环次数):编译器将根据数据标识找到一组数据,将每个分别替换到HTML段
    中得到一段HTML,合并后输出.当组中元素小于最大循环次数时,以组中元素个数为准.
    当最大循环次数为0时以组中元素个数为准.
    条件:输出单值的条件或循环中某次是否输出的条件,可以为常量或者单个数据标识
    含有数据标识的HTML:编译器将段落中的数据标识替换为相应数据拼接后输出.
    单值:single
    循环:iteration
    默认段开始符:{|
    默认段分隔符||
    默认段结束符|}
    默认数据标识前导符$$
    循环变量:Iter(从1开始)
    }
    <!--
    $$Translate
    {
    //编译信息,这部分由编译程序在模版最后添加
    Var=1;
    DateTime=2007-3-21 20:00:00;
    DataEdition=101010010110;
    Variables=a,b,c,d;
    }
    -->
     
     
    注:也考虑将配置信息写在对应的.php文件中,此事待定.
    3/16/2007

    [Nova@PHP]网站从需求分析开始

    在网站开发的第一阶段,应确定需求,并且由需求分析文档得到功能需求。分析功能需求,将其划分为多个模块分别加以实现。
    在模块级别上,分析用户任务路径,应绘制用例图。从任务路径可以得到所需用户界面以及数据入口,此二项是直接和Nova@PHP相关的。只有完成以上工作,Nova@PHP才可以在接下来的过程中发挥作用,见附图。
     
    美工人员根据界面设计创建模版。模版中除HTML外,还应包含如下内容:
    1、模版程序段。模版程序段是为不变的模版写入变化的数据的部分。其内容又包括数据内容(对象、对象组)和控制内容(选择/判断、循环)。编译过程就是分析模版中的程序段,并根据程序段向模版中拼接入相应的数据。
    2、配置信息和编译信息。配置信息由开发者按照约定格式写入主要是关于缓存:此页面是否被缓存、缓存级别等;编译信息由编译程序写入,包括最后编译时间、模版版本、模版中引用的数据以及这些数据的版本等等。
    模版机制:
    接受请求-》根据请求装载模版-》分析配置信息和编译信息-》校验模版更新日期-》如果无缓存则生成并输入页面-》如果有缓存,则检查缓存版本-》如果缓存版本最新则输出页面-》如果已经有数据更新则重新生成页面-》重新生成缓存-》输出页面
    数据引擎部分的一点想法
    见附图。由数据流分析得到数据元素(数据对象),比对用户任务路径和界面,构造多个数据投影。数据投影可能是某个数据对象的一部分属性,也可能是几个数据对象某些属性的集合。数据投影直接对应界面上某处现实,或某处表单提交的内容。数据对象不直接面向模版,而有投影来实现。
    3/15/2007

    [Nova@PHP]开始时候的话

    Nova@PHP被设计为一个PHP模版引擎,用以实现数据和数据的表现的分离。显然,其名字来源于Nova+(ASP),鉴于Nova@PHP和Nova+纠缠不清的关系,我想先赘述一下Nova+。
    Nova+是一个ASP项目,大一下学期提出时名字是Nova,是一个ASP框架(不过那时候我还没有理解什么是框架)。暑假我和Ripple等五人完成大部分功能类,事实上把这个项目变成了一个函数库项目。我们用VBS类的形式将ASP中常用的功能重写增强。这些类后来一直被我用在很多ASP项目中,还算好用吧。大二以后,因为种种原因,Nova变成我一个人的项目,方向也有所偏转,更名为Nova+。经过了几次徘徊后,我在Nova+中重点实现了数据和表现分离以及静态化。Nova+在这方面被我认为成功,但是作为ASP为基础的技术发展潜力不大,所以停工掉。也是停工后,我才意识到我写的是一种叫做模版引擎的东西。在Nova+周围,还衍生出了两个未完成的部分:一个是想象中的数据引擎,可以理解为PHP框架中的数据库抽象类,数据库抽象类我还未及了解,但是想象中的数据引擎除了数据库抽象外还重点考虑数据多级缓存机制;另一个是NPPassport,是一个跨域整合身份验证系统。其中后者完成度稍高一些,前者可以认为尚在想象阶段。这两个东西原本是纠缠在Nova+里面的,直到大二的下学期我才明智的把他们剥离,成为独立的两个东西。这些东西里面基本融入了我对ASP的所有理解以及经验,虽然有些部分还糙了点。
    下面说Nova@PHP
    作为一个可以独立引用的模版引擎,但是事实上Nova@PHP并并不是一个孤立的项目:它是设想中的PHP Framework的一部分。我从06年底开始对PHP Framework产生兴趣。大多数人认为目前PHP Framework的发展并不理想,没有非常合用的作品。当然目前我还没有勇气说填补这个空白,我的目标只是借此完成我的PHP学习,实践一下从ASP项目中获得的经验,同时增加对“框架”和“模式”的认识。目前我想象中PHP Framework中可能包括模版引擎(包括静态化模块),数据引擎(包括数据缓存),身份认证模块等,当然还很模糊。我原想做出一个完整的设计再开工,但是发现做不到,不大现实,也没有必要。事实上整个框架可以被设计为几个分立的部分,每个部分单独设计完成是可以实现的。所以,这个未命名的Framework是一个多模块集成结构,其开发周期也将分为几个段落,并且我在开工时候只能预计当前段落的时间成本。我希望这个蓝图随着时间和当前部分的推进而日渐清晰。
    正是因为Nova+积累了不少经验的缘故,所以我选取模版引擎作为整个PHP框架计划的第一动工的项目。我目前对PHP还不很了解,只在做作业的时候写过一个没有实用价值的小站。所以3月底以前,我要做的只是在语法要求内将Nova+由ASP翻译为PHP,并作为Nova@PHP的第一个版本。之后的时间我会随着PHP了解的增加,根据PHP的特点对它作一些有限的优化。不会很多,因为对PHP了解必经尚浅。可能我会用这个版本的Nova@PHP重写视听在线(vod.bitnp.net)。随后会立即开始第二个部分,有可能是数据引擎吧,未定。如果是的话,可能在完成后重写GoShop(go.bitnp.net)。目前只想好这么多,可以权当只有一个模板引擎的计划吧。
    Nova@PHP将是一个轻量级的模板引擎,着重实现常用功能,第一个版本的目标主要锁定在:1、易上手;2、易用;3、满足中小型常规站点功能需要;4、效率不差。
    易上手是指一个新人从未知到掌握使用方法的过程要容易。易用指的是其应用简洁而非繁琐。之所以将这两条写在前面,是因为搜索引擎上看到的大部分人对于目前的模版引擎的抱怨是复杂难以驾驭。虽然某些人确实懒得可以,但是毕竟程序开发的目标就是解决问题,如果Nova@PHP能因为简单简洁成为大家喜欢用的模版引擎,那么也就算成功了。
    Nova@PHP项目从今天正式开始了。
    8/14/2006

    与Lonecat达人的一次邮件往来

    > 我之前一年多一直在做,这学期开始觉得自己缺少很多知识了......尤其是数据结构课程结束后,觉得自己所学甚少。现在的开发都是在一个很低的技术平面上。这一年几乎没有什么技术上的进展。所以想学点新的东西了。比如最近同学们都在忙着学Linux,我也想学学Java......所以可能最近不再做开发了。下一次再去做兼职,应该是做一些高技术含量的啦,呵呵,现在觉得自己就是一个Asp代码工人......觉得自己在浪费时间。
    > 我在刚来大学的时候觉得在技术上是超出其他同学很多的,毕竟其余的人在来大学之前几乎没有接触过编程。而我已经有了几年的经历。但是现在越来越感到,自己的技术一直没有进步,尤其是理论基础,始终停留在"爱好者"的层面上......看着大家在讨论什么"象棋对弈"等等算法要求比较高的问题,我就觉得自己拿Asp做网站几乎完全是浪费时间。
    > 关于这点,我也很想听听您的意见。技术和实践,理论基础和应用经验,究竟应该如何平衡呢?
     
    REPLY:
    我觉得你的想法挺对的,如果你已经有了这个方面的经验,完全没有必要把所有的时间都花在兼职上。兼职只是一种经历,做一下是为了积累经验接触社会,但不能做太多,那样就浪费时间了。
    另外我觉得大学期间应该尽量提高技术水平,多学一些东西,如果做一个东西什么都学不到,只是重复劳动,那就没有必要做了。
    每个人喜好的方向可能不同,譬如象棋的算法和网站完全是两个不同的方向,但无论在哪个方向上努力,都应该尽量多学一点,尽量做好一点。即便是做网站,也有很多东西可以学,譬如LAMP、AJAX,还有很多跟网络相关的技术都应该有所了解,更重要的是把OOAD学好。而且即便是网络也可以和其它的东西相关,因此尽量把本科阶段的课程学好,因为你不知道以后哪天就会需要他们。
    我们经常会拿武侠小说中的练武来比学习,技术就好比一种拳法、理论就好比内力而实践就好比江湖经验。拳法学的再多,没有内力一样没法施展;空有内力没有招式,打架的时候就会吃亏,因为内力没有发挥的途径;而完全没有江湖经验,出去混很容易吃亏。所以这三点都很重要,而你现在可能应该更多的练习内力,这样你就可以去学习更加上乘的武功,我想你的江湖阅历已经够了,暂时应该隐居一段时间。
    当然学习的时候也尽量配合实践,因为很多东西不做是学不会的。
     
     

    [教程]C语言文件操作

    13.3 文件的打开与关闭

    文件在进行读写操作之前要先打开,使用完毕要关闭。所谓打开文件,实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其它操作。关闭文件则断开指针与文件之间的联系,也就禁止再对该文件进行操作。
    在C语言中,文件操作都是由库函数来完成的。在本章内将介绍主要的文件操作函数。

    13.3.1 文件的打开(fopen函数)

    fopen函数用来打开一个文件,其调用的一般形式为:
    文件指针名=fopen(文件名,使用文件方式);
    其中,
    “文件指针名”必须是被说明为FILE 类型的指针变量;
    “文件名”是被打开文件的文件名;
    “使用文件方式”是指文件的类型和操作要求。
    “文件名”是字符串常量或字符串数组。
    例如:
    FILE *fp;
    fp=("file a","r");
    其意义是在当前目录下打开文件file a,只允许进行“读”操作,并使fp指向该文件。
    又如:
    FILE *fphzk
    fphzk=("c:\\hzk16","rb")
    其意义是打开C驱动器磁盘的根目录下的文件hzk16,这是一个二进制文件,只允许按二进制方式进行读操作。两个反斜线“\\ ”中的第一个表示转义字符,第二个表示根目录。
    使用文件的方式共有12种,下面给出了它们的符号和意义。
    文件使用方式
    意义
    “rt”
    只读打开一个文本文件,只允许读数据
    “wt”
    只写打开或建立一个文本文件,只允许写数据
    “at”
    追加打开一个文本文件,并在文件末尾写数据
    “rb”
    只读打开一个二进制文件,只允许读数据
    “wb”
    只写打开或建立一个二进制文件,只允许写数据
    “ab”
    追加打开一个二进制文件,并在文件末尾写数据
    “rt+”
    读写打开一个文本文件,允许读和写
    “wt+”
    读写打开或建立一个文本文件,允许读写
    “at+”
    读写打开一个文本文件,允许读,或在文件末追加数据
    “rb+”
    读写打开一个二进制文件,允许读和写
    “wb+”
    读写打开或建立一个二进制文件,允许读和写
    “ab+”
    读写打开一个二进制文件,允许读,或在文件末追加数据

    对于文件使用方式有以下几点说明:
    1) 文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是:
    r(read): 读
    w(write): 写
    a(append): 追加
    t(text): 文本文件,可省略不写
    b(banary): 二进制文件
    +: 读和写
    2) 凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。
    3) 用“w”打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。
    4) 若要向一个已存在的文件追加新的信息,只能用“a”方式打开文件。但此时该文件必须是存在的,否则将会出错。
    5) 在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理。因此常用以下程序段打开文件:
    6)
    if((fp=fopen("c:\\hzk16","rb")==NULL)
    {
    printf("\nerror on open c:\\hzk16 file!");
    getch();
    exit(1);
    }
    这段程序的意义是,如果返回的指针为空,表示不能打开C盘根目录下的hzk16文件,则给出提示信息“error on open c:\ hzk16 file!”,下一行getch()的功能是从键盘输入一个字符,但不在屏幕上显示。在这里,该行的作用是等待,只有当用户从键盘敲任一键时,程序才继续执行,因此用户可利用这个等待时间阅读出错提示。敲键后执行exit(1)退出程序。
    7) 把一个文本文件读入内存时,要将ASCII码转换成二进制码,而把文件以文本方式写入磁盘时,也要把二进制码转换成ASCII码,因此文本文件的读写要花费较多的转换时间。对二进制文件的读写不存在这种转换。
    8) 标准输入文件(键盘),标准输出文件(显示器),标准出错输出(出错信息)是由系统打开的,可直接使用。

    13.3.2 文件关闭函数(fclose函数)

    文件一旦使用完毕,应用关闭文件函数把文件关闭,以避免文件的数据丢失等错误。
    fclose函数调用的一般形式是:
    fclose(文件指针);
    例如:
    fclose(fp);
    正常完成关闭文件操作时,fclose函数返回值为0。如返回非零值则表示有错误发生。

    13.4 文件的读写

    对文件的读和写是最常用的文件操作。在C语言中提供了多种文件读写的函数:
    ·字符读写函数 :fgetc和fputc
    ·字符串读写函数:fgets和fputs
    ·数据块读写函数:freed和fwrite
    ·格式化读写函数:fscanf和fprinf
    下面分别予以介绍。使用以上函数都要求包含头文件stdio.h。

    13.4.1 字符读写函数fgetc和fputc

    字符读写函数是以字符(字节)为单位的读写函数。每次可从文件读出或向文件写入一个字符。
    1. 读字符函数fgetc
    fgetc函数的功能是从指定的文件中读一个字符,函数调用的形式为:
    字符变量=fgetc(文件指针);
    例如:
    ch=fgetc(fp);
    其意义是从打开的文件fp中读取一个字符并送入ch中。
    对于fgetc函数的使用有以下几点说明:
    1) 在fgetc函数调用中,读取的文件必须是以读或读写方式打开的。
    2) 读取字符的结果也可以不向字符变量赋值,
    例如:
    fgetc(fp);
    但是读出的字符不能保存。
    3) 在文件内部有一个位置指针。用来指向文件的当前读写字节。在文件打开时,该指针总是指向文件的第一个字节。使用fgetc 函数后,该位置指针将向后移动一个字节。 因此可连续多次使用fgetc函数,读取多个字符。应注意文件指针和文件内部的位置指针不是一回事。文件指针是指向整个文件的,须在程序中定义说明,只要不重新赋值,文件指针的值是不变的。文件内部的位置指针用以指示文件内部的当前读写位置,每读写一次,该指针均向后移动,它不需在程序中定义说明,而是由系统自动设置的。
    【例13.1】读入文件c1.doc,在屏幕上输出。
    #include<stdio.h>
    main()
    {
    FILE *fp;
    char ch;
    if((fp=fopen("d:\\jrzh\\example\\c1.txt","rt"))==NULL)
    {
    printf("\nCannot open file strike any key exit!");
    getch();
    exit(1);
    }
    ch=fgetc(fp);
    while(ch!=EOF)
    {
    putchar(ch);
    ch=fgetc(fp);
    }
    fclose(fp);
    }
    本例程序的功能是从文件中逐个读取字符,在屏幕上显示。程序定义了文件指针fp,以读文本文件方式打开文件“d:\\jrzh\\example\\ex1_1.c”,并使fp指向该文件。如打开文件出错,给出提示并退出程序。程序第12行先读出一个字符,然后进入循环,只要读出的字符不是文件结束标志(每个文件末有一结束标志EOF)就把该字符显示在屏幕上,再读入下一字符。每读一次,文件内部的位置指针向后移动一个字符,文件结束时,该指针指向EOF。执行本程序将显示整个文件。
    2. 写字符函数fputc
    fputc函数的功能是把一个字符写入指定的文件中,函数调用的形式为:
    fputc(字符量,文件指针);
    其中,待写入的字符量可以是字符常量或变量,例如:
    fputc('a',fp);
    其意义是把字符a写入fp所指向的文件中。
    对于fputc函数的使用也要说明几点:
    1) 被写入的文件可以用写、读写、追加方式打开,用写或读写方式打开一个已存在的文件时将清除原有的文件内容,写入字符从文件首开始。如需保留原有文件内容,希望写入的字符以文件末开始存放,必须以追加方式打开文件。被写入的文件若不存在,则创建该文件。
    2) 每写入一个字符,文件内部位置指针向后移动一个字节。
    3) fputc函数有一个返回值,如写入成功则返回写入的字符,否则返回一个EOF。可用此来判断写入是否成功。
    【例13.2】从键盘输入一行字符,写入一个文件,再把该文件内容读出显示在屏幕上。
    #include<stdio.h>
    main()
    {
    FILE *fp;
    char ch;
    if((fp=fopen("d:\\jrzh\\example\\string","wt+"))==NULL)
    {
    printf("Cannot open file strike any key exit!");
    getch();
    exit(1);
    }
    printf("input a string:\n");
    ch=getchar();
    while (ch!='\n')
    {
    fputc(ch,fp);
    ch=getchar();
    }
    rewind(fp);
    ch=fgetc(fp);
    while(ch!=EOF)
    {
    putchar(ch);
    ch=fgetc(fp);
    }
    printf("\n");
    fclose(fp);
    }

    程序中第6行以读写文本文件方式打开文件string。程序第13行从键盘读入一个字符后进入循环,当读入字符不为回车符时,则把该字符写入文件之中,然后继续从键盘读入下一字符。每输入一个字符,文件内部位置指针向后移动一个字节。写入完毕,该指针已指向文件末。如要把文件从头读出,须把指针移向文件头,程序第19行rewind函数用于把fp所指文件的内部位置指针移到文件头。第20至25行用于读出文件中的一行内容。
    【例13.3】把命令行参数中的前一个文件名标识的文件,复制到后一个文件名标识的文件中,如命令行中只有一个文件名则把该文件写到标准输出文件(显示器)中。
    #include<stdio.h>
    main(int argc,char *argv[])
    {
    FILE *fp1,*fp2;
    char ch;
    if(argc==1)
    {
    printf("have not enter file name strike any key exit");
    getch();
    exit(0);
    }
    if((fp1=fopen(argv[1],"rt"))==NULL)
    {
    printf("Cannot open %s\n",argv[1]);
    getch();
    exit(1);
    }
    if(argc==2) fp2=stdout;
    else if((fp2=fopen(argv[2],"wt+"))==NULL)
    {
    printf("Cannot open %s\n",argv[1]);
    getch();
    exit(1);
    }
    while((ch=fgetc(fp1))!=EOF)
    fputc(ch,fp2);
    fclose(fp1);
    fclose(fp2);
    }

    本程序为带参的main函数。程序中定义了两个文件指针fp1和fp2,分别指向命令行参数中给出的文件。如命令行参数中没有给出文件名,则给出提示信息。程序第18行表示如果只给出一个文件名,则使fp2指向标准输出文件(即显示器)。程序第25行至28行用循环语句逐个读出文件1中的字符再送到文件2中。再次运行时,给出了一个文件名,故输出给标准输出文件stdout,即在显示器上显示文件内容。第三次运行,给出了二个文件名,因此把string中的内容读出,写入到OK之中。可用DOS命令type显示OK的内容。

    13.4.2 字符串读写函数fgets和fputs

    1. 读字符串函数fgets
    函数的功能是从指定的文件中读一个字符串到字符数组中,函数调用的形式为:
    fgets(字符数组名,n,文件指针);
    其中的n是一个正整数。表示从文件中读出的字符串不超过 n-1个字符。在读入的最后一个字符后加上串结束标志'\0'。
    例如:
    fgets(str,n,fp);
    的意义是从fp所指的文件中读出n-1个字符送入字符数组str中。
    【例13.4】从string文件中读入一个含10个字符的字符串。
    #include<stdio.h>
    main()
    {
    FILE *fp;
    char str[11];
    if((fp=fopen("d:\\jrzh\\example\\string","rt"))==NULL)
    {
    printf("\nCannot open file strike any key exit!");
    getch();
    exit(1);
    }
    fgets(str,11,fp);
    printf("\n%s\n",str);
    fclose(fp);
    }

    本例定义了一个字符数组str共11个字节,在以读文本文件方式打开文件string后,从中读出10个字符送入str数组,在数组最后一个单元内将加上'\0',然后在屏幕上显示输出str数组。输出的十个字符正是例13.1程序的前十个字符。
    对fgets函数有两点说明:
    1) 在读出n-1个字符之前,如遇到了换行符或EOF,则读出结束。
    2) fgets函数也有返回值,其返回值是字符数组的首地址。
     
    2. 写字符串函数fputs
    fputs函数的功能是向指定的文件写入一个字符串,其调用形式为:
    fputs(字符串,文件指针);
    其中字符串可以是字符串常量,也可以是字符数组名,或指针变量,例如:
    fputs(“abcd“,fp);
    其意义是把字符串“abcd”写入fp所指的文件之中。
    【例13.5】在例13.2中建立的文件string中追加一个字符串。
    #include<stdio.h>
    main()
    {
    FILE *fp;
    char ch,st[20];
    if((fp=fopen("string","at+"))==NULL)
    {
    printf("Cannot open file strike any key exit!");
    getch();
    exit(1);
    }
    printf("input a string:\n");
    scanf("%s",st);
    fputs(st,fp);
    rewind(fp);
    ch=fgetc(fp);
    while(ch!=EOF)
    {
    putchar(ch);
    ch=fgetc(fp);
    }
    printf("\n");
    fclose(fp);
    }

    本例要求在string文件末加写字符串,因此,在程序第6行以追加读写文本文件的方式打开文件string。然后输入字符串,并用fputs函数把该串写入文件string。在程序15行用rewind函数把文件内部位置指针移到文件首。再进入循环逐个显示当前文件中的全部内容。

    13.4.3 数据块读写函数fread和fwtrite

     
    C语言还提供了用于整块数据的读写函数。可用来读写一组数据,如一个数组元素,一个结构变量的值等。
    读数据块函数调用的一般形式为:
    fread(buffer,size,count,fp);
    写数据块函数调用的一般形式为:
    fwrite(buffer,size,count,fp);
    其中:
    buffer 是一个指针,在fread函数中,它表示存放输入数据的首地址。在fwrite函数中,它表示存放输出数据的首地址。
    size 表示数据块的字节数。
    count 表示要读写的数据块块数。
    fp 表示文件指针。
    例如:
    fread(fa,4,5,fp);
    其意义是从fp所指的文件中,每次读4个字节(一个实数)送入实数组fa中,连续读5次,即读5个实数到fa中。
    【例13.6】从键盘输入两个学生数据,写入一个文件中,再读出这两个学生的数据显示在屏幕上。
    #include<stdio.h>
    struct stu
    {
    char name[10];
    int num;
    int age;
    char addr[15];
    }boya[2],boyb[2],*pp,*qq;
    main()
    {
    FILE *fp;
    char ch;
    int i;
    pp=boya;
    qq=boyb;
    if((fp=fopen("d:\\jrzh\\example\\stu_list","wb+"))==NULL)
    {
    printf("Cannot open file strike any key exit!");
    getch();
    exit(1);
    }
    printf("\ninput data\n");
    for(i=0;i<2;i++,pp++)
    scanf("%s%d%d%s",pp->name,&pp->num,&pp->age,pp->addr);
    pp=boya;
    fwrite(pp,sizeof(struct stu),2,fp);
    rewind(fp);
    fread(qq,sizeof(struct stu),2,fp);
    printf("\n\nname\tnumber age addr\n");
    for(i=0;i<2;i++,qq++)
    printf("%s\t%5d%7d %s\n",qq->name,qq->num,qq->age,qq->addr);
    fclose(fp);
    }

    本例程序定义了一个结构stu,说明了两个结构数组boya和boyb以及两个结构指针变量pp和qq。pp指向boya,qq指向boyb。程序第16行以读写方式打开二进制文件“stu_list”,输入二个学生数据之后,写入该文件中,然后把文件内部位置指针移到文件首,读出两块学生数据后,在屏幕上显示。

    文件指针的定位

    1、rewind
    调用方式:
    FILE *fp;
    rewind(fp); 

    说明:
    (1)、rewind使文件的位置指针重新定位于文件开头。

    2、fseek 
    调用方式:
    fseek(文件类型指针,位移量,起始点);
    说明:
    (1)、起始点用0、1、2代替,分别表示文件开始、文件当前位置、文件末尾。
    (2)、位移量指起始点为基点,向前移动的字节数。一般为long型。
    (3)、fseek常用二进制文件,可以实现随机读写。
    3、ftell
    调用方式:
    FILE *fp;
    long i;
    i=ftell(fp);
    说明:
    (1)、函数返回文件当前位置,如果调用出错则返回值为-1L。
    四、出错的检测
    1、ferror
    调用方式:
    FILE *fp;
    ferror(fp);

    说明:
    (1)、返回值为0,表示未出错,返回值为1,表示出错。
    (2)、同一个文件每一次调用输入输出函数,均产生一个新 的ferror函数值。
    (3)、在执行fopen函数时,ferror函数的初始值自动置为0。
    2、clearerr
    调用方式:
    FILE *fp;
    clearerr(fp);

    说明:
    (1):使文件错误标志和文件结束标志为0.

    参考网址:

    http://descriptor.bokee.com/viewdiary.10146062.html

     
    7/26/2006

    Ajax交流文档

    Ajax内部交流文档(新增DEMO)
    创建日期:2005年04月04日
    最后修改:2005年12月05日
    创建人:Amour GUO(Waymangood)
    引用请保持文章完整性并注明出处
    一、使用Ajax的主要原因
      1、通过适当的Ajax应用达到更好的用户体验;
      2、把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理,减轻服务器和带宽的负担,从而达到节约ISP的空间及带宽租用成本的目的。
    二、引用
    Ajax这个概念的最早提出者Jesse James Garrett认为:
      Ajax是Asynchronous JavaScript and XML的缩写。
      Ajax并不是一门新的语言或技术,它实际上是几项技术按一定的方式组合在一在同共的协作中发挥各自的作用,它包括
      使用XHTML和CSS标准化呈现;
      使用DOM实现动态显示和交互;
      使用XML和XSLT进行数据交换与处理;
      使用XMLHttpRequest进行异步数据读取;
      最后用JavaScript绑定和处理所有数据;
      Ajax的工作原理相当于在用户和服务器之间加了—个中间层,使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证和数据处理等都交给Ajax引擎自己来做,只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。
    图2-1
    图2-1

    图2-2
    图2-2
    三、概述
      虽然Garrent列出了7条Ajax的构成技术,但个人认为,所谓的Ajax其核心只有JavaScript、XMLHTTPRequest和DOM,如果所用数据格式为XML的话,还可以再加上XML这一项(Ajax从服务器端返回的数据可以是XML格式,也可以是文本等其他格式)。
      在旧的交互方式中,由用户触发一个HTTP请求到服务器,服务器对其进行处理后再返回一个新的HTHL页到客户端,每当服务器处理客户端提交的请求时,客户都只能空闲等待,并且哪怕只是一次很小的交互、只需从服务器端得到很简单的一个数据,都要返回一个完整的HTML页,而用户每次都要浪费时间和带宽去重新读取整个页面。
      而使用Ajax后用户从感觉上几乎所有的操作都会很快响应没有页面重载(白屏)的等待。
      1、XMLHTTPRequest
      Ajax的一个最大的特点是无需刷新页面便可向服务器传输或读写数据(又称无刷新更新页面),这一特点主要得益于XMLHTTP组件XMLHTTPRequest对象。这样就可以向再发桌面应用程序只同服务器进行数据层面的交换,而不用每次都刷新界面也不用每次将数据处理的工作提交给服务器来做,这样即减轻了服务器的负担又加快了响应速度、缩短了用户等候时间。
      最早应用XMLHTTP的是微软,IE(IE5以上)通过允许开发人员在Web页面内部使用XMLHTTP ActiveX组件扩展自身的功能,开发人员可以不用从当前的Web页面导航而直接传输数据到服务器上或者从服务器取数据。这个功能是很重要的,因为它帮助减少了无状态连接的痛苦,它还可以排除下载冗余HTML的需要,从而提高进程的速度。Mozilla(Mozilla1.0以上及NetScape7以上)做出的回应是创建它自己的继承XML代理类:XMLHttpRequest类。Konqueror (和Safari v1.2,同样也是基于KHTML的浏览器)也支持XMLHttpRequest对象,而Opera也将在其v7.6x+以后的版本中支持XMLHttpRequest对象。对于大多数情况,XMLHttpRequest对象和XMLHTTP组件很相似,方法和属性也类似,只是有一小部分属性不支持。
    XMLHttpRequest的应用:
    XMLHttpRequest对象在JS中的应用
    var xmlhttp = new XMLHttpRequest();
    微软的XMLHTTP组件在JS中的应用
    var xmlhttp = new ActiveXObject(Microsoft.XMLHTTP);
    var xmlhttp = new ActiveXObject(Msxml2.XMLHTTP);
    XMLHttpRequest 对象方法
    /**
    * Cross-browser XMLHttpRequest instantiation.
    */

    if (typeof XMLHttpRequest == ''''undefined'''') {
    XMLHttpRequest = function () {
    var msxmls = [''''MSXML3'''', ''''MSXML2'''', ''''Microsoft'''']
    for (var i=0; i < msxmls.length; i++) {
    try {
    return new ActiveXObject(msxmls[i]+''''.XMLHTTP'''')
    } catch (e) { }
    }
    throw new Error("No XML component installed!")
    }
    }
    function createXMLHttpRequest() {
    try {
    // Attempt to create it "the Mozilla way"
    if (window.XMLHttpRequest) {
    return new XMLHttpRequest();
    }
    // Guess not - now the IE way
    if (window.ActiveXObject) {
    return new ActiveXObject(getXMLPrefix() + ".XmlHttp");
    }
    }
    catch (ex) {}
    return false;
    };

    XMLHttpRequest 对象方法
    方法 描述
    abort() 停止当前请求
    getAllResponseHeaders() 作为字符串返问完整的headers
    getResponseHeader("headerLabel") 作为字符串返问单个的header标签
    open("method","URL"[,asyncFlag[,"userName"[, "password"]]]) 设置未决的请求的目标 URL, 方法, 和其他参数
    send(content) 发送请求
    setRequestHeader("label", "value") 设置header并和请求一起发送

    XMLHttpRequest 对象属性
    属性 描述
    onreadystatechange 状态改变的事件触发器
    readyState 对象状态(integer):
    0 = 未初始化
    1 = 读取中
    2 = 已读取
    3 = 交互中
    4 = 完成
    responseText 服务器进程返回数据的文本版本
    responseXML 服务器进程返回数据的兼容DOM的XML文档对象
    status 服务器返回的状态码, 如:404 = "文件末找到" 、200 ="成功"
    statusText 服务器返回的状态文本信息

      2、JavaScript
      JavaScript是一在浏览器中大量使用的编程语言,,他以前一直被贬低为一门糟糕的语言(他确实在使用上比较枯燥),以在常被用来作一些用来炫耀的小玩意和恶作剧或是单调琐碎的表单验证。但事实是,他是一门真正的编程语言,有着自已的标准并在各种浏览器中被广泛支持。
      3、DOM
      Document Object Model。
      DOM是给 HTML 和 XML 文件使用的一组 API。它提供了文件的结构表述,让你可以改变其中的內容及可见物。其本质是建立网页与 Script 或程序语言沟通的桥梁。
      所有WEB开发人员可操作及建立文件的属性、方法及事件都以对象来展现(例如,document 就代表“文件本身“这个对像,table 对象则代表 HTML 的表格对象等等)。这些对象可以由当今大多数的浏览器以 Script 来取用。
      一个用HTML或XHTML构建的网页也可以看作是一组结构化的数据,这些数据被封在DOM(Document Object Model)中,DOM提供了网页中各个对象的读写的支持。
      4、XML
      可扩展的标记语言(Extensible Markup Language)具有一种开放的、可扩展的、可自描述的语言结构,它已经成为网上数据和文档传输的标准。它是用来描述数据结构的一种语言,就正如他的名字一样。他使对某些结构化数据的定义更加容易,并且可以通过他和其他应用程序交换数据。
      5、综合
      Jesse James Garrett提到的Ajax引擎,实际上是一个比较复杂的JavaScript应用程序,用来处理用户请求,读写服务器和更改DOM内容。
      JavaScript的Ajax引擎读取信息,并且互动地重写DOM,这使网页能无缝化重构,也就是在页面已经下载完毕后改变页面内容,这是我们一直在通过JavaScript和DOM在广泛使用的方法,但要使网页真正动态起来,不仅要内部的互动,还需要从外部获取数据,在以前,我们是让用户来输入数据并通过DOM来改变网页内容的,但现在,XMLHTTPRequest,可以让我们在不重载页面的情况下读写服务器上的数据,使用户的输入达到最少。
      基于XML的网络通讯也并不是新事物,实际上FLASH和JAVA Applet都有不错的表现,现在这种富交互在网页上也可用了,基于标准化的并被广泛支持和技术,并且不需要插件或下载小程序。
      Ajax是传统WEB应用程序的一个转变。以前是服务器每次生成HTML页面并返回给客户端(浏览器)。在大多数网站中,很多页面中至少90%都是一样的,比如:结构、格式、页头、页尾、广告等,所不同的只是一小部分的内容,但每次服务器都会生成所有的页面再返回给客户端,这无形之中是一种浪费,不管是对于用户的时间、带宽、CPU耗用,还是对于ISP的高价租用的带宽和空间来说。如果按一页来算,只能几K或是几十K可能并不起眼,但像SINA每天要生成几百万个页面的大ISP来说,可以说是损失巨大的。而AJAX可以所为客户端和服务器的中间层,来处理客户端的请求,并根据需要向服务器端发送请求,用什么就取什么、用多少就取多少,就不会有数据的冗余和浪费,减少了数据下载总量,而且更新页面时不用重载全部内容,只更新需要更新的那部分即可,相对于纯后台处理并重载的方式缩短了用户等待时间,也把对资源的浪费降到最低,基于标准化的并被广泛支持和技术,并且不需要插件或下载小程序,所以Ajax对于用户和ISP来说是双盈的。
      Ajax使WEB中的界面与应用分离(也可以说是数据与呈现分离),而在以前两者是没有清晰的界限的,数据与呈现分离的分离,有利于分工合作、减少非技术人员对页面的修改造成的WEB应用程序错误、提高效率、也更加适用于现在的发布系统。也可以把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理。
    四、应用
      Ajax理念的出现,揭开了无刷新更新页面时代的序幕,并有代替传统web开发中采用form(表单)递交方式更新web页面的趋势,可以算是一个里程碑。但Ajax都不是适用于所有地方的,它的适用范围是由它的特性所决定的。
      举个应用的例子,是关于级联菜单方面的Ajax应用。
      我们以前的对级联菜单的处理是这样的:
      为了避免每次对菜单的操作引起的重载页面,不采用每次调用后台的方式,而是一次性将级联菜单的所有数据全部读取出来并写入数组,然后根据用户的操作用JavaScript来控制它的子集项目的呈现,这样虽然解决了操作响应速度、不重载页面以及避免向服务器频繁发送请求的问题,但是如果用户不对菜单进行操作或只对菜单中的一部分进行操作的话,那读取的数据中的一部分就会成为冗余数据而浪费用户的资源,特别是在菜单结构复杂、数据量大的情况下(比如菜单有很多级、每一级菜又有上百个项目),这种弊端就更为突出。
      如果在此案中应用Ajax后,结果就会有所改观:
      在初始化页面时我们只读出它的第一级的所有数据并显示,在用户操作一级菜单其中一项时,会通过Ajax向后台请求当前一级项目所属的二级子菜单的所有数据,如果再继续请求已经呈现的二级菜单中的一项时,再向后面请求所操作二级菜单项对应的所有三级菜单的所有数据,以此类推……这样,用什么就取什么、用多少就取多少,就不会有数据的冗余和浪费,减少了数据下载总量,而且更新页面时不用重载全部内容,只更新需要更新的那部分即可,相对于后台处理并重载的方式缩短了用户等待时间,也把对资源的浪费降到最低。
      此外,Ajax由于可以调用外部数据,也可以实现数据聚合的功能(当然要有相应授权),比如微软刚刚在3月15日发布的在线RSS阅读器BETA版;还可以利于一些开放的数据,开发自已的一些应用程序,比如用Amazon的数据作的一些新颖的图书搜索应用。
      总之,Ajax适用于交互较多,频繁读数据,数据分类良好的WEB应用。
    五、Ajax的优势
      1、减轻服务器的负担。因为Ajax的根本理念是“按需取数据”,所以最大可能在减少了冗余请求和响影对服务器造成的负担;
      2、无刷新更新页面,减少用户实际和心理等待时间;
      首先,“按需取数据”的模式减少了数据的实际读取量,打个很形象的比方,如果说重载的方式是从一个终点回到原点再到另一个终点的话,那么Ajax就是以一个终点为基点到达另一个终点;
    重载方式
    图5-1

    Ajax方式
    图5-2
      其次,即使要读取比较大的数据,也不用像RELOAD一样出现白屏的情况,由于Ajax是用XMLHTTP发送请求得到服务端应答数据,在不重新载入整个页面的情况下用Javascript操作DOM最终更新页面的,所以在读取数据的过程中,用户所面对的也不是白屏,而是原来的页面状态(或者可以加一个LOADING的提示框让用户了解数据读取的状态),只有当接收到全部数据后才更新相应部分的内容,而这种更新也是瞬间的,用户几乎感觉不到。总之用户是很敏感的,他们能感觉到你对他们的体贴,虽然不太可能立竿见影的效果,但会在用户的心中一点一滴的积累他们对网站的依赖。
      3、更好的用户体验;
      4、也可以把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理,减轻服务器和带宽的负担,节约空间和带宽租用成本;
      5、Ajax由于可以调用外部数据;
      6、基于标准化的并被广泛支持和技术,并且不需要插件或下载小程序;
      7、Ajax使WEB中的界面与应用分离(也可以说是数据与呈现分离);
      8、对于用户和ISP来说是双盈的。
    六、Ajax的问题
      1、一些手持设备(如手机、PDA等)现在还不能很好的支持Ajax;
      2、用JavaScript作的Ajax引擎,JavaScript的兼容性和DeBug都是让人头痛的事;
      3、Ajax的无刷新重载,由于页面的变化没有刷新重载那么明显,所以容易给用户带来困扰――用户不太清楚现在的数据是新的还是已经更新过的;现有的解决有:在相关位置提示、数据更新的区域设计得比较明显、数据更新后给用户提示等;
      4、对流媒体的支持没有FLASH、Java Applet好;
    七、结束语
      更好的Ajax应用,需要更多的客户端的开发,和对当前的WEB应用理念的思考,而且良好的用户体验,来源于为处处用户考虑的理念,而不单纯是某种技术。
    八、DEMO
      Ajax图片浏览器DEMO:
      http://www.DragonSon.com/pic/
    九、联系方式
      MSN: waymangood@hotmail.com
      OICQ: 458620
      E-Mail: amourguo@gmail.com
      网站: http://www.DragonSon.com

    Ajax七宗罪

     

      Jesse James Garrett 的一篇A New Approach to Web Applications引出了AJAX这个web界的新名词。加上新宠儿在降生下来就和足球名队阿贾克斯、Google Suggest Google Maps这些大腕息息相关,不想出名都难啊。但似乎人们给与AJAX的期望有点太高了,甚至有人提出了用AJAX取代Java Applet和Flash。不知Flickr是不是也听到这种呼声才把自己的Flash UI转向了普通的Javascript。AJAX是个伟大的东西,它是在不创造新技术的前提下诞生的一个标准,凭这一点就能招来大批的狂热追随者,AJAX看起来更像是杨过和小龙女练得玉女素心剑一样,分开来没有什么破坏力,但是二者合一就威力无比。

      罪之一:对搜索引擎的支持不好

      这其实更像一个大大的讽刺,AJAX的鼻祖是Google,但却对Google自己支持最不好了,GMail主界面除过Top和Bottom外没有一个链接就是最形象的讽刺了。虽然Mail本身是个私人的应用系统,但这个无链接的设计界面恰恰给AJAX开了个坏头。Flash也有同样有这个毛病。没有链接的web就像森林中迷路的羔羊,这句看似广告语,其实是web设计的根本原则。

      罪之二:编写复杂、容易出错

      javascript本是是个轻量级的小东西,现在被强迫重用起来,负担可想而知。javascript对OOP的支持很少,这就限制了javascript代码的可重用可封装等等,从Google Mpa还是其他一些应用中能看到的都是无数的<Script src="..." type="text/javascript"></Script>这样的文件包含,这些除了让程序员头昏的更快点,一点好处都没有。更可怕的是在javascript中竟然没有一款顺手的Debug软件,很多写js的老手到今天还是用最原始的alert("")来调试,splinetech JavaScript HTML Debugger 算是一个看起来还像个样子的调试器吧,可惜不是免费的,几十大刀让我这种穷人只能望而生叹了。

      罪之三:冗余代码更多了

      和上面说的差不多,层层包含js文件是AJAX的通病,再加上以往的很多服务端代码现在放到了客户端,所以每次打开一个页面会包含很多的无用的js文件也一同下载下来。虽然宽带越来越普及,但是减少代码冗余还是每个web设计者的必修课。

      罪之四:破坏了Web的原有标准

      什么叫破坏web标准?点击查看全部,这就是破坏了web标准。好好的A标签放着不用,偏要用span。这种例子很多,flickr中的标题单击后可以更改,这虽然(也包括我)是大家一致叫好觉得方便的设计,但同时这也是歧义了web元素本身的含义,物是人非这个词不知道用的合不合适?

      罪之五:缺少一个没有标准之争、没有back和history的浏览器

      哈哈,这句话语有点讽刺意义。现在的浏览器市场,不管是IE还是FireFox还是Opera等等。浏览器和浏览器之间的差异一直都是web设计者心中永远的痛,支持的css不一样,支持的客户端脚本不一样,有的竟然连客户端脚本的用法都有不同。这让程序员非常苦恼,最明显的就是调用xmlhttprequest了,req=(window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");这段创建xmlhttp对象的代码就是为了适应IE和非IE两天阵营的浏览器的经典例子。说是没有back和没有history的浏览器,这也是一个讽刺,主要是指在AJAX下点击链接是不Redirect页面,所以不存在后退和前进了,同样,没有后退和前进也就无存找浏览历史纪录了。back和history存在的根本就是url的改变,在AJAX下人们发现不改url也同样能达到内容改变这个酷酷的特点,何乐而不为呢?look http://www.dux2005.org/和http://www.zagodesign.com/,我承认这两个站确实做得非常棒,但除了酷酷的感觉外,毫无用处。

      罪之六:XML只是用来打幌子

      xml从诞生那天起就被一致看好,大有非xml不娶之势,我想Jesse James Garrett也是为了趋于流行才把xml强行加入ajax的吧。xml有一个致命的缺点,那就是加载的资源耗费,这好像是所有平台下xml的通病。google map虽然是Jesse James Garrett推荐的AJAX的品牌代言人,但是gmap并没有用xml,而是用了原生的javascript数组,我自己在用AJAX从服务端传回数据时也从来不用XML,因为它让我更繁琐让系统更慢。服务端首先要调用xml对要传输的数据进行封装,客户端得到数据后再调用xml进行解析,简直是画蛇添足。AJAX的一个重要特点是要身法轻盈,数据的传输尽量单一和简陋,如果确实需要传输大量复杂的数据,也应该通过多次调用传回。

      罪之七:世界这么大却找不到自己的家

      AJAX适用于什么?能干什么?能带来什么?在网站上用AJAX那是笑话,除非像Google Map和Flickr这样的专业领域的网站外,普通网站根本没必要用这个技术;在庞大的企业应用市场估计还能有AJAX的一点容身之地,不过在MS、SUN不会看着AJAX这个野孩子来在他们的地盘上撒泼的,如果大家都用AJAX,那java给谁卖?.net给谁卖?所以AJAX在企业应用也不是长久之地。所以,AJAX现在找不到自己合适的位置是个很大的尴尬。疑病乱投医,最近把AJAX的矛头指向Flash和Applet就是一个例子。

      当然,我也不是要把AJAX扁的一无是处,我本人就非常喜欢这门技术,它能让web设计者的眼球更加宽广,让一些大胆的设计成为现实,但是我也会很冷静的小心翼翼的利用这个利器,利器虽好,一不留神刺伤的是自己。

    AJAX与微软的新方案

    2005.10.13 

     如果你曾参与过网络开发,那么对你来说,利用远程脚本调用能力、通过AJAX(Asynchronous JavaScript + XML)来开发应用软件的最新趋势也就不足为奇了。毕竟,这一技术多年前就已出现,只是与浏览器不兼容罢了。微软一直宣称ActiveX为解决方案,但随着AJAX技术的不断升温,这一情况已经改变。现在让我们深入探究AJAX革命,以及微软的参与和方案。 

    AJAX是什么?

    定义AJAX可不象指向W3C网页那样简单,因为它是几种技术的组合。它包括如下技术:

    * XHTML 和 CSS 的标准表示;

    * 使用文档对象模型DOM(Document Object Model)实现动态显示及用户交互;

    * 使用 XML 、XSLT和XMLHttpRequest进行数据交换及操作;

    * 使用 JavaScript 将所有技术绑定在一起。

    AJAX与传统网络开发的最大不同在于采用了远程脚本调用技术。远程调用技术允许用户方的JavaScript语言向服务器发送数据请求,而不用刷新网页。这一任务是通过JavaScript语言与XMLHttpRequest对象来实现的。远程脚本调用将一部分处理过程转移到客户(浏览器),这大大减少了向网络服务器的呼求数目。

    微软首次将XMLHttpRequest对象作为一个ActiveX对象应用在Windows IE5中。与这个ActiveX组件一同首次开发的还有Outlook Web Access。研发Mozilla计划的工程师推出了Mozilla 1.0(及Netscape 7)的兼容本地版,苹果公司也在他们的Safari 1.2中增加了这一支持。在一份提议的W3C标准中也包含了类似的功能。与此同时,XMLHttpRequest对象实际上已成为技术标准。

    “中间人”

    传统的网络应用软件首先向HTTP服务器触发一个用户行为或请求的呼求。反过来,服务器执行某些任务,再向发出请求的用户返回一个HTML页面。这是一种不连贯的用户体验,服务器在处理请求的时候,用户多数时间处于等待的状态。

    AJAX则不同。它通过在用户与服务器之间引入一个中间媒介,从而消除了网络交互过程中的处理—等待—处理—等待缺点。用户的浏览器在执行任务时即装载了AJAX引擎。AJAX引擎用JavaScript语言编写,通常藏在一个隐藏的框架中。它负责编译用户界面及与服务器之间的交互。AJAX引擎允许用户与应用软件之间的交互过程异步进行,独立于用户与网络服务器间的交流。

    AJAX不断升温

    AJAX正受到大型公司Google及Amazon的关注。Google已将AJAX广泛应用于其开发的Gmail、Google Suggest和Google Maps等网络应用软件中。(确实,在最近所有开发或改进的主要产品中,Google在AJAX方面投入了大量资金。)同样,Amazon也推出了应用AJAX技术的A9搜索引擎。每天都有许多类似的例子涌现。

    微软的AJAX

    当然,微软也在着手开发更为完善的AJAX。它即将推出代号为Atlas的AJAX工具。Atlas的功能超越了AJAX本身,包括整合Visual Studio的调试功能。另外,新的ASP.NET控件将使客户端控件与服务器端代码的捆绑更为简便。Atlas客户脚本框架(Atlas Clent Script Framework)也使与网页及相关项目的交互更为便利。但Visual Studio 2005中并不包含此项功能。

    微软最近宣布Atlas客户脚本框架将包含如下内容(详细资料请访问Atlas计划网站):

    * 一个可扩展的核心框架,它添加了JavaScript功能:如生命同时期管理、继承管理、多点传送处理器和界面管理。
    * 一个常见功能的基本类库,有丰富的字符串处理、计时器和运行任务。
    * 为HTML附加动态行为的用户界面框架。
    * 一组用来简化服务器连通和网络访问的网络堆栈。
    * 一组丰富的用户界面开发控件,如:自动完成的文本框、动画和拖放。
    * 处理浏览器脚本行为差异的浏览器兼容层面。

    上述内容只是一个初步的框架。在确切的产品发布之前,这些内容很可能会有所改变。如果你等不及微软的产品,可以先试用一下免费的微软.NET框架Ajax.NET库。

    AJAX的缺点

    AJAX要求用户的浏览器支持JavaScript语言。尽管这并不是主要的问题,不过也要加以考虑。同样,这些应用软件必须经过严格的测试来适应不同的浏览器及平台。但是,这种情形只对基于浏览器的应用软件而言,并不包括目标浏览器可被控制的局域网在内。

    用户对AJAX的抱怨主要集中在浏览器后退功能的失效上,因为在AJAX下,页面的动态更新并不被浏览器认为是进入另一个网页。不过,用IFRAME中的一个常用方法就可以解决该问题。

    AJAX面对的另一个批评让我觉得很有趣,有人认为AJAX不过是为了推销旧技术而引入的新名词而已。这也许是对的,但至少它所包含的技术是成熟且经过测试的。

    旧瓶装新酒

    AJAX技术在网络开发界并不新奇,但总的来说,它对所有主流浏览器的广泛支持使其更易于为网络开发界所接受并加以应用。AJAX所应用的技术成熟而稳定。利用它你能够开发出丰富的应用软件,从而减少服务器的响应时间,这样用户的等待时间也相应减少。

    Ajax轻松上路

    什么是 AJAX? 
      AJAX (异步 JavaScript 和 XML) 是个新产生的术语,专为描述JavaScript的两项强大性能.这两项性能在多年来一直被网络开发者所忽略,直到最近Gmail, Google suggest和google Maps的横空出世才使人们开始意识到其重要性.

    这两项被忽视的性能是:

    • 无需重新装载整个页面便能向服务器发送请求.
    • 对XML文档的解析和处理.

      步骤 1 – "请!" --- 如何发送一个HTTP请求

      为了用JavaScript向服务器发送一个HTTP请求, 需要一个具备这种功能的类实例. 这样的类首先由Internet Explorer以ActiveX对象引入, 被称为XMLHTTP. 后来Mozilla, Safari 和其他浏览器纷纷仿效, 提供了XMLHttpRequest类,它支持微软的ActiveX对象所提供的方法和属性.

      因此, 为了创建一个跨浏览器的这样的类实例(对象), 可以应用如下代码:

    if (window.XMLHttpRequest) { // Mozilla, Safari, ...
        http_request = new XMLHttpRequest();
    } else if (window.ActiveXObject) { // IE
        http_request = new ActiveXObject("Microsoft.XMLHTTP");
    }

      (上例对代码做了一定简化,这是为了解释如何创建XMLHTTP类实例. 实际的代码实例可参阅本篇步骤3.)

      如果服务器的响应没有XML mime-type header,某些Mozilla浏览器可能无法正常工作. 为了解决这个问题, 如果服务器响应的header不是text/xml,可以调用其它方法修改该header.

    http_request = new XMLHttpRequest();
    http_request.overrideMimeType('text/xml');

      接下来要决定当收到服务器的响应后,需要做什么.这需要告诉HTTP请求对象用哪一个JavaScript函数处理这个响应.可以将对象的onreadystatechange属性设置为要使用的JavaScript的函数名,如下所示:

    http_request.onreadystatechange = nameOfTheFunction;

      注意:在函数名后没有括号,也无需传递参数.另外还有一种方法,可以在扉页(fly)中定义函数及其对响应要采取的行为,如下所示:

    http_request.onreadystatechange = function(){
        // do the thing
    };

      在定义了如何处理响应后,就要发送请求了.可以调用HTTP请求类的open()和send()方法, 如下所示:

    http_request.open('GET', 'http://www.example.org/some.file', true);
    http_request.send(null);

    • open()的第一个参数是HTTP请求方式 – GET, POST, HEAD 或任何服务器所支持的您想调用的方式. 按照HTTP规范,该参数要大写;否则,某些浏览器(如Firefox)可能无法处理请求.有关HTTP请求方法的详细信息可参考http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html W3C specs
    • 第二个参数是请求页面的URL.由于自身安全特性的限制,该页面不能为第三方域名的页面.同时一定要保证在所有的页面中都使用准确的域名,否则调用open()会得到"permission denied"的错误提示.一个常见的错误是访问站点时使用domain.tld,而当请求页面时,却使用www.domain.tld.
    • 第三个参数设置请求是否为异步模式.如果是TRUE, JavaScript函数将继续执行,而不等待服务器响应.这就是"AJAX"中的"A". 

      如果第一个参数是"POST",send()方法的参数可以是任何想送给服务器的数据. 这时数据要以字符串的形式送给服务器,如下所示:

    name=value&anothername=othervalue&so=on

      步骤 2 – "收到!" --- 处理服务器的响应

      当发送请求时,要提供指定处理响应的JavaScript函数名.

    http_request.onreadystatechange = nameOfTheFunction;

      我们来看看这个函数的功能是什么.首先函数会检查请求的状态.如果状态值是4,就意味着一个完整的服务器响应已经收到了,您将可以处理该响应.

    if (http_request.readyState == 4) {
        // everything is good, the response is received
    } else {
        // still not ready
    }

      readyState的取值如下:

    • 0 (未初始化)
    • 1 (正在装载)
    • 2 (装载完毕)
    • 3 (交互中)
    • 4 (完成)
    (Source)

      接着,函数会检查HTTP服务器响应的状态值. 完整的状态取值可参见 W3C site. 我们着重看值为200 OK的响应.

    if (http_request.status == 200) {
        // perfect!
    } else {
        // there was a problem with the request,
        // for example the response may be a 404 (Not Found)
        // or 500 (Internal Server Error) response codes
    }

      在检查完请求的状态值和响应的HTTP状态值后, 您就可以处理从服务器得到的数据了.有两种方式可以得到这些数据:

    • http_request.responseText – 以文本字符串的方式返回服务器的响应
    • http_request.responseXML – 以XMLDocument对象方式返回响应.处理XMLDocument对象可以用JavaScript DOM函数 

      步骤 3 – "万事俱备!" - 简单实例

      我们现在将整个过程完整地做一次,发送一个简单的HTTP请求. 我们用JavaScript请求一个HTML文件, test.html, 文件的文本内容为"I'm a test.".然后我们"alert()"test.html文件的内容.

    <script type="text/javascript" language="javascript">

        var http_request = false;

        function makeRequest(url) {

            http_request = false;

            if (window.XMLHttpRequest) { // Mozilla, Safari,...
                http_request = new XMLHttpRequest();
                if (http_request.overrideMimeType) {
                    http_request.overrideMimeType('text/xml');
                }
            } else if (window.ActiveXObject) { // IE
                try {
                    http_request = new ActiveXObject("Msxml2.XMLHTTP");
                } catch (e) {
                    try {
                        http_request = new ActiveXObject("Microsoft.XMLHTTP");
                    } catch (e) {}
                }
            }

            if (!http_request) {
                alert('Giving up :( Cannot create an XMLHTTP instance');
                return false;
            }
            http_request.onreadystatechange = alertContents;
            http_request.open('GET', url, true);
            http_request.send(null);

        }

        function alertContents() {

            if (http_request.readyState == 4) {
                if (http_request.status == 200) {
                    alert(http_request.responseText);
                } else {
                    alert('There was a problem with the request.');
                }
            }

        }
    </script>
    <span
        style="cursor: pointer; text-decoration: underline"
        onclick="makeRequest('test.html')">
            Make a request
    </span>

      本例中:

    • 用户点击浏览器上的"请求"链接;
    • 接着函数makeRequest()将被调用.其参数 – HTML文件test.html在同一目录下;
    • 这样就发起了一个请求.onreadystatechange的执行结果会被传送给alertContents();
    • alertContents()将检查服务器的响应是否成功地收到,如果是,就会"alert()"test.html文件的内容. 

      步骤 4 – "X-文档" --- 处理XML响应

      在前面的例子中,当服务器对HTTP请求的响应被收到后,我们会调用请求对象的reponseText属性.该属性包含了test.html文件的内容.现在我们来试试responseXML属性.

      首先,我们新建一个有效的XML文件,后面我们将使用这个文件.该文件(test.xml)源代码如下所示:

    <?xml version="1.0" ?>
    <root>
        I'm a test.
    </root>

      在该脚本中,我们只需修改请求部分:
    ...
    onclick="makeRequest('test.xml')">
    ...

      接着,在alertContents()中,我们将alert()的代码alert(http_request.responseText);换成:

    var xmldoc = http_request.responseXML;
    var root_node = xmldoc.getElementsByTagName('root').item(0);
    alert(root_node.firstChild.data);

      这里,我们使用了responseXML提供的XMLDocument对象并用DOM方法获取存于XML文件中的内容.

    ADO记录集向XML文档的转换(已批注)

    (NC:文章写于2003年秋天...XML刚刚开始嚣张的年代,看看,我在2004年秋天开始写Asp,2005年才知道XML这东西,现在居然也要这里那里的用它,这世界变化多快.)

    面对漫天飞舞的XML曾经迷惑,不就是一种带格式的文本文件吗,为什么会惹得众多软件巨头竞相追捧,以致成为网络时代的通用表达语言?仔细研究下来,XML的以下特点使之成为互联网上的新宠:

    1.  通用性:自从其诞生的那天起,便立志成为电子商务时代的世界语,所以它采用了一种结构化的ASCII文本文件,任何系统都可以方便的与之沟通。

    2.  开放:XML为W3C所制定的标准语法,并已获得软件工业的认可。

    3.  可扩展:无固定不变的标记,可根据需求创建新标记

    4.  自我描述能力:DTD将XML的每个部分做了声明与精确的格式定义。而SCHEMA是XML文档元素的规则组合,它指定文本中所允许的元素,及其可能的组合。

    正因为此,通过ADO取得的数据记录,保存为XML文档,有着广泛的应用价值,下面详细讨论之。

    目标

    现有一个ACCESS数据库PeiXun.mdb,一个kecheng数据表

    我们将把其内容保存为如下格式的XML文档:

    -<xml>

    -<id>3</id>

      <classid>1 </classid>

      <date>2003年5月24日</date>

    <curriculum_name>MBA考前辅导第一期基础班</curriculum_name>

     </row>

     </xml>

    正如我们所熟悉的用ASP操作数据库模式,先创建一个conn..asp文件,用于打开数据库,在后面的代码中都会用到:

    <%

        on error resume next

           dim conn,connstr

           dim dbpath

           connstr="DBQ="+server.mappath("DataBase/peixun.mdb")+";DefaultDir=;DRIVER={Microsoft Access Driver (*.mdb)};"

         set conn=server.createobject("adodb.connection")

           conn.Open  connstr

    %>


    方案一

    基本上,维护XML文档的技术有三种,第一种是使用DOM(Document Object Modal)接口,第二种是通过SAX(Simple API for XML),第三种是采用传统的字符串维护(NC:一直用第三种方式)。

    所谓DOM就是把整个XML文档加载到一个树状结构的节点中,然后再通过维护树状结构的方式来改变XML文档,使用DOM时,整个XML文档必须先加载到内存中。

    实际上,很多家公司都实现了DOM,包括IBM,Apache,Microsoft等,而Microsoft公司是把DOM的实现放在MSXML SDK内,而MS IE 也使用DOM 。下面我们就使用MSXML对象实现从ADO RecordSet 到XML文档的转化。

    1.  取得ADO数据记录集:

    <!--#include file ="conn.asp"-->

    <%

        Dim strsql

        Dim objRecordset

       Dim fileObj

        strsql=" select  id,class_id,date, curriculum_name  from kecheng "                 

        set objRecordset=conn.execute (strsql)                 

     %>

    2.  创建XMLDOM对象

    <%

    Set objXMLDOM = Server.CreateObject("MSXML2.DOMDocument.3.0")

        ''''''''创建根节点<xml>

        Set objRootNode = objXMLDOM.createElement("xml")

        objXMLDOM.documentElement = objRootNode

        ‘用createProcessingInstruction方法处理指令

    objXMLDOM.appendChild(objXML.createProcessingInstruction("xml","version=""1.0"""))

    %>

      

     

    3. 循环把数据集中的每条记录写到DOM的节点中去:

    <%

    Do While NOT objRecordset.EOF

        ''''''''创建子元素 row

        Set objRowNode = objXMLDOM.createElement("row")

    <--start banner ad--><--ba--> <Script language="JavaScript1.1" src="http://ad.cn.doubleclick.net/adj/messagingplus.zdnet.com.cn/developer/code;sz=1x1;ord=972790391?" type="text/javascript"> </Script> <--end banner ad-->

        ''''''''创建子元素 id

        Set objNode = objXMLDOM.createElement("id")

        objNode.text = _

             objRecordset.Fields.Item("id").Value

        ''''''''id 作为row 的子节点添加到row下

        objRowNode.appendChild(objNode)

        ''''''''创建 classid节点,并使之为row的子节点

    Set objNode = objXMLDOM.createElement("classid")

        objNode.text = _

             objRecordset.Fields.Item("classid").Value

        objRowNode.appendChild(objNode)

        ''''''''创建 date节点,并使之为row的子节点

    Set objNode = objXMLDOM.createElement("date")

        objNode.text = _

             objRecordset.Fields.Item("date").Value

        objRowNode.appendChild(objNode)

        ''''''''创建curriculum_name节点,并使之为row的子节点

    Set objNode = objXMLDOM.createElement("curriculum_name")

        objNode.text = _

             objRecordset.Fields.Item("curriculum_name").Value

        objRowNode.appendChild(objNode)

        ''''''''row 作为xml的子节点添加

    objRootNode.appendChild(objRowNode)

        ''''''''移到下一条记录

    objRecordset.MoveNext

    Loop

    %>

    4.  调用save方法保存XML文件

    <%

    objXMLDOM.save(server.MapPath("kecheng.xml"))

    (NC:这种写入是否需要IIS中的写权限?如果需要,是否影响安全性?)

    %>

    5.  释放资源

    <%

    Set objNode = Nothing

    Set objRowNode = Nothing

    Set objRootNode = Nothing

    Set objRecordset = Nothing

    %>

    您肯定发现了,第3步写得好罗嗦啊,完全可以用RecordSet得Fields属性,循环取出所有的字段,如下所示:

    <%

    Do While NOT objRecordset.EOF

            ''''''''创建子元素 row

            Set objRowNode = objXMLDOM.createElement("row")

            For Each varItem In objRecordset.Fields

               Set objNode = objXMLDOM.createElement(varItem.name)

               objNode.text =varItem.value

               objRowNode.appendChild(objNode)

            Next

       ''''''''    row 作为xml的子节点添加

            objRootNode.appendChild(objRowNode)

           

            objRecordset.MoveNext

    Loop

    %>

    这样写即简洁又通用,实际上写程序的过程就是不断精益求精的过程啊(NC:赞,单纯的程序员应该是一个有洁癖的完美主义者)

    方案二(NC:也是我以前用的方法)

    <--start banner ad--><--ba--> <Script language="JavaScript1.1" src="http://ad.cn.doubleclick.net/adj/messagingplus.zdnet.com.cn/developer/code;sz=1x1;ord=1648567173?" type="text/javascript"> </Script> <--end banner ad-->

    我们把记录集和XML格式串放到字符串中,生成目标中所示的格式,然后把字符串写到一个文本文件中。

    1.  同方案一中第一步取得ADO数据记录集。

    2.  定义XML格式初始化字符串:

    <%

    Dim strXML

    strXML = "<?XML version="&""""&"1.0"&""""&" encoding="&""""&"gb2312"&""""&"?>"

    strXML = strXML & "<xml>"

    %>

    注意我们在这里把XML文档的encoding属性定义为gb23312,以防止中文字符在XML解析器中(如IE)解析时出现错误。

    3.  循环把数据集中的每条记录附加到所定义的字符串中:

    <%

    objRecordset.MoveFirst

        Do While NOT objRecordset.EOF

            For Each varItem In objRecordset.Fields

               strXML = strXML _

                                &"<"_

                                &varItem.name_

                             &">"_

                                &varItem.value_

                                &"</"_

    &varItem.name_

    &">"

            Next

       Loop

         strXML = strXML & "</xml>"

    Set objRecordset = Nothing

    %>

     

     

    4. 把字符串保存到文件中去:

       <%

     Dim FileObject,OutFile

    ‘调用系统文件对象

    SET FileObject=Server.CreateObject("Scripting.FileSystemObject")

       ‘创建文本文件

    Set OutFile=FileObject.CreateTextFile(server.MapPath("kc1.xml"),TRUE,FALSE)         

        ‘把字符串写到文件中去。

        OutFile.WriteLine(strXML)

        OutFile.Close

        Set OutFile=Nothing

    Set FileObject=Nothing

    %>

    方案三

    实际上ADO的RecordSet对象中有一个Save方法,可以直接把数据保存为XML格式。下面我们看看是如何使用的:

    1.  同方案一中第一步取得ADO数据记录集。

    2.  创建DOMDocument对象,并调用RecordSet的Save方法,把数据保存到DOMDocument中去。

    Save方法在ADODB 的RecordSet 的对象中是这样声明的:

    Sub Save([FileName As String], _         [PersistFormat As PersistFormatEnum = adPersistADTG])

    Save 方法的两个参数都是可选的,但若是第一次调用,必须指定文件名Filename。

    Save 不关闭 Recordset 或 FileName,从而可以继续使用 Recordset 并保存最新的更改。在 Recordset 关闭之前 FileName将保持打开,在这段时间其它应用程序可以读取但不能写入 FileName。

    PersistFormatEnum 值,指定保存 Recordset 所使用的格式。可以是如下的某个常量

    AdPersistADTG (默认)使用专用的“Advanced Data Tablegram”格式保存。
    AdPersistXML 使用XML 格式保存。

    以上是MSDN中对该方法的描述,据此,可以利用Save把RecordSet保存为XML文件:

    objRecordset.save server.MapPath("ceshi.xml"), adPersistXML

    需要注意的是,Filename并不一定是磁盘文件,也可以是内存流对象,比如DOMDocument。

    下面把第二步中的代码列于此:

    <%

    Const adPersistXML = 1

    Dim objXMLDOM

    Set objXMLDOM = Server.CreateObject("MSXML2.DOMDocument.3.0")

    objRecordset.save objXMLDOM, adPersistXML

    %>

    这样,数据记录就保存到了objXMLDOM对象中了,为什么不直接保存成XML文件呢?这是因为通过该方法保存成的XML文件附加了一些我们目标中不需要的信息:


    图片一

    这些信息是XML文档的架构(Schema)信息。它包含了RecordSet中记录的描述,其中<s:Schema> 定义了各字段的名称,类型及其它一些属性; <rs:data> 是RecordSet中的所有数据记录<z:row>则具体到每一条记录的信息。我们的任务下一步就是利用XSLT把该文档转化为目标中XML文档的格式。

    3.  利用XSLT对XML文档进行转换。(NC:3、4步是以前没有想到也不会的,不过有必要比较一下与方案二的效率差异。之所以强调效率,因为这种利用xml作为中间数据层的方法一旦在站点内广为使用,就会代替原数据库成为耗用资源的主力)

    那么什么是XSLT呢?它是Extensible Stylesheet Language Transformations的缩写,是一种专为XML设计的样式表语言,负责将XML源代码转化为另一种格式。XSLT转换必须由特定的软件来担任,这样的软件称为XSL处理器。XSL处理器在工作之前,得先借助XML解析器替它把XSLT样式表和待转换的XML文档中的节点和属性分离出来,分离的结果我们程之为源树,指的是转换前的XML结构。然后,XSL处理器根据XSL中的命令对XML文档的源树进行操作,得到转换的成品,我们称之为结果树。下图就是利用XSLT对XML进行转换的原理图。


    图片二

    下面我们就编写XSLT文件 RecordsetCleaner.xsl

    <%

    <?xml version="1.0"?>

    <!-- RecordsetCleaner.xsl -->

    <xsl:stylesheet version="1.0"

        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

        xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"

        xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"

        xmlns:rs="urn:schemas-microsoft-com:rowset"

        xmlns:z="#RowsetSchema">

    <xsl:output omit-xml-declaration="yes"/>

    <xsl:template match="/">

        <xsl:element name="xml">

            <xsl:for-each select="/xml/rs:data/z:row">

                <xsl:element name="row">

                    <xsl:for-each select="@*">

                        <xsl:element name="{name()}">

                            <xsl:value-of select="."/>

                        </xsl:element>

                    </xsl:for-each>

                </xsl:element>

            </xsl:for-each>

        </xsl:element>

    </xsl:template>

    </xsl:stylesheet>

    %>

    4.  调用XSLT转换。
    现在XSLT文件已经准备好了,开始让它与XML文档发生作用吧。记住,我们在第二步的时候已经把RecordSet保存在了objXMLDOM中。

    <%

    Dim strCleanXML, objXMLDOM_XSLT

    Set objXMLDOM_XSLT = CreateObject("MSXML2.DOMDocument.3.0")

    objXMLDOM_XSLT.load(Server.MapPath("RecordsetCleaner.xsl"))

    strCleanXML = objXMLDOM.transformNode(objXMLDOM_XSLT)

    %>

    现在,strCleanXML字符串中就保存着我们目标中所要求的XML文档。下一步就是要把它保存在磁盘文件中去。

    5.保存为文件

    <%

    objXMLDOM.loadXML(strCleanXML)

    objXMLDOM.save(server.MapPath("test1.xml"))

    Set objXMLDOM = Nothing

    Set objXMLDOM_XSLT = Nothing

    Set objRecordset = Nothing

    %>

    在这里,我们复用了objXMLDOM对象,通过调用loadXML方法,其内容已经变为已经减肥过的XML文档内容了。

    遗留问题

    当数据集中的数据包含“,’,<,,>等XML保留字符时,转换将会失败,我们在上面的讨论中并没有注意这个问题。在实际开发中,要首先对这些字符进行过滤,然后才能进行转换。

    使用ado2.1访问XML文件(已批注)

    MDAC 2.1有了许多新的特性,比如数据链结,三维数据分形和重定形数据(Data shaping and reshaping,实在不知道该怎么翻译),离线保持记录集,自动同步客户端游标,建立新记录集(自己加入数据,不从查询中得到),DDL和JRO等,其中的离线保持记录集就是采用XML来实现的。
    这样,我们就可以象使用Recordset一样使用XML了,而且,也可以把Recordset保存为XML了,请看这一段Example Code:
    Dim objRS
    Const adCmdFile = 256
    Const adPersistXML = 1
    Set objRS = Server.CreateObject("ADODB.Recordset")
    ''''''''''''''''这里我新建一个记录集,当然从数据库中查询得到的也完全可以
    objRS.Fields.Append "ID", adInteger
    objRS.Fields.Append "Content", adVarChar, 20
    objRS.Open
    objRS.AddNew Array("ID", "Content"), Array(1, "test")
    ''''''''''''''''很简单,一个Save Method就可以转化为XML了
    objRS.Save Server.MapPath("test.xml"), adPersistXML
    objRS.Close
    ''''''''''''''''要打开XML也非常的容易
    objRS.Open Server.MapPath("test.xml"), , , , adCmdFile
    不过呢,Recordset保存的XML比我们平常写的XML要复杂得多,因为它要记录字段的详细信息,让我们来看一下就知道了。
    这是Recordset保存的:
    <xml xmlns:s=''''''''''''''''uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882''''''''''''''''
    xmlns:dt=''''''''''''''''uuid:C2F41010-65B3-11d1-A29F-00AA00C14882''''''''''''''''
    xmlns:rs=''''''''''''''''urn:schemas-microsoft-com:rowset''''''''''''''''
    xmlns:z=''''''''''''''''#RowsetSchema''''''''''''''''>
    <s:Schema id=''''''''''''''''RowsetSchema''''''''''''''''>
    <s:ElementType name=''''''''''''''''row'''''''''''''''' content=''''''''''''''''eltOnly'''''''''''''''' rs:updatable=''''''''''''''''true''''''''''''''''>
      <s:attribute type=''''''''''''''''ID''''''''''''''''/>
      <s:attribute type=''''''''''''''''Content''''''''''''''''/>
      <s:extends type=''''''''''''''''rs:rowbase''''''''''''''''/>
    </s:ElementType>
    <s:AttributeType name=''''''''''''''''ID'''''''''''''''' rs:number=''''''''''''''''1'''''''''''''''' rs:write=''''''''''''''''true''''''''''''''''>
      <s:datatype dt:type=''''''''''''''''int'''''''''''''''' dt:maxLength=''''''''''''''''4'''''''''''''''' rs:precision=''''''''''''''''0'''''''''''''''' rs:fixedlength=''''''''''''''''true'''''''''''''''' rs:maybenull=''''''''''''''''false''''''''''''''''/>
    </s:AttributeType>
    <s:AttributeType name=''''''''''''''''Content'''''''''''''''' rs:number=''''''''''''''''2'''''''''''''''' rs:write=''''''''''''''''true''''''''''''''''>
      <s:datatype dt:type=''''''''''''''''string'''''''''''''''' dt:maxLength=''''''''''''''''20'''''''''''''''' rs:precision=''''''''''''''''0'''''''''''''''' rs:maybenull=''''''''''''''''false''''''''''''''''/>
    </s:AttributeType>
    </s:Schema>
    <rs:data>
    <rs:insert>
      <z:row ID=''''''''''''''''1'''''''''''''''' Content=''''''''''''''''test''''''''''''''''/>
    </rs:insert>
    </rs:data>
    </xml>  (NC:汗)
    我自己写的:
    <?xml version="1.0" encoding="gb2312" ?>
    <root>
        <z:row ID=''''''''''''''''1'''''''''''''''' Content=''''''''''''''''test''''''''''''''''/>
    </root>
    用ADO访问XML并没有给我们带来什么方便,用XMLDOM也是比较简单的,但是它给我们提供了一种新的编程方式:用XML实现三层结构。
    第一,如果数据库服务器上的一些数据将在一段时间内保持不变,比如一些对照表,而数据库服务器又不和Web Server在一起,那么就可以用XML在中间层放置这些数据,比用文本文件还是要来得方便和快捷的。 (NC:所见略同,解决目前NP的问题,终于为自己的想法找到依据了)
    第二,比如我不想用数据库,又想放一些数据,比如我刚做的电子贺卡(实际上只是想用点新技术而已),那么也可以用XML来存放数据。
    第三,比如某些数据不经常变动,比如一天变动一次,那么我不希望每次查询都去访问数据库,而是在有数据变动的时候保存到一个XML里面,而让客户端代码去读XML。 (按固定的时间刷新会影响用户体验,其实合理设置刷更新点是件很容易的且可行的事情)

    (NC:如果自己写一个将RecordSet转换成XML的东东,算法多加锤炼,相比效率怎样呢?)

    以上内容部分来自PDC99资料DATA01:ADO体系结构和性能调整、WIN13:XML-实现3层Web应用程序。
    由于本人水平有限,文中有谬误和遗漏之处,还望大家多指教。
    7/25/2006

    开篇语

        一直想开一个纯技术的Blog,记录一下平日里琐碎的收获。也曾经在NPBlog里面写过一个,写到C++学习手记的时候,数据库被Ripple回档,好多东西没了。于是更新就慢了下来。后来因为论坛宠物数据丢失的事情,NC那个ID自锁谢罪了。之后就再也没有过记录。
        事实上,最近这半年时间里,我在技术上也没有什么新的吸收和突破。很多东西都是平面推开的,除了提供一下实际经验,没有更多意义。
        所以,开了这一处地方,一是要再次尝试尽量有条理的记录一下所学所想所思;二也是希望刺激一下自己学习新东西的劲头。望如愿吧。
        另外,这里可能也会有一些相关课程的作业,项目。也可能会有一些我和其他人关于技术的交流的记录,一并收录。
        唯一与技术无关的,我也想在这里整理一下我和网协的事情,想了好久了,一直没有动笔的。