2005年08月17日

作者:robbin
网址:
http://hibernate.fankai.com/

Java Learning Path (一)、工具篇


一、 JDK (Java Development Kit)

JDK是整个Java的核心,包括了Java运行环境(Java Runtime Envirnment),一堆Java工具和Java基础的类库(rt.jar)。不论什么Java应用服务器实质都是内置了某个版本的JDK。因此掌握JDK是学好Java的第一步。最主流的JDK是Sun公司发布的JDK,除了Sun之外,还有很多公司和组织都开发了自己的JDK,例如IBM公司开发的JDK,BEA公司的Jrocket,还有GNU组织开发的JDK等等。其中IBM的JDK包含的JVM(Java Virtual Machine)运行效率要比Sun JDK包含的JVM高出许多。而专门运行在x86平台的Jrocket在服务端运行效率也要比Sun JDK好很多。但不管怎么说,我们还是需要先把Sun JDK掌握好。

1、 JDK的下载和安装
JDK又叫做J2SE(Java2 SDK Standard Edition),可以从Sun的Java网站上下载到,
http://java.sun.com/j2se/downloads.html ,JDK当前最新的版本是J2SDK1.4.2,建议下载该版本的JDK,下载页面在这里:http://java.sun.com/j2se/1.4.2/download.html。

下载好的JDK是一个可执行安装程序,默认安装完毕后会在C:\Program Files\Java\目录下安装一套JRE(供浏览器来使用),在C:\j2sdk1.4.2下安装一套JDK(也包括一套JRE)。然后我们需要在环境变量PATH的最前面增加java的路径C:\j2sdk1.4.2\bin。这样JDK就安装好了。

2、 JDK的命令工具
JDK的最重要命令行工具:
java: 启动JVM执行class
javac: Java编译器
jar: Java打包工具
javadoc: Java文档生成器
这些命令行必须要非常非常熟悉,对于每个参数都要很精通才行。对于这些命令的学习,JDK Documentation上有详细的文档。


二、 JDK Documentation

Documentation在JDK的下载页面也有下载连接,建议同时下载Documentation。Documentation是最最重要的编程手册,涵盖了整个Java所有方面的内容的描述。可以这样说,学习Java编程,大部分时间都是花在看这个Documentation上面的。我是随身携带的,写Java代码的时候,随时查看,须臾不离手。


三、 应用服务器(App Server)

App Server是运行Java企业组件的平台,构成了应用软件的主要运行环境。当前主流的App Server是BEA公司的Weblogic Server和IBM公司的Websphere以及免费的Jboss,选择其中一个进行学习就可以了,个人推荐Weblogic,因为它的体系结构更加干净,开发和部署更加方便,是Java企业软件开发人员首选的开发平台。下面简要介绍几种常用的App Server:

1、 Tomcat
Tomcat严格意义上并不是一个真正的App Server,它只是一个可以支持运行Serlvet/JSP的Web容器,不过Tomcat也扩展了一些App Server的功能,如JNDI,数据库连接池,用户事务处理等等。Tomcat被非常广泛的应用在中小规模的Java Web应用中,因此本文做一点下载、安装和配置Tomcat的介绍:

Tomcat是Apache组织下Jakarta项目下的一个子项目,它的主网站是:
http://jakarta.apache.org/tomcat/ ,Tomcat最新版本是Tomcat4.1.27,软件下载的连接是:http://www.apache.org/dist/jakarta/tomcat-4/binaries/

下载Tomcat既可以直接下载zip包,也可以下载exe安装包(个人建议zip更干净些),不管哪种情况,下载完毕安装好以后(zip直接解压缩就可以了)。需要设置两个环境变量:

JAVA_HOME=C:\j2sdk1.4.2
CATALINA_HOME=D:\tomcat4 (你的Tomcat安装目录)

这样就安装好了,启动Tomcat运行CATALINA_HOME\bin\startup.bat,关闭Tomcat运行shutdown.bat脚本。Tomcat启动以后,默认使用8080端口,因此可以用浏览器访问
http://localhost:8080来测试Tomcat是否正常启动。

Tomcat提供了两个Web界面的管理工具,URL分别是:
http://localhost:8080/admin/index.jsp
http://localhost:8080/manager/html
在启用这两个管理工具之前,先需要手工配置一下管理员用户和口令。用一个文本工具打开CATALINA_HOME\conf\tomcat-users.xml这个文件,加入如下几行:

<role rolename="manager"/>
<role rolename="admin"/>
<user username="robbin" password="12345678" roles="admin,manager,tomcat"/>

这样用户“robbin”就具备了超级管理员权限。重新启动Tomcat以后,你就可以使用该用户来登陆如上的两个管理工具,通过Web方式进行Tomcat的配置和管理了。

2、 BEA Weblogic
Weblogic可以到BEA的网站上免费注册之后下载到最新的Weblogic8.1企业版,License可以免费使用1年时间,其实这已经完全足够了。Weblogic的下载连接:
http://commerce.bea.com/index.jsp,…/edocs.bea.com/

3、 IBM Webshpere
Websphere同样可以下载到免费的试用版本,到IBM的developerWorks网站可以看到Websphere试用产品的下载和相关的Websphere的资料,developerWorks中文网站的连接是:
http://www-900.ibm.com/developerWorks/cn/wsdd/ ,Websphere的下载连接:http://www7b.software.ibm.com/wsdd/…WASsupport.html

4、 Jboss
Jboss是免费开源的App Server,可以免费的从Jboss网站下载:
http://www.jboss.org/index.html,然…n.com/idea.html


四、 Java应用的运行环境

Java的应用可以简单分为以下几个方面:

1、 Java的桌面应用
桌面应用一般仅仅需要JRE的支持就足够了。

2、 Java Web应用
Java的Web应用至少需要安装JDK和一个web容器(例如Tomcat),以及一个多用户数据库,Web应用至少分为三层:
Browser层:浏览器显示用户页面
Web层:运行Servlet/JSP
DB层:后端数据库,向Java程序提供数据访问服务

3、 Java企业级应用
企业级应用比较复杂,可以扩展到n层,最简单情况会分为4层:
Browser层:浏览器显示用户页面
Client层:Java客户端图形程序(或者嵌入式设备的程序)直接和Web层或者EJB层交互
Web层:运行Servlet/JSP
EJB层:运行EJB,完成业务逻辑运算
DB层:后端数据库,向Java程序提供数据访问服务

4、 Java嵌入式应用
Java嵌入式应用是一个方兴未艾的领域,从事嵌入式开发,需要从Sun下载J2ME开发包,J2ME包含了嵌入式设备专用虚拟机KVM,和普通的JDK中包含的JVM有所不同。另外还需要到特定的嵌入式厂商那里下载模拟器。


Java Learning Path(二)、书籍篇

学习一门新的知识,不可能指望只看一本,或者两本书就能够完全掌握。需要有一个循序渐进的阅读过程。我推荐Oreilly出版的Java系列书籍。

在这里我只想补充一点看法,很多人学习Java是从《Thinking in Java》这本书入手的,但是我认为这本书是不适合初学者的。我认为正确的使用这本书的方法应该是作为辅助的读物。《Thinking in Java》并不是在完整的介绍Java的整个体系,而是一种跳跃式的写作方法,是一种类似tips的方法来对Java很多知识点进行了深入的分析和解释。

对于初学者来说,最好是找一本Java入门的书籍,但是比较完整的循序的介绍Java的语法,面向对象的特性,核心类库等等,在看这本书的同时,可以同步来看《Thinking in Java》,来加深对Java的理解和原理的运用,同时又可以完整的了解Java的整个体系。

对于Java的入门书籍,蔡学镛推荐的是Oreilly的《Exploring Java, 2nd Edition》 或者《Java in a Nutshell,2nd Edition(针对C++背景)》,我并没有看过这两本书。其实我觉得电子工业出版社的《Java 2编程详解》或者《Java 2从入门到精通》就很不错。

在所有的Java书籍当中,其实最最有用的,并不是O’reilly的 Java Serials,真正最最有用处是JDK的Documentation!几乎你想获得的所有的知识在Documentation里面全部都有,其中最主要的部分当然是Java基础类库的API文档,是按照package来组织的,对于每一个class都有详细的解释,它的继承关系,是否实现了某个接口,通常用在哪些场合,还可以查到它所有的public的属性和方法,每个属性的解释,意义,每个方法的用途,调用的参数,参数的意义,返回值的类型,以及方法可能抛出的异常等等。可以这样来说,所有关于Java编程方面的书籍其实都不过是在用比较通俗易懂的语言,和良好的组织方式来介绍Documentation里面的某个package里面包含的一些类的用法而已。所以万变不离其宗,如果你有足够的能力来直接通过Documentation来学习Java的类库,那么基本上就不需要看其他的书籍了。除此之外,Documentation也是编程必备的手册,我的桌面上有三个Documentation的快捷方式,分别是J2SDK1.4.1的Documentation,Servlet2.3的Documentation和J2SDKEE1.3.1的Documentation。有了这个三个Documentation,什么其他的书籍都不需要了。

对于Java Web 编程来说,最核心的是要熟悉和掌握HTTP协议,这个就和Java无关了,在熟悉HTTP协议之后,就需要熟悉Java的实现HTTP协议的类库,也就是Servlet API,所以最重要的东西就是Servlet API。当然对于初学者而言,直接通过Servlet API来学习Web编程有很大的难度,我推荐O’reilly的《Java Server Pages 》这本书来学习Web 编程。

EJB的书籍当中,《Enterprise JavaBeans, 2nd Edition》是一本很不错的书, EJB的学习门槛是比较高,入门很难,但是这本书完全降低了学习的难度,特别重要的一点是,EJB的学习需要结合一种App Server的具体实现,所以在学习EJB的同时,必须同步的学习某种App Server,而这本书相关的出了三本书,分别是Weblogic6.1,Websphere4.0和JBoss3.0上面部署书中例子的实做。真是既有理论,又有实践。在学习EJB的同时,可以边看边做,EJB的学习会变得很轻松。

但是这本书也有一个问题,就是版本比较旧,主要讲EJB1.1规范和部分EJB2.0的规范。而Ed Roman写的《Mastering EJB 2.0》这本书完全是根据EJB2.0规范写的,深入浅出,覆盖了EJB编程的各个方面,并且还有很多编程经验tips,也是学习EJB非常推荐的书籍之一。

如果是结合Weblogic来学习J2EE的话,《J2EE应用与BEA Weblogic Server》绝对是首选读物,虽然是讲述的Weblogic6.0,仍然值得购买,这本书是BEA官方推荐的教材,作者也是BEA公司的工程师。现在中文版已经随处可见了。这本书结合Weblogic介绍了J2EE各个方面的技术在Weblogic平台上的开发和部署,实践指导意义非常强。

在掌握了Java平台基础知识和J2EE方面的知识以后,更进一步的是学习如何运用OO的方法进行软件的设计,那么就一定要学习“设计模式”。Sun公司出版了一本《J2EE核心模式》,是每个开发Java企业平台软件的架构师必备的书籍。这本书全面的介绍了J2EE体系架构的各种设计模式,是设计师的必读书籍。

Java Learning Path(三)过程篇

每个人的学习方法是不同的,一个人的方法不见得适合另一个人,我只能是谈自己的学习方法。因为我学习Java是完全自学的,从来没有问过别人,所以学习的过程基本上完全是自己摸索出来的。我也不知道这种方法是否是比较好的方法,只能给大家提供一点参考了。

学习Java的第一步是安装好JDK,写一个Hello World, 其实JDK的学习没有那么简单,关于JDK有两个问题是很容易一直困扰Java程序员的地方:一个是CLASSPATH的问题,其实从原理上来说,是要搞清楚JRE的ClassLoader是如何加载Class的;另一个问题是package和import问题,如何来寻找类的路径问题。把这两个问题摸索清楚了,就扫除了学习Java和使用JDK的最大障碍。推荐看一下王森的《Java深度历险》,对这两个问题进行了深入的探讨。

第二步是学习Java的语法。Java的语法是类C++的,基本上主流的编程语言不是类C,就是类C++的,没有什么新东西,所以语法的学习,大概就是半天的时间足够了。唯一需要注意的是有几个不容易搞清楚的关键字的用法,public,protected,private,static,什么时候用,为什么要用,怎么用,这可能需要有人来指点一下,我当初是完全自己琢磨出来的,花了很久的时间。不过后来我看到《Thinking in Java》这本书上面是讲了这些概念的。

第三步是学习Java的面向对象的编程语言的特性的地方。比如继承,构造器,抽象类,接口,方法的多态,重载,覆盖,Java的异常处理机制。对于一个没有面向对象语言背景的人来说,我觉得这个过程需要花很长很长时间,因为学习Java之前没有C++的经验,只有C的经验,我是大概花了一个月左右吧,才彻底把这些概念都搞清楚,把书上面的例子反复的揣摩,修改,尝试,把那几章内容反复的看过来,看过去,看了不下5遍,才彻底领悟了。不过我想如果有C++经验的话,应该一两天时间足够了。那么在这个过程中,可以多看看《Thinking in Java》这本书,对面向对象的讲解非常透彻。可惜的是我学习的时候,并没有看到这本书,所以自己花了大量的时间,通过自己的尝试和揣摩来学会的。

第四步就是开始熟悉Java的类库。Java的基础类库其实就是JDK安装目录下面jre\lib\rt.jar这个包。学习基础类库就是学习rt.jar。基础类库里面的类非常非常多。据说有3000多个,我没有统计过。但是真正对于我们来说最核心的只有4个,分别是
java.lang.*;
java.io.*;
java.util.*;
java.sql.*;

这四个包的学习,每个包的学习都可以写成一本厚厚的教材,而O’reilly也确实是这样做的。我觉得如果时间比较紧,是不可能通过读四本书来学习。我觉得比较好的学习方法是这样的:
首先要通读整个package的框架,了解整个package的class,interface,exception的构成,最好是能够找到介绍整个包框架的文章。这些专门介绍包的书籍的前几章应该就是这些总体的框架内容介绍。

对包整体框架的把握并不是要熟悉每个类的用法,记住它有哪些属性,方法。想记也记不住的。而是要知道包有哪些方面的类构成的,这些类的用途是什么,最核心的几个类分别是完成什么功能的。我在给人培训的时候一般是一次课讲一个包,所以不可能详细的介绍每个类的用法,但是我反复强调,我给你们讲这些包的不是要告诉你们类的方法是怎么调用的,也不要求你们记住类的方法调用,而是要你们了解,Java给我们提供了哪些类,每个类是用在什么场合,当我遇到问题的时候,我知道哪个类,或者哪几个类的组合可以解决我的问题,That’all!,当我们具体写程序的时候,只要你知道该用哪个类来完成你的工作就足够了。编码的时候,具体的方法调用,是边写代码,边查Documentation,所有的东西都在Documentation里面,不要求你一定记住,实际你也记不住3000多个类的总共将近10万个方法调用。所以对每个包的总体框架的把握就变得极为重要。

第五步,通过上面的学习,如果学的比较扎实的话,就打好了Java的基础了,剩下要做的工作是扫清Documentation里面除了上面4个包之外的其他一些比较有用处的类。相信进展到这一步,Java的自学能力已经被培养出来了,可以到了直接学习Documentation的水平了。除了要做GUI编程之外,JDK里面其他会有用处的包是这些:
java.text.*;
java.net.*;
javax.naming.*;
这些包里面真正用的比较多的类其实很少,只有几个,所以不需要花很多时间。

第六步,Java Web 编程
Web编程的核心是HTTP协议,HTTP协议和Java无关,如果不熟悉HTTP协议的话,虽然也可以学好Servlet/JSP编程,但是达不到举一反三,一通百通的境界。所以HTTP协议的学习是必备的。如果熟悉了HTTP协议的话,又有了Java编程的良好的基础,学习Servlet/JSP简直易如反掌,我学习Servlet/JSP就用了不到一周的时间,然后就开始用JSP来做项目了。

在Servlet/JSP的学习中,重头仍然是Servlet Documentation。Servlet API最常用的类很少,花比较少的时间就可以掌握了。把这些类都看一遍,多写几个例子试试。Servlet/JSP编程本质就是在反复调用这些类来通过HTTP协议在Web Server和Brower之间交谈。另外对JSP,还需要熟悉几个常用JSP的标记,具体的写法记不住的话,临时查就是了。

此外Java Web编程学习的重点要放在Web Application的设计模式上,如何进行业务逻辑的分析,并且进行合理的设计,按照MVC设计模式的要求,运用Servlet和JSP分别完成不同的逻辑层,掌握如何在Servlet和JSP之间进行流程的控制和数据的共享,以及Web Application应该如何配置和部署。

第七步,J2EE编程
以上的学习过程如果是比较顺利的话,进行到这一步,难度又陡然提高。因为上面的知识内容都是只涉及一个方面,而像EJB,JMS,JTA等核心的J2EE规范往往是几种Java技术的综合运用的结晶,所以掌握起来难度比较大。

首先一定要学习好JNDI,JNDI是App Server定位服务器资源(EJB组件,Datasouce,JMS)查找方法,如果对JNDI不熟悉的话,EJB,JMS这些东西几乎学不下去。JNDI其实就是javax.naming.*这个包,运用起来很简单。难点在于服务器资源文件的配置。对于服务器资源文件的配置,就需要看看专门的文档规范了,比如web.xml的写法,ejb-jar.xml的写法等等。针对每种不同的App Server,还有自己的服务资源配置文件,也是需要熟悉的。

然后可以学习JTA,主要是要理解JTA对于事务的控制的方法,以及该在什么场合使用JTA。这里可以简单的举个例子,我们知道一般情况可以对于一个数据库连接进行事务控制(conn.setAutoCommit(false),….,conn.commit()),做为一个原子操作,但是假设我的业务需求是要把对两个不同数据库的操作做为一个原子操作,你能做的到吗?这时候只能用JTA了。假设操作过程是先往A数据库插一条记录,然后删除B数据库另一个记录,我们自己写代码是控制不了把整个操作做为一个原子操作的。用JTA的话,由App Server来完成控制。

在学习EJB之前要学习对象序列化和RMI,RMI是EJB的基础。接着学习JMS和EJB,对于EJB来说,最关键是要理解EJB是如何通过RMI来实现对远端对象的调用的,以及在什么情况下要用到EJB。

在学习完EJB,JMS这些东西之后,你可能会意识到要急不可待学习两个领域的知识,一个是UML,另一个是Design Pattern。Java企业软件的设计非常重视框架(Framework)的设计,一个好的软件框架是软件开发成功的必要条件。在这个时候,应该开始把学习的重点放在设计模式和框架的学习上,通过学习和实际的编程经验来掌握EJB的设计模式和J2EE的核心模式。

J2EE规范里面,除了EJB,JMS,JTA,Servlet/JSP,JDBC之外还有很多很多的企业技术,这里不一一进行介绍了。

另外还有一个最新领域Web Services。Web Services也完全没有任何新东西,它像是一种黏合剂,可以把不同的服务统一起来提供一个统一的调用接口,作为使用者来说,我只要获得服务提供者给我的WSDL(对服务的描述),就够了,我完全不知道服务器提供者提供的服务究竟是EJB组件,还是.Net组件,还是什么CORBA组件,还是其他的什么实现,我也不需要知道。Web Services最伟大的地方就在于通过统一的服务提供方式和调用方式,实现了整个Internet服务的共享,是一个非常令人激动的技术领域。Web Services好像目前还没有什么很好的书籍,但是可以通过在网络上面查资料的方式来学习。

Java Learning Path(四) 方法篇

Java作为一门编程语言,最好的学习方法就是写代码。当你学习一个类以后,你就可以自己写个简单的例子程序来运行一下,看看有什么结果,然后再多调用几个类的方法,看看运行结果,这样非常直观的把类给学会了,而且记忆非常深刻。然后不应该满足把代码调通,你应该想想看如果我不这样写,换个方式,再试试行不行。记得哪个高人说过学习编程就是个破坏的过程,把书上的例子,自己学习Documentation编写的例子在运行通过以后,不断的尝试着用不同的方法实现,不断的尝试破坏代码的结构,看看它会有什么结果。通过这样的方式,你会很彻底的很精通的掌握Java。

举个例子,我们都编过Hello World

public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}

很多初学者不是很理解为什么main方法一定要这样来定义public static void main(String[] args),能不能不这样写?包括我刚学习Java的时候也有这样的疑问。想知道答案吗?很简单,你把main改个名字运行一下,看看报什么错误,然后根据出错信息进行分析;把main的public取掉,在试试看,报什么错误;static去掉还能不能运行;不知道main方法是否一定要传一个String[]数组的,把String[]改掉,改成int[],或者String试试看;不知道是否必须写args参数名称的,也可以把args改成别的名字,看看运行结果如何。

我当初学习Java的时候就是这样做的,把Hello World程序反复改了七八次,不断运行,分析运行结果,最后就彻底明白为什么了main方法是这样定义的了。

此外,我对于staic,public,private,Exception,try{ }catch {}finally{}等等等等一开始都不是很懂,都是把参考书上面的例子运行成功,然后就开始破坏它,不断的根据自己心里面的疑问来重新改写程序,看看能不能运行,运行出来是个什么样子,是否可以得到预期的结果。这样虽然比较费时间,不过一个例子程序这样反复破坏几次之后。我就对这个相关的知识彻底学通了。有时候甚至故意写一些错误的代码来运行,看看能否得到预期的运行错误。这样对于编程的掌握是及其深刻的。

其中特别值得一提的是JDK有一个非常棒的调试功能,-verbose
java –verbose
javac –verbose 以及其它很多JDK工具都有这个选项
-verbose 可以显示在命令执行的过程中,JVM都依次加载哪里Class,通过这些宝贵的调试信息,可以帮助我们分析出JVM在执行的过程中都干了些什么。

另外,自己在学习过程中,写的很多的这种破坏例程,应该有意识的分门别类的保存下来,在工作中积累的典型例程也应该定期整理,日积月累,自己就有了一个代码库了。遇到类似的问题,到代码库里面 Copy & Paste ,Search & Replace,就好了,极大提高了开发速度。最理想的情况是把一些通用的例程自己再抽象一层,形成一个通用的类库,封装好。那么可复用性就更强了。

所以我觉得其实不是特别需要例程的,自己写的破坏例程就是最好的例子,如果你实在对自己写的代码不放心的话,我强烈推荐你看看JDK基础类库的Java源代码。在JDK安装目录下面会有一个src.zip,解开来就可以完整的看到整个JDK基础类库,也就是rt.jar的Java源代码,你可以参考一下Sun是怎么写Java程序的,规范是什么样子的。我自己在学习Java的类库的时候,当有些地方理解的不是很清楚的时候,或者想更加清晰的理解运作的细节的时候,往往会打开相应的类的源代码,通过看源代码,所有的问题都会一扫而空。

Java Learning Path(五)资源篇

1、
http://java.sun.com/ (英文)
Sun的Java网站,是一个应该经常去看的地方。不用多说。

2、
http://www-900.ibm.com/developerWorks/cn/
IBM的developerWorks网站,英语好的直接去英文主站点看。这里不但是一个极好的面向对象的分析设计网站,也是Web Services,Java,Linux极好的网站。强烈推荐!!!

3、
http://www.javaworld.com/ (英文)
关于Java很多新技术的讨论和新闻。想多了解Java的方方面面的应用,这里比较好。

4、
http://dev2dev.bea.com.cn/index.jsp
BEA的开发者园地,BEA作为最重要的App Server厂商,有很多独到的技术,在Weblogic上做开发的朋友不容错过。

5、
http://www.huihoo.com/
灰狐动力网站,一个专业的中间件网站,虽然不是专业的Java网站,但是在J2EE企业应用技术方面有深厚的造诣。

6、
http://www.theserverside.com/home/ (英文)
TheServerSide是一个著名的专门面向Java Server端应用的网站。

7、
http://www.javaresearch.org/
Java研究组织,有很多优秀的Java方面的文章和教程,特别是在JDO方面的文章比较丰富。

8、
http://www.cnjsp.org/
JSP技术网站,有相当多的Java方面的文章和资源。

9、
http://www.jdon.com/
Jdon论坛,是一个个人性质的中文J2EE专业技术论坛,在众多的Java的中文论坛中,Jdon一个是技术含量非常高,帖子质量非常好的论坛。

10、
http://sourceforge.net/
SourgeForge是一个开放源代码软件的大本营,其中也有非常非常丰富的Java的开放源代码的著名的软件。

2005年08月16日

一、什么是框架
  框架Frames最主要功用是"分割"视窗,使每个"小视窗"能显示不同的HTM L文件,不同框架之间可以互动(interact),这就是说不同框架之间可以交换讯息与资料。例如:假设您开了两个frames,第一个frame可显示书的目录,第二个frame则显示章节的具体内容。
  框架可以将屏幕分割成不同的区域,每个区域有自己的URL,通过Frames[]数组对象来实现不同框架的访问。实际上框架对象本身也一类窗口,它继承了窗口对象的所有特征,并拥有所有的属性和方法。下面我们先看一下框架的例子。

<HTML>
<HEAD>
</HEAD>
<Frameset Rows="20%,80%">
<frame src="test9_1.html">
<Frameset Cols="50%,50%">
<frame src="test9_2.html">
<frame src="test9_3.html">
</Frameset>
</Frameset>
</HTML>


  以上HTML标识将屏幕分成三个框架。先将窗口分成以二行为单位的窗口,之后再按分成二个窗口。并在相应的框架中放入自己的HTML文档。
  通过[Framset ]告诉浏览器您要设置几个框架;rows这项参数告诉浏览器您想将视窗分割成几列;而 cols这项参数是告诉浏览器您想将视窗分割成几行。
  可以用很多组的 <frameset…> tags 将视窗分割得更复杂。
  可以给每个frame一个"名字" (name)。frame的名字在JavaScript语法中的地位非常重要。     可以用 <src> 告诉浏览器您要载入哪一个 HTML文件。

二、如何访问框架
  在前面我们介绍过使用document.forms[]实现单一窗体中不同元素的访问。而要实现框架中多窗体的不同元素的访问,则必须使用window对象中的Frames属性。Frames属性同样也是一个数组,他在  父框架集中为每一个子框架设有一项。通过下标实现不同框架的访问:
parent.frames[Index1].docuement.forms[index2]
  通过parent.frames.length确定窗口中窗体的数目。 除了使用数组下标来访问窗体外还可以使用框架名和窗体名来实现各元素的访:
parent.framesName.decument.formNames.elementName.(m/p)

  三、范例
  下面我们通过一个具体的实例, 来说明利用JavaScript脚本在WEB中实现更为复杂的信息交互。该例子是在一个多窗口中实现窗体信息的动态交互,在程序中首先在浏览器窗口中制作三个用于窗体交互的窗口,每个窗体窗口实现不同信息的动态交互。
  tset9.html为主调用文档它首先将窗口划分为具有二行的窗体,尔后再将第二行的窗体划分为具有二列的窗体;
test9-1.html为显示标题文档;
test9_2.html为第二框架文档其中需要注意的是:
通过JavaScript脚本将所示的“云南省”和“四川省”分别改为“昆明市”和“成都市”;
test7_3.html为第三框架文档。

 主调文档
主要作用是将窗口划分为具有二行的窗体,尔后再将第二行的窗体划分为具有二列的窗体。
Test9.htm

<HTML>
<HEAD>
</HEAD>
<Frameset Rows="10%,90%">
<frame src="test9_1.htm">
<Frameset Cols="40%,60%">
<frame src="test9_2.htm">
<frame src="test9_3.htm">
</Frameset>
</Frameset>
</HTML>
第一个框架
主要作用是显示标题文档。
Test9_1.htm
<HTML>
<HEAD>
</HEAD>
<H2>使用框架实现WEB交互</H2>
</HTML>

 
第二个框架
主要作用是实现交互。可以通过JavaScript脚本将所示的“云南省”和“四川省”分别改为“昆明市”和“成都市”。
Test9_2.htm

<HTML>
<HEAD>
</HEAD>
<Body>
<Form name="test9_1">
请选择城市:<BR>
<Select name="select1" Multiple>
<Option>云南省
<Option>四川省
<Option>贵州省
<Option>山东省
<Option>江苏省
<Option>浙江省
<Option>安徽省
<Option>河南省
</select><BR>
<HR>
<Input Type="Submit" name="" value="提交">
<Input Type="reset" name="" value="复位">
</Form>
<pre>
<script language="JavaScript">
document.test9_1.elements[0].options[0].text="昆明市";
document.test9_1.elements[0].options[1].text="成都市";
</script>
</pre>
</Body>
</HTML>

 
第三个框架
主要作用是实现交互。
Test9_3.htm

<HTML>
<HEAD>
</HEAD>
<Body>
<Form name="test9_2">
请输入用户名:
<Input Type="text" name="text1" Value="" Size=20><BR>
<HR>
请选择:
<Input Type="Checkbox" name="checkbox1" Value="qb">全部信息<BR>
<Input Type="Checkbox" name="checkbox2" Value="bf">部分信息<BR>
<Input Type="Checkbox" name="checkbox3" Value="sy">所有城市<br>
<HR>
<Input Type="Submit" name="" value="提交">
<Input Type="reset" name="" value="复位">
<BR>
</Form>
<script language="JavaScript">
document.test9_2.elements[0].value="劳动和社会保障";
document.test9_2.elements[1].checked=true;
document.test9_2.elements[2].checked=true;
document.test9_2.elements[3].checked=false;
</script>
</Body>
</HTML>

  在浏览器中的结果见图9-2所示。



图 9-2 在浏览器中结果
 
  本讲介绍框架中的基本元素的主要功能和使用,利用JavaScript脚本可以非常方便、灵活地实现Web页面更为复杂的信息交互,这是HTML标识语言所不能具备的。从中可以看出JavaScript是多么的吸引众多的Web设计人员。

今天在产品里发现了一个bug,多个aspx页面都无法提交,点了提交按纽都没有反应,初步猜测是Validate的问题。详细的解决过程就不写了,将最后的结论总结如下:

    .NET Framework 1.1的补丁对Validator有影响,如果使用补丁前的WebUIValidation.js,会导致包含有Validators的页面无法提交。

     打补丁前,WebUIValidation.js中的ValidatorCommonOnSubmit如下:

function ValidatorCommonOnSubmit() {
    
event.returnValue = !Page_BlockSubmit;
    Page_BlockSubmit 
= false;
}


  打补丁后,ValidatorCommonOnSubmit如下:
 

function ValidatorCommonOnSubmit() {
    var result 
= !Page_BlockSubmit;
    Page_BlockSubmit 
= false;
    
event.returnValue = result;
    
return result;
}


 打补丁前,System.Web.dll中BaseValidator的RegisterValidatorCommonScript如下:

protected void RegisterValidatorCommonScript()
{
      
if (this.Page.IsClientScriptBlockRegistered("ValidatorIncludeScript"))
      
{
            
return;
      }

      
string text1 = Util.GetScriptLocation(this.Context);
      
string text2 = HttpRuntime.FormatResourceString("Validator_missing_script", text1 + "WebUIValidation.js");
      
string text3 = HttpRuntime.FormatResourceString("Validator_wrong_script""WebUIValidation.js""125""\" + Page_ValidationVer + \"");
      
string text4 = string.Empty;
      
if (this.Page.Request.IsLocal)
      
{
            
object[] objArray1 = new object[3{ text2, "125", text3 } ;
            text4 
= string.Format("\r\n<script language=\"javascript\">\r\n<!–\r\nvar Page_ValidationActive = false;\r\nif (typeof(clientInformation) != \"undefined\" && clientInformation.appName.indexOf(\"Explorer\") != -1) {{\r\n    if (typeof(Page_ValidationVer) == \"undefined\")\r\n        alert(\"{0}\");\r\n    else if (Page_ValidationVer != \"{1}\")\r\n        alert(\"{2}\");\r\n    else\r\n        ValidatorOnLoad();\r\n}}\r\n\r\nfunction ValidatorOnSubmit() {{\r\n    if (Page_ValidationActive) {{\r\n        ValidatorCommonOnSubmit();\r\n    }}\r\n}}\r\n// –>\r\n</script>\r\n        ", objArray1);
      }

      
else
      
{
            text4 
= string.Format("\r\n<script language=\"javascript\">\r\n<!–\r\nvar Page_ValidationActive = false;\r\nif (typeof(clientInformation) != \"undefined\" && clientInformation.appName.indexOf(\"Explorer\") != -1) {{\r\n    if ((typeof(Page_ValidationVer) != \"undefined\") && (Page_ValidationVer == \"{0}\"))\r\n        ValidatorOnLoad();\r\n}}\r\n\r\nfunction ValidatorOnSubmit() {{\r\n    if (Page_ValidationActive) {{\r\n        ValidatorCommonOnSubmit();\r\n    }}\r\n}}\r\n// –>\r\n</script>\r\n        ""125");
      }

      
this.Page.RegisterClientScriptFileInternal("ValidatorIncludeScript""javascript", text1, "WebUIValidation.js");
      
this.Page.RegisterStartupScript("ValidatorIncludeScript", text4);
      
this.Page.RegisterOnSubmitStatement("ValidatorOnSubmit""ValidatorOnSubmit();");
}


  打完补丁后,RegisterValidatorCommonScript代码如下:

protected void RegisterValidatorCommonScript()
{
      
if (this.Page.IsClientScriptBlockRegistered("ValidatorIncludeScript"))
      
{
            
return;
      }

      
string text1 = Util.GetScriptLocation(this.Context);
      
string text2 = HttpRuntime.FormatResourceString("Validator_missing_script", text1 + "WebUIValidation.js");
      
string text3 = HttpRuntime.FormatResourceString("Validator_wrong_script""WebUIValidation.js""125""\" + Page_ValidationVer + \"");
      
string text4 = string.Empty;
      
if (this.Page.Request.IsLocal)
      
{
            
object[] objArray1 = new object[3{ text2, "125", text3 } ;
            text4 
= string.Format("\r\n<script language=\"javascript\" type=\"text/javascript\">\r\n<!–\r\nvar Page_ValidationActive = false;\r\nif (typeof(clientInformation) != \"undefined\" && clientInformation.appName.indexOf(\"Explorer\") != -1) {{\r\n    if (typeof(Page_ValidationVer) == \"undefined\")\r\n        alert(\"{0}\");\r\n    else if (Page_ValidationVer != \"{1}\")\r\n        alert(\"{2}\");\r\n    else\r\n        ValidatorOnLoad();\r\n}}\r\n\r\nfunction ValidatorOnSubmit() {{\r\n    if (Page_ValidationActive) {{\r\n        return ValidatorCommonOnSubmit();\r\n    }}\r\n    return true;\r\n}}\r\n// –>\r\n</script>\r\n        ", objArray1);
      }

      
else
      
{
            text4 
= string.Format("\r\n<script language=\"javascript\" type=\"text/javascript\">\r\n<!–\r\nvar Page_ValidationActive = false;\r\nif (typeof(clientInformation) != \"undefined\" && clientInformation.appName.indexOf(\"Explorer\") != -1) {{\r\n    if ((typeof(Page_ValidationVer) != \"undefined\") && (Page_ValidationVer == \"{0}\"))\r\n        ValidatorOnLoad();\r\n}}\r\n\r\nfunction ValidatorOnSubmit() {{\r\n    if (Page_ValidationActive) {{\r\n        return ValidatorCommonOnSubmit();\r\n    }}\r\n    return true;\r\n}}\r\n// –>\r\n</script>\r\n        ""125");
      }

      
this.Page.RegisterClientScriptFileInternal("ValidatorIncludeScript""javascript", text1, "WebUIValidation.js");
      
this.Page.RegisterStartupScript("ValidatorIncludeScript", text4);
      
this.Page.RegisterOnSubmitStatement("ValidatorOnSubmit""if (!ValidatorOnSubmit()) return false;");
}


  花了些时间找出问题原因,记录下来,以便查询。

  再有就是建议没有打.NET Framework 1.1补丁的,尽早打补丁,同时不要在发布产品的时候发布任何.NET Framework中带的文件,包含.js和.dll。

这个问题是因为IIS根目录下的aspnet_client\system_web\1_1_4322\中不正确的文件版本引起的。在安装SP1时,需要更新aspnet_client\system_web\1_1_4322\中的SmartNav.js与WebUIValidation.js文件, 更新之后文件的修改日期应该是2004年7月,如果在安装SP1时没有成功更新这两个文件(旧文件的修改日期是2003年), 就会出现不能提交的问题。当你遇到类似问题时,先检查一下SmartNav.js与WebUIValidation.js文件,如果文件版本有问题,运行aspnet_regiis -c重新安装脚本或者从其他电脑上复制过来。

2005年08月09日

级别: 中级


作者
2003 年 3 月

用XPath精确定位节点元素

用XPath精确定位节点元素
在利用XSL进行转换的过程中,匹配的概念非常重要。在模板声明语句 xsl:template match = ""和模板应用语句xsl:apply-templates select = "" 中,用引号括起来的部分必须能够精确地定位节点。具体的定位方法则在XPath中给出。

之所以要在XSL中引入XPath的概念,目的就是为了在匹配XML文档结构树时能够准确地找到某一个节点元素。可以把XPath比作文件管理路径:通过文件管理路径,可以按照一定的规则查找到所需要的文件;同样,依据XPath所制定的规则,也可以很方便地找到XML结构文档树中的任何一个节点,显然这对XSLT来说是一个最最基本的功能。

XPath数据类型
XPath可分为四种数据类型:

  • 节点集(node-set)
    节点集是通过路径匹配返回的符合条件的一组节点的集合。其它类型的数据不能转换为节点集。
  • 布尔值(boolean)
    由函数或布尔表达式返回的条件匹配值,与一般语言中的布尔值相同,有true和 false两个值。布尔值可以和数值类型、字符串类型相互转换。
  • 字符串(string)
    字符串即包含一系列字符的集合,XPath中提供了一系列的字符串函数。字符串可与数值类型、布尔值类型的数据相互转换。
  • 数值(number)
    在XPath中数值为浮点数,可以是双精度64位浮点数。另外包括一些数值的特殊描述,如非数值NaN(Not-a-Number)、正无穷大infinity、负无穷大-infinity、正负0等等。number的整数值可以通过函数取得,另外,数值也可以和布尔类型、字符串类型相互转换。

其中后三种数据类型与其它编程语言中相应的数据类型差不多,只是第一种数据类型是XML文档树的特有产物。

XPath节点类型
另外,由于XPath包含的是对文档结构树的一系列操作,因此搞清楚XPath节点类型也是很必要的。回忆一下第二章中讲到的XML文档的逻辑结构,一个XML文件可以包含元素、CDATA、注释、处理指令等逻辑要素,其中元素还可以包含属性,并可以利用属性来定义命名空间。相应地,在XPath中,将节点划分为七种节点类型:

  1. 根节点(Root Node)
    根节点是一棵树的最上层,根节点是唯一的。树上其它所有元素节点都是它的子节点或后代节点。对根节点的处理机制与其它节点相同。在XSLT中对树的匹配总是先从根节点开始。
  2. 元素节点(Element Nodes)
    元素节点对应于文档中的每一个元素,一个元素节点的子节点可以是元素节点、注释节点、处理指令节点和文本节点。可以为元素节点定义一个唯一的标识id。元素节点都可以有扩展名,它是由两部分组成的:一部分是命名空间URI,另一部分是本地的命名。
  3. 文本节点(Text Nodes)
    文本节点包含了一组字符数据,即CDATA中包含的字符。任何一个文本节点都不会有紧邻的兄弟文本节点,而且文本节点没有扩展名。
  4. 属性节点(Attribute Nodes)
    每一个元素节点有一个相关联的属性节点集合,元素是每个属性节点的父节点,但属性节点却不是其父元素的子节点。这就是说,通过查找元素的子节点可以匹配出元素的属性节点,但反过来不成立,只是单向的。再有,元素的属性节点没有共享性,也就是说不同的元素节点不共有同一个属性节点。
    对缺省属性的处理等同于定义了的属性。如果一个属性是在DTD声明的,但声明为 #IMPLIED,而该属性没有在元素中定义,则该元素的属性节点集中不包含该属性。
    此外,与属性相对应的属性节点都没有命名空间的声明。命名空间属性对应着另一种类型的节点。
  5. 命名空间节点(Namespace Nodes)
    每一个元素节点都有一个相关的命名空间节点集。在XML文档中,命名空间是通过保留属性声明的,因此,在XPath中,该类节点与属性节点极为相似,它们与父元素之间的关系是单向的,并且不具有共享性。
  6. 处理指令节点(Processing Instruction Nodes)
    处理指令节点对应于XML文档中的每一条处理指令。它也有扩展名,扩展名的本地命名指向处理对象,而命名空间部分为空。
  7. 注释节点(Comment Nodes)
    注释节点对应于文档中的注释。

一个XML文档树
我们来构造一棵XML文档树,作为后面举例的依托:


	<A id="a1">
	  <B id="b1">
		<C id="c1">
		  <B name="b"/>
		  <D id="d1"/>
		  <E id="e1"/>
		  <E id="e2"/>
		</C>
	  </B>
	  <B id="b2"/>
	  <C id="c2">
		<B/>
		<D id="d2"/>
		<F/>
	  </C>
	  <E/>
	</A>

以下将要介绍一些XPath中节点匹配的基本方法。

路径匹配
路径匹配与文件路径的表示相仿,比较好理解。有以下几个符号:

(1)用“/”指示节点路径
如“/A/C/D” 表示节点"A"的子节点"C"的子节点"D",即id值为d2的D节点, “/”表示根节点。

(2)用“//” 表示所有路径以"//"后指定的子路径结尾的元素
如“//E” 表示所有E元素,结果是所有三个E元素,如“//C/E”表示所有父节点为C的E元素,结果是id值为e1和e2的两个E元素 。

(3)用“*” 表示路径的通配符
如“/A/B/C/*”表示 A元素→B元素→C元素下的所有子元素,即name值为b的B元素、 id值为d1的D元素和id值为e1和e2的两个E元素
“/*/*/D”表示上面有两级节点的D元素,匹配结果是id值为d2的D元素 ,如“//*”表示所有的元素。

位置匹配
对于每一个元素,它的各个子元素是有序的。

如:/A/B/C[1]表示A元素→B元素→C元素的第一个子元素,得到name值为b的B元素

/A/B/C[last()]表示A元素→B元素→C元素的最后一个子元素,得到id值为e2的E元素

/A/B/C[position()>1]表示A元素→B元素→C元素之下的位置号大于1的元素,得到id值为d1的D元素和两个具有id值的E元素

属性及属性值
在XPath中可以利用属性及属性值来匹配元素,要注意的是,元素的属性名前要有"@"前缀。例如:

//B[@id]表示所有具有属性id的B元素,结果为id值为b1和b2的两个B元素

//B[@*]表示所有具有属性的B元素,结果为两个具有id属性的B元素和一个具有name属性B元素

//B[not(@*)]表示所有不具有属性的B元素,结果为A元素→C元素下的B元素

//B[@id="b1"] id值为b1的B元素,结果为A元素下的B元素

亲属关系匹配
XML文档可归结为树型结构,因此任何一个节点都不是孤立的。通常我们把节点之间的归属关系归结为一种亲属关系,如父亲、孩子、祖先、后代、兄弟等等。在对元素进行匹配时,同样可以用到这些概念。例如:

//E/parent::* 表示所有E节点的父节点元素,结果为id值为a1的A元素和id值为c1的C元素

//F/ancestor::* 表示所有F元素的祖先节点元素,结果为id值为a1的A元素和id值为c2的C元素

/A/child::* 表示A的子元素,结果为id值为b1、b2的B元素,id值为c2的C元素,以及没有任何属性的E元素

/A/descendant::* 表示A的所有后代元素,结果为除A元素以外的所有其它元素

//F/self::* 表示所有F的自身元素,结果为F元素本身

//F/ancestor-or-self::* 表示所有F元素及它的祖先节点元素,结果为F元素、F元素的父节点C元素和A元素

/A/C/descendant-or-self::* 表示所有A元素→C元素及它们的后代元素,结果为id值为c2的C元素、该元素的子元素B、D、F元素

/A/C/following-sibling::* 表示A元素→C元素的紧邻的后序所有兄弟节点元素,结果为没有任何属性的E元素

/A/C/preceding-sibling::* 表示A元素→C元素的紧邻的前面所有兄弟节点元素,结果为id值为b1和b2的两个B元素

/A/B/C/following::* 表示A元素→B元素→C元素的后序的所有元素,结果为id 为b2的B元素、无属性的C元素、无属性的B元素、id为d2的D元素、无属性的F元素、\无属性的E元素。

/A/C/preceding::* 表示A元素→C元素的前面的所有元素,结果为id为b2的B元素、id为e2的E元素、id为e1的E元素、id为d1的D元素、name为 b的B元素、id为c1的C元素、id为b1的B元素

条件匹配
条件匹配就是利用一些函数的运算结果的布尔值来匹配符合条件的节点。常用于条件匹配的函数有四大类:节点函数、字符串函数、数值函数、布尔函数。例如last()、position()等等,这里我们就不再赘述。

以上这些匹配方法中,用得最多的还要数路径匹配。在上一章样式表的例子中,无论是在语句<xsl:template match="学生花名册">中,还是在语句 <xsl:value-of select="名字"/>中,都是依靠给出相对于当前路径的子路径来定位节点的。

节点匹配路径Xpath

    在利用XSL进行转换的过程中,匹配的概念非常重要。在模板声明语句xsl:template match = ""和模板应用语句xsl:apply-templates select = ""中,用引号括起来的部分必须能够精确地定位节点。具体的定位方法则在XPath中给出。

   另外,也可以使用Xpath对XML文档进行搜索、定位。

之所以要引入XPath的概念,目的就是为了在匹配XML文档结构树时能够准确地找到某一个节点元素。可以把XPath比作文件管理路径:通过文件管理路径,可以按照一定的规则查找到所需要的文件;同样,依据XPath所制定的规则,也可以很方便地找到XML结构文档树中的任何一个节点。

在介绍XPath的匹配规则之前,我们先来看一些有关XPath的基本概念。首先要说的是XPath数据类型。XPath可分为四种数据类型:

节点集(node-set)
节点集是通过路径匹配返回的符合条件的一组节点的集合。其它类型的数据不能转换为节点集。

布尔值(boolean)
由函数或布尔表达式返回的条件匹配值,与一般语言中的布尔值相同,有true和false两个值。布尔值可以和数值类型、字符串类型相互转换。

字符串(string)
字符串即包含一系列字符的集合,XPath中提供了一系列的字符串函数。字符串可与数值类型、布尔值类型的数据相互转换。

数值(number)
XPath中数值为浮点数,可以是双精度64位浮点数。另外包括一些数值的特殊描述,如非数值NaN(Not-a-Number)、正无穷大infinity、负无穷大-infinity、正负0等等。number的整数值可以通过函数取得,另外,数值也可以和布尔类型、字符串类型相互转换。

其中后三种数据类型与其它编程语言中相应的数据类型差不多,只是第一种数据类型是XML文档树的特有产物。另外,由于XPath包含的是对文档结构树的一系列操作,因此搞清楚XPath节点类型也是很必要的。由于XML文档的逻辑结构,一个XML文件可以包含元素、CDATA、注释、处理指令等逻辑要素,其中元素还可以包含属性,并可以利用属性来定义命名空间。相应地,在XPath中,将节点划分为七种节点类型:

根节点(Root Node)
根节点是一棵树的最上层,根节点是唯一的。树上其它所有元素节点都是它的子节点或后代节点。对根节点的处理机制与其它节点相同。在XSLT中对树的匹配总是先从根节点开始。

元素节点(Element Nodes)
元素节点对应于文档中的每一个元素,一个元素节点的子节点可以是元素节点、注释节点、处理指令节点和文本节点。可以为元素节点定义一个唯一的标识id。
元素节点都可以有扩展名,它是由两部分组成的:一部分是命名空间URI,另一部分是本地的命名。

文本节点(Text Nodes)
文本节点包含了一组字符数据,即CDATA中包含的字符。任何一个文本节点都不会有紧邻的兄弟文本节点,而且文本节点没有扩展名。

属性节点(Attribute Nodes)
每一个元素节点有一个相关联的属性节点集合,元素是每个属性节点的父节点,但属性节点却不是其父元素的子节点。这就是说,通过查找元素的子节点可以匹配出元素的属性节点,但反过来不成立,只是单向的。再有,元素的属性节点没有共享性,也就是说不同的元素节点不共有同一个属性节点。
对缺省属性的处理等同于定义了的属性。如果一个属性是在DTD声明的,但声明为#IMPLIED,而该属性没有在元素中定义,则该元素的属性节点集中不包含该属性。
此外,与属性相对应的属性节点都没有命名空间的声明。命名空间属性对应着另一种类型的节点。

命名空间节点(Namespace Nodes)
每一个元素节点都有一个相关的命名空间节点集。在XML文档中,命名空间是通过保留属性声明的,因此,在XPath中,该类节点与属性节点极为相似,它们与父元素之间的关系是单向的,并且不具有共享性。

处理指令节点(Processing Instruction Nodes)
处理指令节点对应于XML文档中的每一条处理指令。它也有扩展名,扩展名的本地命名指向处理对象,而命名空间部分为空。

注释节点(Comment Nodes)
注释节点对应于文档中的注释。下面,我们来构造一棵XML文档树:

<A id="a1">
  <B id="b1">
    <C id="c1">
      <B name="b"/>
      <D id="d1"/>
      <E id="e1"/>
      <E id="e2"/>
    </C>
  </B>
  <B id="b2"/>
  <C id="c2">
    <B/>
    <D id="d2"/>
    <F/>
  </C>
  <E/>
</A>

现在,来实现一些利用Xpath使XML中节点匹配的基本方法。

路径匹配
路径匹配与文件路径的表示相仿,比较好理解。有以下几个符号:

  号

  义

  例

匹配结果

/

指示节点路径

/A/C/D

节点"A"的子节点"C"的子节点"D",即id值为d2的D节点

/

根节点

//

所有路径以"//"后指定的子路径结尾的元素

//E

所有E元素,结果是所有三个E元素

//C/E

所有父节点为C的E元素,结果是id值为e1和e2的两个E元素

*

路径的通配符

/A/B/C/*

A元素→B元素→C元素下的所有子元素,即name值为b的B元素、id值为d1的D元素和id值为e1和e2的两个E元素

/*/*/D

上面有两级节点的D元素,匹配结果是id值为d2的D元素

//*

所有的元素

|

逻辑或

//B | //C

所有B元素和C元素

位置匹配
对于每一个元素,它的各个子元素是有序的。如:

  例

  义

匹配结果

/A/B/C[1]

A元素→B元素→C元素的第一个子元素

name值为b的B元素

/A/B/C[last()]

A元素→B元素→C元素的最后一个子元素

id值为e2的E元素

/A/B/C[position()>1]

A元素→B元素→C元素之下的位置号大于1的元素

id值为d1的D元素和两个具有id值的E元素

属性及属性值
在XPath中可以利用属性及属性值来匹配元素,要注意的是,元素的属性名前要有"@"前缀。例如:

  例

  义

匹配结果

//B[@id]

所有具有属性id的B元素

id值为b1和b2的两个B元素

//B[@*]

所有具有属性的B元素

两个具有id属性的B元素和一个具有name属性B元素

//B[not(@*)]

所有不具有属性的B元素

A元素→C元素下的B元素

//B[@id="b1"]

id值为b1的B元素

A元素下的B元素

亲属关系匹配
XML文档可归结为树型结构,因此任何一个节点都不是孤立的。通常我们把节点之间的归属关系归结为一种亲属关系,如父亲、孩子、祖先、后代、兄弟等等。在对元素进行匹配时,同样可以用到这些概念。例如:

  例

  义

匹配结果

//E/parent::*

所有E节点的父节点元素

id值为a1的A元素和id值为c1的C元素

//F/ancestor::*

所有F元素的祖先节点元素

id值为a1的A元素和id值为c2的C元素

/A/child::*

A的子元素

id值为b1、b2的B元素,id值为c2的C元素,以及没有任何属性的E元素

/A/descendant::*

A的所有后代元素

A元素以外的所有其它元素

//F/self::*

所有F的自身元素

F元素本身

//F/ancestor-or-self::*

所有F元素及它的祖先节点元素

F元素、F元素的父节点C元素和A元素

/A/C/descendant-or-self::*

所有A元素→C元素及它们的后代元素

id值为c2的C元素、该元素的子元素B、D、F元素

/A/C/following-sibling::*

A元素→C元素的紧邻的后序所有兄弟节点元素

没有任何属性的E元素

/A/C/preceding-sibling::*

A元素→C元素的紧邻的前面所有兄弟节点元素

id值为b1和b2的两个B元素

/A/B/C/following::*

A元素→B元素→C元素的后序的所有元素

id为b2的B元素、无属性的C元素、无属性的B元素、id为d2的D元素、无属性的F元素、无属性的E元素。

/A/C/preceding::*

A元素→C元素的前面的所有元素

id为b2的B元素、id为e2的E元素、id为e1的E元素、id为d1的D元素、name为b的B元素、id为c1的C元素、id为b1的B元素

条件匹配
条件匹配就是利用一些函数的运算结果的布尔值来匹配符合条件的节点。常用于条件匹配的函数有四大类:节点函数、字符串函数、数值函数、布尔函数。
例如前面提到的last()、position()等等。这些功能函数可以帮助我们精确寻找需要的节点。
  

函数及功能

作用

count()功能

统计计数,返回符合条件的节点的个数

number()功能

将属性的值中的文本转换为数值

substring() 功能

语法:substring(value, start, length)

截取字符串

sum()功能
  

求和

 

这些功能只是XPath语法中的一部分,还有大量的功能函数没有介绍,而且目前XPath的语法仍然在不断发展中。通过这些函数我们可以实现更加复杂的查询和操作。

以上这些匹配方法中,用得最多的还要数路径匹配。依靠给出相对于当前路径的子路径来定位节点的。

2005年08月05日

var oTbl,tr;
var strsubmitdate;
oTbl=document.getElementById("DataGrid1");
for(var i=1;i<oTbl.rows.length-1;i++){  
 tr=oTbl.rows.item(i);
if (tr.cells[2].children[0].checked){
alert(i);
alert(tr.cells[1].innerText);//这是datagrid1里面的第一列的值         
                                     alert(tr.cells[0].getElementsByTagName (‘input’)[0].value);    //这是绑的一个Textbox的值在第二列
}
}

页面代码:
<asp:datagrid id="DataGrid1" runat="server" Width="535px" AutoGenerateColumns="False" BackColor="#FFFFF5">
<ItemStyle HorizontalAlign="Center"></ItemStyle>
<HeaderStyle HorizontalAlign="Center" BackColor="#DDDDD5"></HeaderStyle>
<Columns>
<asp:TemplateColumn HeaderText="选择清单">
<HeaderStyle HorizontalAlign="Center"></HeaderStyle>
<ItemStyle HorizontalAlign="Center"></ItemStyle>
<HeaderTemplate>
<FONT face="宋体">选择</FONT>
</HeaderTemplate>
<ItemTemplate>
<INPUT id="<%#  Container.ItemIndex %>" type=radio value="<%# Container.ItemIndex %>" name=radioes>
</ItemTemplate>
<EditItemTemplate>
<FONT face="宋体"></FONT>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="顺序">
<HeaderTemplate>
<FONT face="宋体">顺序</FONT>
</HeaderTemplate>
<ItemTemplate>
<asp:Label id="billingnum" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateColumn>
<asp:BoundColumn Visible="False" DataField="primarycode" HeaderText="物品清单编号">
<ItemStyle HorizontalAlign="Center"></ItemStyle>
</asp:BoundColumn>
<asp:BoundColumn Visible="False" DataField="casecode" HeaderText="案件编号"></asp:BoundColumn>
<asp:BoundColumn Visible="False" DataField="isaudit" HeaderText="是否审核"></asp:BoundColumn>
<asp:BoundColumn DataField="isaudit" HeaderText="是否审核"></asp:BoundColumn>
<asp:BoundColumn HeaderText="记录总数"></asp:BoundColumn>
<asp:BoundColumn DataField="adddate" HeaderText="生成时间"></asp:BoundColumn>
<asp:BoundColumn DataField="memo" HeaderText="描述"></asp:BoundColumn>
</Columns>
</asp:datagrid>
后台代码:

private void Button_update_Click(object sender, System.EventArgs e)
{
string radio_id = Request.Form["radioes"];

if(radio_id!="" && radio_id!=null)
{

int i=Convert.ToInt32(radio_id);
        StringBuilder str=new StringBuilder(100);
System.Web.UI.WebControls.DataGridItem dgi=this.DataGrid1.Items[i];
str.Append(dgi.Cells[2].Text.Trim());
ViewState["primarycode"]=str.ToString();
StringBuilder str2=new StringBuilder(100);
System.Web.UI.WebControls.DataGridItem dgi2=this.DataGrid1.Items[i];
str2.Append(dgi.Cells[4].Text.Trim());
string isautid=str2.ToString();
}
}

2005年08月02日

很多用户在自己的机器中架设起网站、FTP服务,甚至是小型邮件服务器,但这些网络服务由于防火墙或处于内网的缘故,只能供自己或同一局域网内的用户使用。

  如果你想让这些网络服务被更多的人分享,其实可以利用防火墙将这些服务发布到互联网中,如何发布呢?

  下面,e博士就针对Windows XP系统的Windows防火墙的“服务发布”功能,介绍几种常用服务的发布操作。

  服务发布“要素”

  在进行服务发布操作之前,首先要了解发布服务所要掌握的几个要素,它有助于用户对服务发布的理解。这几个要素依次是“服务发布所使用的协议”、“服务使用的端口”、“防火墙映射端口”、“服务器的IP地址”。

  以发布IIS服务为例。默认情况下,IIS服务是在TCP的80端口监听用户的访问,所以这个“80”就是IIS服务使用的端口。当然这个端口号也可以自定义,如修改为“8000”,只要不和别的服务使用的端口号冲突即可。

  其次要正确理解IIS服务发布所使用的协议,它使用的是TCP协议。

  提示:我们通常说的“HTTP”协议是指用户访问IIS网站所需要的协议,而IIS服务发布所使用的是TCP协议,它和“HTTP”协议是不同的。

  另外,还要清楚地知道IIS服务的IP地址,以及它在Windows防火墙中所使用的映射端口,这个映射端口也可以是“80”,当然也可以自行修改,只要该映射端口没被别的服务占用即可。

  实战

  了解了服务发布所需要掌握的几个要素后,下面就开始“小试牛刀”。

  1.Web服务发布

  下面,笔者就通过Windows防火墙将内网中的IIS服务发布到互联网中。该IIS服务器位于内网,并且使用IP地址“192.168.1.5”,没发布之前只有同一局域网中的用户能访问它,互联网中的其他用户则无法访问。想让更多的用户访问到它,就必须将IIS服务发布到公网上才行。

  在网关服务器的系统托盘中,右键点击连接公网的那块网卡的图标,在弹出的菜单中选择“更改Windows防火墙设置”,弹出“Windows防火墙”对话框,切换到“高级”标签页,然后在“网络连接设置”框中选中连接公网的那个连接选项后,点击“设置”按钮,弹出“高级设置”对话框(图1),切换到“服务”标签页,在这里就可以对IIS服务进行发布。


图1

  在Windows防火墙中已经内置了常用的服务发布选项,如Web服务器、FTP服务器等,只是没被启用。如果IIS服务使用的端口和Windows防火墙的映射端口都是使用默认的“80”,直接启用内置的“Web服务器发布选项”即可完成IIS服务发布。在服务标签页中,勾选“Web服务器(HTTP)”选项后,双击该选项,在弹出的“服务设置”对话框中的“在您的网络上主持此服务的计算机的名称或IP地址”栏输入IIS服务的IP地址,如“192.168.1.5”,然后点击“确定”按钮,最后在服务标签页中点击“确定”完成IIS服务的发布。

  补充:如果IIS服务使用的端口和Windows防火墙的映射端口不全是默认的“80”,那么我们就要新建服务发布选项,完成IIS服务的发布。如IIS服务使用的是“8000”端口,Windows防火墙的映射端口使用“80”。在服务标签页中点击“添加”按钮,弹出“服务设置”对话框(图2),在“服务描述”栏中为该服务发布选项设置一个名称,如“我的Web服务器”,接着在“在您的网络上主持此服务的计算机的名称或IP地址”栏中输入IIS服务器的IP地址,选中“TCP”单选项,然后在“此服务的外部端口号”栏中输入“80”,也就是Windows防火墙的映射端口,在“此服务的内部端口号”栏中输入“8000”,这是IIS服务器所使用的端口号,最后点击“确定”按钮,完成IIS服务的发布。


图2

  2.FTP服务发布

  Windows防火墙中也内置了FTP服务器的发布选项。如果FTP服务使用的端口和Windows防火墙的映射端口都为默认的“21”,就可以直接启用FTP服务发布选项。方法同IIS服务的发布是一样的。但此时要注意服务器发布选项中不包含服务器的IP地址参数,需要我们手工设置。因此双击服务标签页中的“FTP服务器”选项,在“服务设置”对话框中的“在您的网络上主持此服务的计算机的名称或IP地址”栏输入FTP服务器的IP地址即可,最后点击“确定”按钮。

  有些用户发现,启用了内置的FTP服务器选项后,还是不能正常访问FTP服务器,这是因为用户访问FTP服务器,不但要使用FTP服务器的“21”端口,还需要使用“20”端口传输数据,必须将该端口发布到公网上才行。

  新建一个服务发布选项,将“20”端口发布到公网中。在服务标签页中点击“添加”按钮,弹出“服务设置”对话框,在“服务描述”栏中输入“FTP服务器-20”,接着输入FTP服务器的IP地址,选中“TCP”单选项,然后在“此服务的外部端口号”栏中输入“20”,在“此服务的内部端口号”栏中输入“20”,最后点击“确定”按钮,完成FTP服务器的“20”端口的发布。

  以上只是简单介绍了一下Web服务和FTP服务的发布,其他服务的发布方法也是相同的,只要你了解服务发布中的几个要素:服务发布所使用的协议(TCP或UDP)、服务使用的端口(可能有多个)、防火墙映射端口(可能有多个)以及服务器的IP地址,就能圆满完成服务的发布。

  在网关服务器的系统托盘中,右键点击连接公网的那块网卡的图标,在弹出的菜单中选择“更改Windows防火墙设置”,弹出“Windows防火墙”对话框,切换到“高级”标签页,然后在“网络连接设置”框中选中连接公网的那个连接选项后,点击“设置”按钮,弹出“高级设置”对话框(图1),切换到“服务”标签页,在这里就可以对IIS服务进行发布。


图1

  在Windows防火墙中已经内置了常用的服务发布选项,如Web服务器、FTP服务器等,只是没被启用。如果IIS服务使用的端口和Windows防火墙的映射端口都是使用默认的“80”,直接启用内置的“Web服务器发布选项”即可完成IIS服务发布。在服务标签页中,勾选“Web服务器(HTTP)”选项后,双击该选项,在弹出的“服务设置”对话框中的“在您的网络上主持此服务的计算机的名称或IP地址”栏输入IIS服务的IP地址,如“192.168.1.5”,然后点击“确定”按钮,最后在服务标签页中点击“确定”完成IIS服务的发布。

  补充:如果IIS服务使用的端口和Windows防火墙的映射端口不全是默认的“80”,那么我们就要新建服务发布选项,完成IIS服务的发布。如IIS服务使用的是“8000”端口,Windows防火墙的映射端口使用“80”。在服务标签页中点击“添加”按钮,弹出“服务设置”对话框(图2),在“服务描述”栏中为该服务发布选项设置一个名称,如“我的Web服务器”,接着在“在您的网络上主持此服务的计算机的名称或IP地址”栏中输入IIS服务器的IP地址,选中“TCP”单选项,然后在“此服务的外部端口号”栏中输入“80”,也就是Windows防火墙的映射端口,在“此服务的内部端口号”栏中输入“8000”,这是IIS服务器所使用的端口号,最后点击“确定”按钮,完成IIS服务的发布。


图2

  2.FTP服务发布

  Windows防火墙中也内置了FTP服务器的发布选项。如果FTP服务使用的端口和Windows防火墙的映射端口都为默认的“21”,就可以直接启用FTP服务发布选项。方法同IIS服务的发布是一样的。但此时要注意服务器发布选项中不包含服务器的IP地址参数,需要我们手工设置。因此双击服务标签页中的“FTP服务器”选项,在“服务设置”对话框中的“在您的网络上主持此服务的计算机的名称或IP地址”栏输入FTP服务器的IP地址即可,最后点击“确定”按钮。

  有些用户发现,启用了内置的FTP服务器选项后,还是不能正常访问FTP服务器,这是因为用户访问FTP服务器,不但要使用FTP服务器的“21”端口,还需要使用“20”端口传输数据,必须将该端口发布到公网上才行。

  新建一个服务发布选项,将“20”端口发布到公网中。在服务标签页中点击“添加”按钮,弹出“服务设置”对话框,在“服务描述”栏中输入“FTP服务器-20”,接着输入FTP服务器的IP地址,选中“TCP”单选项,然后在“此服务的外部端口号”栏中输入“20”,在“此服务的内部端口号”栏中输入“20”,最后点击“确定”按钮,完成FTP服务器的“20”端口的发布。

  以上只是简单介绍了一下Web服务和FTP服务的发布,其他服务的发布方法也是相同的,只要你了解服务发布中的几个要素:服务发布所使用的协议(TCP或UDP)、服务使用的端口(可能有多个)、防火墙映射端口(可能有多个)以及服务器的IP地址,就能圆满完成服务的发布。