XML和JSP交互技术

发表于:2007-07-14来源:作者:点击数: 标签:
XML和JSP都是近两年才出现的技术,目前已经成为了很多 程序员 的热点话题。XML(可扩展的标记语言)是用来定义文档标记语言的框架,主要用来存储和发送数据信息,以便各种基于WEB的应用之间能更方便的交换数据。而Jsp是 服务器 端程序动态设计语言,可以用
XML和JSP都是近两年才出现的技术,目前已经成为了很多程序员的热点话题。XML(可扩展的标记语言)是用来定义文档标记语言的框架,主要用来存储和发送数据信息,以便各种基于WEB的应用之间能更方便的交换数据。而Jsp是服务器端程序动态设计语言,可以用来设计服务器端各种程序如B2B、B2C等各种系统,由于其面向对象、编译执行、健壮等特性,也得到了越来越多的应用。

   一个很实用的技术就是如何将XML和JSP结合起来,所幸的是我们不用去写底支持层东西了,因为很多厂商如SUN、IBM等都发布了自己的支持XML的API,其中SUN公司提供了一个支持在Java下使用XML的API-JAXP(JAVATM API for XML Processing Optional Package),这部分API提供了基本的读写、操作XML文档的功能,通过它我们可以很方便的将XML集成到Java应用程序中来。

   目前JAXP的版本是1.1,除了基本XML支持外还支持SAX 2.0 、DOM 2和XSL技术。SUN公司提供的JAXP可以在SUN公司的主页(下载)。

   一、 JAXP的安装

   1、安装前请确认您用的是JDK 1.1.8 以上版本的Java环境。
   2、在http://java.sun.com/xml 下载JAXP1.1的zip版本,解压到硬盘中,假定解压目录为#JAXP11,解压后发现有三个jar文件jaxp.jar crimson.jar xalan.jar,这就是JAXP的核心了。
   3、修改系统的CLASSPATH变量,在Windows平台下添加这样一行:

    #JAXP11\jaxp.jar; #JAXP11\crimson.jar; #JAXP11\xalan.jar
    在Unix/Linux系统下添加下面一行:
    #JAXP11/jaxp.jar: #JAXP11/crimson.jar: #JAXP11/xalan.jar alan.jar

如果你使用的是Java2的话,有一种更简单的方法,将上面的三个文件直接拷贝到JDK的Lib扩展目录中去,如#JAVA_HOME/jre/lib/ext(#JAVA_HOME代表JDK目录),这样就不用修改CLASSPATH了。

   4、好了,安装完成了,下一步就是编写程序然后运行了。   二、 简单的XML例子

   XML (EXtensible Markup Language )是一种类似HTML的语言,和HTML不同,XML主要用来描述结构化数据,通过XML格式我们可以很方便的在各种应用程序之间交换数据,而这些都是传统技术需要花费很大精力才能做到的。

   让我们来看一个简单的XML文档例子,这个例子保存了部分个人档案,请将它保存为personal.xml文件,因为后面我们的Jsp文件还会调用它中间的数据。

   <个人档案>

   <姓名>xxxx

   <性别>男

   <年龄>24
   coolknight@263.net

   <个人主页> ;http://www.21jsp.com

   <介绍>欢迎大家访问我的主页!

是不是很类似于HTML文件,如HTML中的元素"你好"等等,因为XML和HTML一样都是标准SGML的子集合,所以有类似之处。但也有很多不同之处需要注意,比如XML文件必须有成对地标记而且大小写敏感,而这些在HTML中都是默认允许的。

  〉谝恍惺潜匦氲?ML声明, 我们可以看到声明是在之间的,中间可以定义部分属性,version="1.0"表示文档将使用XML1.0的规范,encoding="gb2312"表示采用中文字符集,这样我们在下面对于数据就可以使用中文了。

   接着就是<个人档案>标记了,这是XML文件中的根元素,也是不可缺少的,而且必须有一个对应的结束标记,在开始和结束标记之间我们就可以定义自己的数据描述了。

   嵌套在<个人档案>标记如"<姓名>刘玉锋"就是具体的数据描述了,同根元素一样必须是成对的标记,在标记中间可以是标记对应具体的数值。这种表示方法有点类似于数据库中的记录了,字段名字为"姓名"、"性别"等,上面的XML文件就相当于一个只有一条记录的表"个人档案"。当然在XML文件中可以进行多层嵌套,但这就不在本文的讨论范围了。

   当然,这里只是一个特别简单能代表XML的例子,XML的相关内容特别多,如果想更多了解XML的话建议还是看相关的书籍。

三、JSP和XML交互

   前面已经说过了,Jsp通过SUN公司的API-JAXP可以实现和XML的交互,那么具体实现主要有两种方法,一种是采用DOM2 API,另外一种是采用SAX2 API。

   在这里我们主要讨论JAXP中的SAX(Simple API for XML Parsing)技术,DOM2技术可以看SUN公司相关的文档。

   1)关于SAX模型
   SAX模型是一种处理XML文件的方法,它是事件驱动的,有些类似于AWT中的事件驱动机制,通过事件驱动来识别XML文档的内容。在API中关于SAX的主要有下面的几个包:

   oorg.xml.sax
   oorg.xml.sax.helpers
   oorg.xml.sax.ext

在前台的Java程序或者是Jsp程序中通过调用这几个包中的API就可以很好地实现Java和XML的交互。

   2)关于HandlerBase接口

   我们知道在AWT中一般是通过实施ActionListener等接口实现事件的处理的,同样的在SAX中SUN也提供了一个类似的接口HandlerBase来处理XML解析的功能,通过将HandlerBase和XML文件关联可以很好的来处理XML文件。

   在实施接口中我们主要重载三个HandlerBase的方法startElement(String tag, AttributeList attrs)、characters(char[] ch, int start, int length)、endElement(String name)。

   startElement()在读取一行XML数据的开始标记时候触发,子类必须覆盖这个方法,这样就可以在处理XML节点前先进行自己的处理(比如开始读取或者写入XML文件中的节点时候)。

   public void startElement (String name, AttributeList attributes)
    throws SAXException
    {
     // no op
     }

参数name代表XML节点名字,attributes代表默认或者特殊的属性,这个方法抛出一个违例org.xml.sax.SAXException。

   characters()方法主要用来处理和之间具体的数据,在处理节点数据时候触发,我们可以覆盖这个方法来进行数据操作的处理,可以添加代码读取节点数据值或者是写入节点数据值。   public void characters (char ch[], int start, int length)

    throws SAXException
    {
     // no op
    }

参数ch[]代表一个字符数组,start代表字符数组的开始位置,length代表要取的字符数组中ch[]中的元素个数,同样的这个方法抛出一个违例org.xml.sax.SAXException。

   endElement()方法在处理节点元素结束的时候触发,也就是碰到标记的时候,我们可以覆盖这个方法来进行数据的收尾工作,比如将节点数据写入到文件中。   public void endElement (String name)

    throws SAXException
     {
      // no op
     }

参数name代表XML节点名字,这个方法抛出一个违例org.xml.sax.SAXException

   从上面我们也可以看出,三个方法在XML事件处理中的顺序依次为:

    startElement()àcharacters()àendElement(String name)

也许还不好理解,不要紧在下面我们将会写一个类myHandler类实现HandlerBase接口,并且覆盖这三个主要的方法来实现我们的XML文件读取操作。

   3)关于哈希表

   由于程序用到了哈希表,所以在这里先简单的介绍一下哈希表的基本语法以便大家能更好的理解下面的程序。   哈希表HashTable是从Dictionary派生出来的,里面具有一系列的关键字和数值,一个关键字对应一个数值,识别主要是通过对象的哈希代码hashCode识别。

   我们程序中用到的方法如下:

   put(Object key,Object value)添加一对关键字/数值到哈希表中
   get(Object key)根据关键字得到它的值
   keys()取得所有关键字并返回一个集合Enumeration

此外,哈希表还具有其他很多有用的方法如长度size()、是否为空empty()、是否重复containsKey()等等,限于篇幅在这里就不进行介绍了。
4) 实施HandlerBase接口
   在这里我们编写一个myHandler的类,它用来实施HandlerBase接口,并且覆盖接口的三个主要方法startElement(String tag, AttributeList attrs)、characters(char[] ch, int start, int length)、endElement(String name)以便能对XML文件进行操作。

   为了保存数据以便外部程序能够调用本类中的数据,我们采用了哈希表结构来保存解析XML文件后的所有节点名字以及节点的数据值,startElement()方法主要用来读取XML文件中的节点名称,characters()方法主要用来根据节点名称读取节点数据,endElement()方法主要是在一个XML节点处理完毕后将这对节点名称和节点数据保存在哈希表中。

   在外部程序中我们只需要调用getTable()方法返回一个哈希表对象就可以读取所有的节点和节点数据值了。

   代码不多,而且我在下面添加了很多注释,应该很好看懂了。

   myHandler.java文件
   file://文件放置在包com.jsp21.www中
   package com.jsp21.www;
   file://导入相关的java API
   import java.io.*;
   import org.w3c.dom.*;
   import org.xml.sax.*;
   import javax.xml.parsers.SAXParser;
   import javax.xml.parsers.SAXParserFactory;
   import java.util.Hashtable;
   import java.util.Enumeration;

   // myHandler类实现HandlerBase接口;

   public class myHandler extends HandlerBase {
   private String myElement = null; file://XML文件中的标记名称;
   private String myValue = null; file://XML文件中标记对应的值;
   private Hashtable mytable = new Hashtable(); file://用来保存XML文件中所有的数据;
   file://得到保存有XML数据的哈希表Hashtable;
   public Hashtable getTable() {
    return mytable;
   }

   file://覆盖HandlerBase接口中的startElement方法,读取一行XML数据的开始标记时候执行此方法;

   // tag代表XML中的标记,如前面XML文件中的NAME AGE等;

   public void startElement(String tag, AttributeList attrs)
    throws SAXException {
    myElement = tag;
   }

   file://覆盖HandlerBase接口中的characters方法,主要用来得到和之间具体的数据;

   // 当对应myElement的标记发现值后,也就是startElement方法执行完毕后,就会触发这个characters方法来得到具体的数值;

   file://如myElement="姓名"时候,myValue就会等于"刘玉锋";
   public void characters(char[] ch, int start, int length)
   throws SAXException {
     myValue = new String(ch, start, length);
   }

   file://覆盖HandlerBase接口中的endElement方法,主要用来在一行XML数据读取完毕后进行自己的处理;

   // 当XML文件中一行标记读取完毕后,触发此endElement方法;
   file://如果存在对应的结束标记,就将前面得到的标记myElement和值myValue
   file://放入到mytable哈希表中;
   public void endElement(String name) throws SAXException {
   if ( myElement.equals(name) ) {
    mytable.put(myElement, myValue);
   }
   }
   }

好了,编译这个class,并把myHandler.class文件放置在CLASSPATH能找到的路径中,比如Tomcat中应用程序的Web-inf\classes\com\jsp21\www目录下。

5)Jsp程序调用XML

   在这里,我们写了一个比较简单的Jsp程序来调用前面的myHandler类,并通过这个类来读取personal.xml文件中的内容,最后显示在Jsp页面中。

   首先我们创建一个SAXParserFactory的实例saxpF,然后通过这个实例来创建一个SAXParser的实例saxpser(可以用来解析XML文件内容),当然还要创建myHandler类的实例,最后通过saxpser.parse()方法将XML文件和myHandler类实例关联起来(这样会执行myHandler中的几个事件处理方法)。

(说明:SAXParserFactory是一个抽象类,定义了一个factory API可以让Java应用程序配置或者是获得一个SAX的解析器(SAX parser)。SAXParser也是一个抽象类,通过这个类应用程序可以解析XML文件的内容。)

   到这时候XML所有内容都保存在了myHandler类实例中的哈希表中,最后通过getTable()方法得到这个哈希表对象,将哈希表中的键保存在集合Enumeration中,使用一个循环来读取哈系表中的数据并显示在Jsp页面上。我们用集合的目的在于使这个Jsp程序尽量通用,传递一个XML文件名字就可以读出所有内容,当然你也可以不使用集合而使用(String)hshTable.get("姓名")这样的方法来读取特定的节点值。

   下面是Jsp文件代码,请保存为jspxml.jsp文件

这是一个XML+JSP的例子,读取XML文件中的内容

代码写完好,将此文件放在Web应用程序目录下,然后通过浏览器运行这个程序,如http://192.168.0.98:7070/welcome_html/jspxml.jsp?file=e:\\personal.xml,注意必须使用参数?file=路径\\personal.xml (路径根据你保存在硬盘中的目录而定,Java表示:Windows系统下"\\"代表一个"\"),运行后的效果如下面所示:

可以看到,XML文件中的所有数据都通过这个Jsp文件读取出来了,因为这个Jsp程序是文件无关的,你也可以将file=e:\\personal.xml中的xml文件名字换为其他的XML文件看看最后运行效果。

   要说明一点的就是本人在最后实际采用的是JAXP1.01版本的API,有可能是本人的系统原因,发现程序在1.1版本下可以编译通过,但运行的时候会出现下面错误(即使JAXP1.1包中自带的例子main.java也这样):

   java.lang.NoClassDefFoundError: org.apache.crimson.jaxp.SAXParserFactoryImpl

所以最后换作了1.01版本的JAXP来运行程序,1.01版本的JAXP在上面的地址同样可以下载。

原文转自:http://www.ltesting.net