SAX入门
来源:互联网 发布:椰族部落永久域名新址 编辑:程序博客网 时间:2024/04/30 12:17
wukejia@msn.com
本文为打算在程序中使用SAX2技术的Java程序员提供一个快速指南。
SAX是一个针对多种不同XML解析器(以及具备XML解析器行为的东西)实现的通用接口。就像JDBC是一个针对不同关系数据库(以及看起来象关系数据库一样的东东)实现的接口一样。如果你打算使用SAX,以下前提是必须的:
(1)Java 1.1 或其更高版本。
(2)一个SAX2兼容的XML解析器,它应当被安装在Java classpath中。
(3)SAX2的发布包(通常由XML解析器提供)应当安装在Java classpath中。大多数的Java/XML工具都会包括SAX2以及一个使用它的解析器。
绝大多数的web应用服务器使用SAX2做为它们对XML的核心支持。尤其是具备JAXP 1.1支持的环境通常都提供SAX2。
首先,创建一个继承自DefaultHandler的类:
import org.xml.sax.helpers.DefaultHandler;
public class MySAXApp extends DefaultHandler
{
public MySAXApp ()
{
super();
}
}
因为这是个Java程序,我们创建一个main方法,使用XMLReaderFactory的createXMLReader方法动态选取一个SAX驱动。注意此处的“throws Exception”只是象征性的,真正的程序中不应出现这么简陋的异常处理代码:
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
}
如果你的Java环境无法提供一个默认的编译时XML驱动(或者使用系统资源META-INF/services/org.xl.sax.driver),那么你有必要设置Java系统属性org.xml.sax.driver的值为SAX驱动的全类名,比如:
java -Dorg.xml.sax.driver=com.example.xml.SAXDriver MySAXApp sample.xml
你可能使用到的类名有:
Class Name Notes
gnu.xml.aelfred2.SAXDriver Lightweight non-validating parser; Free Software
gnu.xml.aelfred2.XmlReader Optionally validates; Free Software
oracle.xml.parser.v2.SAXParser Optionally validates; proprietary
org.apache.crimson.parser.XMLReaderImpl Optionally validates; used in JDK 1.4; Open Source
org.apache.xerces.parsers.SAXParser Optionally validates; Open Source
或者,如果你不介意把你的程序绑定到一个唯一的SAX驱动,你可以直接使用它的构造函数:
public static void main (String args[])
throws Exception
{
XMLReader xr = new com.example.xml.SAXDriver();
}
这里我们假设用到的XML解析器的SAX驱动名叫com.example.xml.SAXDriver(实际上不存在)。我们能够使用这个对象来解析XML文档,但首先,我们必须注册解析器用来报告信息的事件处理器,这通过XMLReader接口的setContentHandler方法和setErrorHandler方法实现。在真实的应用中处理器通常是分别独立的对象,但对这个简单的演示,我们把所有的处理器绑定到顶级类(MySAXApp),我们实例化这个类,并把它注册给XML读取对象:
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
MySAXApp handler = new MySAXApp();
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
}
以上代码创建一个MySAXApp的实例来接收XML解析事件,并把它注册给XML读取器以接收规范的内容事件和错误事件(还有其它极少用到的事件)。现在,让我们假定所有的命令行参数都是文件名,我们尝试用XMLReader接口的parse方法一个一个地解析它们:
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
MySAXApp handler = new MySAXApp();
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
// Parse each file provided on the command line.
for (int i = 0; i < args.length; i++) {
FileReader r = new FileReader(args[i]);
xr.parse(new InputSource(r));
}
}
注意,每一个XML资源必须被包装到InputSource对象中来被解析。下面是完整的演示代码(到目前为止):
import java.io.FileReader;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.helpers.DefaultHandler;
public class MySAXApp extends DefaultHandler
{
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
MySAXApp handler = new MySAXApp();
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
// Parse each file provided on the command line.
for (int i = 0; i < args.length; i++) {
FileReader r = new FileReader(args[i]);
xr.parse(new InputSource(r));
}
}
public MySAXApp ()
{
super();
}
}
你可以编译这个代码并运行它(记得指定org.xml.sax.driver属性为SAX驱动),但除非文档包含没有定义良好的XML,程序不会输出任何信息,因为你还没有设置你的程序来处理SAX事件。
当你开始实现XML解析事件的处理方法时,情况开始变得有趣(记得在前面一段我们注册了一个类来接收XML解析事件)。最重要的事件是文档的开始和结束,元素的开始和结束以及字符数据。
为了找出文档的开始和结束,客户程序实现startDocument和endDocument方法:
public void startDocument ()
{
System.out.println("Start document");
}
public void endDocument ()
{
System.out.println("End document");
}
start/endDocument事件处理器不接收任何参数。当SAX驱动找到文档开始的时候,它将调用startDocument方法一次;当它找到文档尾的时候,它将调用endDocument方法一次(即使有错误存在)。
上面的例子只是打印了一条消息到标准输出流中,但你的程序可以在这些事件处理器中包含任何代码:最通常的做法是,程序将在内存中构建某种类型的树,产生输出,操纵数据库,或从XML流中抽取信息。
SAX驱动也以同样的方式对元素开始和结束作出响应,所不同的是它将传入参数给方法startElement和endElement:
public void startElement (String uri, String name,
String qName, Attributes atts)
{
if ("".equals (uri))
System.out.println("Start element: " + qName);
else
System.out.println("Start element: {" + uri + "}" + name);
}
public void endElement (String uri, String name, String qName)
{
if ("".equals (uri))
System.out.println("End element: " + qName);
else
System.out.println("End element: {" + uri + "}" + name);
}
这个方法在每一个元素开始或结束的时候打印一行消息,括号中的是名字空间URI。参数qName包含的是XML 1.0中定义的名字,只能用于所有没有名字空间URI的元素。在这个快速入门里,我们不会看到访问属性的代码;你可以通过属性名来访问它们,或者,如果它们构成一个矢量的话,你可以遍历它们。
最后,SAX2将通过characters方法报告字符数据;下面的实现将会把所有的字符数据打印到屏幕上;因为它需要对特殊字符做专门处理,所以会花费较长时间:
public void characters (char ch[], int start, int length)
{
System.out.print("Characters: /"");
for (int i = start; i < start + length; i++) {
switch (ch[i]) {
case '//':
System.out.print("////");
break;
case '"':
System.out.print("///"");
break;
case '/n':
System.out.print("//n");
break;
case '/r':
System.out.print("//r");
break;
case '/t':
System.out.print("//t");
break;
default:
System.out.print(ch[i]);
break;
}
}
System.out.print("/"/n");
}
注意,SAX驱动会按照自己的方式随意组织字符数据成块,因此,你不能指望一个元素内容所有的字符数据都能被一个characters事件所捕获。
以下是一个完整的例子程序(再强调一下,在真实的应用中,各事件处理器可能分别由不同的类实现):
import java.io.FileReader;
import org.xml.sax.XMLReader;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.helpers.DefaultHandler;
public class MySAXApp extends DefaultHandler
{
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
MySAXApp handler = new MySAXApp();
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
// Parse each file provided on the command line.
for (int i = 0; i < args.length; i++) {
FileReader r = new FileReader(args[i]);
xr.parse(new InputSource(r));
}
}
public MySAXApp ()
{
super();
}
////////////////////////////////////////////////////////////////////
// Event handlers.
////////////////////////////////////////////////////////////////////
public void startDocument ()
{
System.out.println("Start document");
}
public void endDocument ()
{
System.out.println("End document");
}
public void startElement (String uri, String name,
String qName, Attributes atts)
{
if ("".equals (uri))
System.out.println("Start element: " + qName);
else
System.out.println("Start element: {" + uri + "}" + name);
}
public void endElement (String uri, String name, String qName)
{
if ("".equals (uri))
System.out.println("End element: " + qName);
else
System.out.println("End element: {" + uri + "}" + name);
}
public void characters (char ch[], int start, int length)
{
System.out.print("Characters: /"");
for (int i = start; i < start + length; i++) {
switch (ch[i]) {
case '//':
System.out.print("////");
break;
case '"':
System.out.print("///"");
break;
case '/n':
System.out.print("//n");
break;
case '/r':
System.out.print("//r");
break;
case '/t':
System.out.print("//t");
break;
default:
System.out.print(ch[i]);
break;
}
}
System.out.print("/"/n");
}
}
参考下面的XML文档:
<?xml version="1.0"?>
<poem xmlns="http://www.megginson.com/ns/exp/poetry">
<title>Roses are Red</title>
<l>Roses are red,</l>
<l>Violets are blue;</l>
<l>Sugar is sweet,</l>
<l>And I love you.</l>
</poem>
假设该文档名为roses.xml,名为com.example.xml.SAXDriver(实际上根本不存在这样的驱动)的SAX2驱动被部署在你的classpath中,你可以这样调用例子程序:
java -Dorg.xml.sax.driver=com.example.xml.SAXDriver MySAXApp roses.xml
运行后,得到如下结果:
Start document
Start element: {http://www.megginson.com/ns/exp/poetry}poem
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}title
Characters: "Roses are Red"
End element: {http://www.megginson.com/ns/exp/poetry}title
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "Roses are red,"
End element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "Violets are blue;"
End element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "Sugar is sweet,"
End element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "And I love you."
End element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "/n"
End element: {http://www.megginson.com/ns/exp/poetry}poem
End document
注意这个短文档所产生的(至少)25个事件:所用到的6个元素的开始和结束(活着,你愿意的话,一个开始标签,一个结束标签),11个字符数据块(包括元素间的空白),一个文档开始标签,一个文档结束标签。如果输入文档不包括xmlns="http://www.megginson.com/ns/exp/poetry"属性来声明所有元素都在此名称空间中,则输出结果会如下所示:
Start document
Start element: poem
Characters: "/n"
Start element: title
Characters: "Roses are Red"
End element: title
Characters: "/n"
Start element: l
Characters: "Roses are red,"
End element: l
Characters: "/n"
Start element: l
Characters: "Violets are blue;"
End element: l
Characters: "/n"
Start element: l
Characters: "Sugar is sweet,"
End element: l
Characters: "/n"
Start element: l
Characters: "And I love you."
End element: l
Characters: "/n"
End element: poem
End document
你很可能两种类型的文档都会用到:有的使用XML名称空间,有的不使用。你处理的文档中也可能有的元素(属性)有名称空间,而有的却没有。要确定你的程序中有检测名称空间URI的代码,而不是假定程序处理的文档总有名称空间URI(或总是没有名称空间URI)。
根据SAX Quickstart整理,原文见:http://www.saxproject.org/quickstart.html
本文为打算在程序中使用SAX2技术的Java程序员提供一个快速指南。
1 必备条件
SAX是一个针对多种不同XML解析器(以及具备XML解析器行为的东西)实现的通用接口。就像JDBC是一个针对不同关系数据库(以及看起来象关系数据库一样的东东)实现的接口一样。如果你打算使用SAX,以下前提是必须的:
(1)Java 1.1 或其更高版本。
(2)一个SAX2兼容的XML解析器,它应当被安装在Java classpath中。
(3)SAX2的发布包(通常由XML解析器提供)应当安装在Java classpath中。大多数的Java/XML工具都会包括SAX2以及一个使用它的解析器。
绝大多数的web应用服务器使用SAX2做为它们对XML的核心支持。尤其是具备JAXP 1.1支持的环境通常都提供SAX2。
2 解析一个文档
首先,创建一个继承自DefaultHandler的类:
import org.xml.sax.helpers.DefaultHandler;
public class MySAXApp extends DefaultHandler
{
public MySAXApp ()
{
super();
}
}
因为这是个Java程序,我们创建一个main方法,使用XMLReaderFactory的createXMLReader方法动态选取一个SAX驱动。注意此处的“throws Exception”只是象征性的,真正的程序中不应出现这么简陋的异常处理代码:
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
}
如果你的Java环境无法提供一个默认的编译时XML驱动(或者使用系统资源META-INF/services/org.xl.sax.driver),那么你有必要设置Java系统属性org.xml.sax.driver的值为SAX驱动的全类名,比如:
java -Dorg.xml.sax.driver=com.example.xml.SAXDriver MySAXApp sample.xml
你可能使用到的类名有:
Class Name Notes
gnu.xml.aelfred2.SAXDriver Lightweight non-validating parser; Free Software
gnu.xml.aelfred2.XmlReader Optionally validates; Free Software
oracle.xml.parser.v2.SAXParser Optionally validates; proprietary
org.apache.crimson.parser.XMLReaderImpl Optionally validates; used in JDK 1.4; Open Source
org.apache.xerces.parsers.SAXParser Optionally validates; Open Source
或者,如果你不介意把你的程序绑定到一个唯一的SAX驱动,你可以直接使用它的构造函数:
public static void main (String args[])
throws Exception
{
XMLReader xr = new com.example.xml.SAXDriver();
}
这里我们假设用到的XML解析器的SAX驱动名叫com.example.xml.SAXDriver(实际上不存在)。我们能够使用这个对象来解析XML文档,但首先,我们必须注册解析器用来报告信息的事件处理器,这通过XMLReader接口的setContentHandler方法和setErrorHandler方法实现。在真实的应用中处理器通常是分别独立的对象,但对这个简单的演示,我们把所有的处理器绑定到顶级类(MySAXApp),我们实例化这个类,并把它注册给XML读取对象:
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
MySAXApp handler = new MySAXApp();
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
}
以上代码创建一个MySAXApp的实例来接收XML解析事件,并把它注册给XML读取器以接收规范的内容事件和错误事件(还有其它极少用到的事件)。现在,让我们假定所有的命令行参数都是文件名,我们尝试用XMLReader接口的parse方法一个一个地解析它们:
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
MySAXApp handler = new MySAXApp();
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
// Parse each file provided on the command line.
for (int i = 0; i < args.length; i++) {
FileReader r = new FileReader(args[i]);
xr.parse(new InputSource(r));
}
}
注意,每一个XML资源必须被包装到InputSource对象中来被解析。下面是完整的演示代码(到目前为止):
import java.io.FileReader;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.helpers.DefaultHandler;
public class MySAXApp extends DefaultHandler
{
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
MySAXApp handler = new MySAXApp();
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
// Parse each file provided on the command line.
for (int i = 0; i < args.length; i++) {
FileReader r = new FileReader(args[i]);
xr.parse(new InputSource(r));
}
}
public MySAXApp ()
{
super();
}
}
你可以编译这个代码并运行它(记得指定org.xml.sax.driver属性为SAX驱动),但除非文档包含没有定义良好的XML,程序不会输出任何信息,因为你还没有设置你的程序来处理SAX事件。
3 处理事件
当你开始实现XML解析事件的处理方法时,情况开始变得有趣(记得在前面一段我们注册了一个类来接收XML解析事件)。最重要的事件是文档的开始和结束,元素的开始和结束以及字符数据。
为了找出文档的开始和结束,客户程序实现startDocument和endDocument方法:
public void startDocument ()
{
System.out.println("Start document");
}
public void endDocument ()
{
System.out.println("End document");
}
start/endDocument事件处理器不接收任何参数。当SAX驱动找到文档开始的时候,它将调用startDocument方法一次;当它找到文档尾的时候,它将调用endDocument方法一次(即使有错误存在)。
上面的例子只是打印了一条消息到标准输出流中,但你的程序可以在这些事件处理器中包含任何代码:最通常的做法是,程序将在内存中构建某种类型的树,产生输出,操纵数据库,或从XML流中抽取信息。
SAX驱动也以同样的方式对元素开始和结束作出响应,所不同的是它将传入参数给方法startElement和endElement:
public void startElement (String uri, String name,
String qName, Attributes atts)
{
if ("".equals (uri))
System.out.println("Start element: " + qName);
else
System.out.println("Start element: {" + uri + "}" + name);
}
public void endElement (String uri, String name, String qName)
{
if ("".equals (uri))
System.out.println("End element: " + qName);
else
System.out.println("End element: {" + uri + "}" + name);
}
这个方法在每一个元素开始或结束的时候打印一行消息,括号中的是名字空间URI。参数qName包含的是XML 1.0中定义的名字,只能用于所有没有名字空间URI的元素。在这个快速入门里,我们不会看到访问属性的代码;你可以通过属性名来访问它们,或者,如果它们构成一个矢量的话,你可以遍历它们。
最后,SAX2将通过characters方法报告字符数据;下面的实现将会把所有的字符数据打印到屏幕上;因为它需要对特殊字符做专门处理,所以会花费较长时间:
public void characters (char ch[], int start, int length)
{
System.out.print("Characters: /"");
for (int i = start; i < start + length; i++) {
switch (ch[i]) {
case '//':
System.out.print("////");
break;
case '"':
System.out.print("///"");
break;
case '/n':
System.out.print("//n");
break;
case '/r':
System.out.print("//r");
break;
case '/t':
System.out.print("//t");
break;
default:
System.out.print(ch[i]);
break;
}
}
System.out.print("/"/n");
}
注意,SAX驱动会按照自己的方式随意组织字符数据成块,因此,你不能指望一个元素内容所有的字符数据都能被一个characters事件所捕获。
4 SAX2应用实例
以下是一个完整的例子程序(再强调一下,在真实的应用中,各事件处理器可能分别由不同的类实现):
import java.io.FileReader;
import org.xml.sax.XMLReader;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.helpers.DefaultHandler;
public class MySAXApp extends DefaultHandler
{
public static void main (String args[])
throws Exception
{
XMLReader xr = XMLReaderFactory.createXMLReader();
MySAXApp handler = new MySAXApp();
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
// Parse each file provided on the command line.
for (int i = 0; i < args.length; i++) {
FileReader r = new FileReader(args[i]);
xr.parse(new InputSource(r));
}
}
public MySAXApp ()
{
super();
}
////////////////////////////////////////////////////////////////////
// Event handlers.
////////////////////////////////////////////////////////////////////
public void startDocument ()
{
System.out.println("Start document");
}
public void endDocument ()
{
System.out.println("End document");
}
public void startElement (String uri, String name,
String qName, Attributes atts)
{
if ("".equals (uri))
System.out.println("Start element: " + qName);
else
System.out.println("Start element: {" + uri + "}" + name);
}
public void endElement (String uri, String name, String qName)
{
if ("".equals (uri))
System.out.println("End element: " + qName);
else
System.out.println("End element: {" + uri + "}" + name);
}
public void characters (char ch[], int start, int length)
{
System.out.print("Characters: /"");
for (int i = start; i < start + length; i++) {
switch (ch[i]) {
case '//':
System.out.print("////");
break;
case '"':
System.out.print("///"");
break;
case '/n':
System.out.print("//n");
break;
case '/r':
System.out.print("//r");
break;
case '/t':
System.out.print("//t");
break;
default:
System.out.print(ch[i]);
break;
}
}
System.out.print("/"/n");
}
}
5 例子输出
参考下面的XML文档:
<?xml version="1.0"?>
<poem xmlns="http://www.megginson.com/ns/exp/poetry">
<title>Roses are Red</title>
<l>Roses are red,</l>
<l>Violets are blue;</l>
<l>Sugar is sweet,</l>
<l>And I love you.</l>
</poem>
假设该文档名为roses.xml,名为com.example.xml.SAXDriver(实际上根本不存在这样的驱动)的SAX2驱动被部署在你的classpath中,你可以这样调用例子程序:
java -Dorg.xml.sax.driver=com.example.xml.SAXDriver MySAXApp roses.xml
运行后,得到如下结果:
Start document
Start element: {http://www.megginson.com/ns/exp/poetry}poem
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}title
Characters: "Roses are Red"
End element: {http://www.megginson.com/ns/exp/poetry}title
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "Roses are red,"
End element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "Violets are blue;"
End element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "Sugar is sweet,"
End element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "/n"
Start element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "And I love you."
End element: {http://www.megginson.com/ns/exp/poetry}l
Characters: "/n"
End element: {http://www.megginson.com/ns/exp/poetry}poem
End document
注意这个短文档所产生的(至少)25个事件:所用到的6个元素的开始和结束(活着,你愿意的话,一个开始标签,一个结束标签),11个字符数据块(包括元素间的空白),一个文档开始标签,一个文档结束标签。如果输入文档不包括xmlns="http://www.megginson.com/ns/exp/poetry"属性来声明所有元素都在此名称空间中,则输出结果会如下所示:
Start document
Start element: poem
Characters: "/n"
Start element: title
Characters: "Roses are Red"
End element: title
Characters: "/n"
Start element: l
Characters: "Roses are red,"
End element: l
Characters: "/n"
Start element: l
Characters: "Violets are blue;"
End element: l
Characters: "/n"
Start element: l
Characters: "Sugar is sweet,"
End element: l
Characters: "/n"
Start element: l
Characters: "And I love you."
End element: l
Characters: "/n"
End element: poem
End document
你很可能两种类型的文档都会用到:有的使用XML名称空间,有的不使用。你处理的文档中也可能有的元素(属性)有名称空间,而有的却没有。要确定你的程序中有检测名称空间URI的代码,而不是假定程序处理的文档总有名称空间URI(或总是没有名称空间URI)。
根据SAX Quickstart整理,原文见:http://www.saxproject.org/quickstart.html
- SAX入门
- Sax快速入门
- javawebday08(sax解析入门)
- Android入门开发之SAX
- SAX解析XML(入门)
- SAX轻松入门(二)--带验证的SAX解析
- SAX轻松入门(三)--SAX过滤器(filter)
- Java解析XML文档SAX入门案例
- SAX
- SAX
- sax
- sax
- SAX
- sax
- SAX
- Sax
- Sax .
- sax
- 软件测试的14种类型(ZT)
- 通过ADO连接各种数据库的字符串翠集(一)
- McCabe推荐的代码走查方法
- 通过ADO连接各种数据库的字符串翠集(二)(完)
- [转帖]对C#开发两个基本原则的深入讨论
- SAX入门
- VB编程的市场
- C#.Net一百零一夜(第一夜)
- Java的起源
- Tomcat5.5下配置JNDI JDBC数据源
- .Net应用程序发布问题的最新解决方案,感觉比较爽(可桌面、程序中加自己的ICO及卸载等)
- SQL注入漏洞全接触
- 几种分页算法。翻页必备
- Stored Procedure(存储过程)编写经验和优化措施