kshen转Sean's XML学习笔记

转自http://blog.csdn.net/sean_gao/ 

 [XML学习笔记][1]基本概念

 

XML是eXtensible Markup Language的缩写,它的前身是SGML,或者说,XML是SGML的子集。简单讲,XML是一种文档格式,作为一种标准,有利于不同机构间的数据交换。从表面上看,XML是一种语言,但是它同时也是一种创造和定义其他语言的语言。通过一组定义好的规范,我们可以很方便的扩展它。

我们来看一个实际的XML长什么样:(仅仅是个最简单的例子,为了说明XML的基本结构)

< customer-repository >
  
< customer  index ="C82FB7E9982A02FD" >
    
< name  first-name ="Brian"  last-name ="Molko" />
    
< register-date >
      2005-01-01
    
</ register-date >
    
< visits >
      3
    
</ visits >
  
</ customer >
  
< customer  index ="BADE12908E72CB21" >
    
< name  first-name ="Alanis"  last-name ="Morissette" />
    
< register-date >
      2005-02-01
    
</ register-date >
    
< visits >
      1
    
</ visits >
  
</ customer >
</ customer-repository >

直观的看,我们这个XML文件定义了一组客户,每一个客户又有相应的ID、姓名、注册时间和到访次数。这就是一个最基本的XML,它很类似HMTL,但是一方面它可以有自定义的标签,另一方面它也要求更加严格的语法,如标签必有开闭且不能重叠等。不仅仅是这样,通常每个XML文件都会对应一组严格定义的语法,以便对它们进行正确的处理,这一点我会在稍后作更详细的说明。

 [XML学习笔记][2.1]XML验证

 

为了使得我们定义的XML文档有意义,我们通常必须为它定义一组语法,如:这个文档应该包含那种类型的数据,这种数据的层次结构又是怎样的,等等。这样我们的XML文档就可以通过专门的工具来验证其合法性。

有两种方式:I- DTD (document type definition); II- XSD (XML Schema definition),我们分别来看一下。

DTD比较简单和直截了当,它可以很容易的定义元素和元素之间的隶属关系,如:

<! ELEMENT customer-repository (customer+) >

<! ELEMENT customer (name, register-date, visits) >
<! ATTLIST customer
  index ID #REQUIRED
>

<! ELEMENT name (#PCDATA) >
<! ATTLIST name
  first-name CDATA #REQUIRED
  last-name CDATA #REQUIRED
>

<! ELEMENT register-date (#CDATA) >

<! ELEMENT visits (#CDATA) >

<!ELEMENT>用于定义元素,同时可以定义该元素是否包含其他元素,<!ATTLIST>用于定义元素的属性,具体的语法可以参考http://www.w3c.org/xml/ 上的文档。为了把我们的XML文档和上面定义的语法联系到一起,我们需要在XML中加入这样一行代码:

<! DOCTYPE customer-repository SYSTEM "customer-repository.dtd" >

与DTD类似,XSD也是通过一些规则来定义一类XML的语法,它比DTD更加灵活,也更加强大,是目前W3C主推的XML验证标准。它通过一些命名空间已经定义好的元素类型来定义我们的XML语法,如:

< xsd:element  name ="visits"  type ="xsd:decimal"   />

这里的xsd就是我们要用到的名字空间。由于目前大部分的XML还都是使用DTD的方式,对XSD的了解就到这里吧。有兴趣的可以去W3C的网站了解具体语法。

 [XML学习笔记][2.2]XML内容提取

 

为了让XML文档能够被应用程序识别和处理,必须提供一个读取XML文档的途径。当然,你也许会说,XML不就是文本文件吗?我用java.io包不就可以读取了?XML文件并非简单的plain text,它有自己的结构和描述性,我们需要在基本的I/O之上更进一步。常见的XML读取有两种不同的方式:SAX和DOM,下面我们分别来看一下:

SAX是Simple API for XML的缩写,顾名思义,就是处理XML的简单API,就象它的名字所暗示的那样,SAX比DOM要简单直接得多。本质上讲,SAX是事件驱动的,比如,当读取XML文件到一个标签的结尾时,该事件被传递到应用程序,应用程序做出相应处理,于是,应用程序在这个时候只知道已经读取的那一部分内容,而对剩下的XML数据一无所知。这正是SAX的局限,同时,因为SAX是读一部分处理一部分,它的速度相当快。

DOM是Document Object Model的缩写,文档对象模型,这个名字听上去就要更抽象一些,它是一次性把整个XML文档读取完毕然后构件一个完整的树状对象模型,于是它的速度要比SAX慢很多,但是对XML文档整体就有一个更加完整的视图,这在有些时候是必需的。

通常我们使用的XML API都同时支持这两种模式,在遇到具体问题时,我们可以根据文档的复杂度、规模、以及我们的需求来确定到底使用哪一种模式。

 [XML学习笔记][2.3]XML转换

 

作为W3C推出的拳头标准,XML的强大优势之一就是它可以方便的被转换成其他格式的XML或者其他不同类型的文件,如PDF、HTML等都是常见的XML转换的输出格式。

为了实现这个功能,我们需要利用到eXtensible Stylesheet Language for Transformations (XSLT)。XSL文件是这样一些样式表,它们指定如何从一个XML文件转换出其他的格式。这个是不是多少让你想起MFC的文档-视图结构或者MVC模式?

 [XML学习笔记][2.4]XML作为消息传递载体

 

由于XML的平台和技术独立性,它经常被用来在不同的系统之间传递消息,基于XML这一特性而产生的常见的技术和规范包括:SOAP、Web Services、UDDI和WSDL。

SOAP的全称是Simple Object Access Protocol,它定义了一类XML如何创建、打包和传送,可以直接通过HTTP方式同步或异步的传递;Web Services在很大程度上依赖于SOAP;UDDI相当于在网上存储和共享Web Services的位置信息,供使用者在需要调用某个Web Service时查询;而WSDL是Web Services Dercription Language的缩写,用于在UDDI上描述Web服务。

 [XML学习笔记][2.5]XML数据操作

 

XML的另一个重要的应用是数据操作。

就数据操作而言,一个基本的概念是XPath,XPath是一种语言,用于通过某种文本形式的途径表示XML文档中的元素或者另一个XML文档等等,基于XPath,我们才能够在XML中相对方便的引用到相关的内容,以致使用到XSLT这样的东东。

为什么会有这样的语言?因为在很多时候XML文档所代表的数据是相互关联的,而并非独立的一个一个元素和文档,XPath等语言使得很多高级的操作得以简单的完成。

 [XML学习笔记][2.6]XML存储


XML文档只能以文本文件的形式存在吗?错。

常见的XML存储形式有:

  • 文本文件
  • 关系数据库
  • 二进制文件
  • XML数据库(这个是不是有点过分了,呵呵)

以文本形式储存XML数据当然在很多情况下是适用的,也是我们最常看到的XML存储方式,因为我们在J2EE中接触最多的就是XML的配置文件嘛,如果不是文本的,我们改起来是不是就有点别扭了?只不过文本的东西每次用的时候都需要做转换,影响到执行的效率罢了。所以通常我们在做项目时也会用一些自动化的工具将我们的XML在系统运行或调试前做一些转换。

这样看,我们还真的不能想当然了。

 [XML学习笔记][3]在Java的世界中使用XML

在前面,我们一起很粗略的过了一遍XML的基础知识,下面该看看如何在Java中使用功能强大的XML了。由于XML的广泛应用,许多厂商或者团体都使用Java编写了用于处理XML的类库,这些类库之间并不兼容,为了给这些类库的使用者们提供一个通用的接口,我们欣喜地看到Java中引入了JAXP,Java API for XML Processing,我们当然也可以通过实现和扩展JAXP来构建我们自己的XML处理类。

在我们的日常Java编程中,需要处理XML通常是如下情形:

    I- 从XML中读取和分析数据
    II- 利用XLST将XML转换成其他格式

在接下来的笔记中,我们就分别来看看这两种工作如何通过JAXP来完成。
 [XML学习笔记][3.1]通过JAXP使用SAX
 

在前面的笔记中,我们曾经提到读取XML数据的两种截然不同的方式,SAX就是其中一种。来看一段代码:

/*
 * Created on 2005-2-24
 * All rights reserved.
 * 
 
*/

package sean.home.test;

import java.io.File;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * @author Sean GAO
 *         <p>
 *         gaoyuxiang@gmail.com
 *         </p>
 * 
 
*/

public   class  Main  {

    
public static void main(String[] args) throws Exception {

        SAXParserFactory factory 
= SAXParserFactory.newInstance();
        SAXParser parser 
= factory.newSAXParser();

        DefaultHandler myHandler 
= new DefaultHandler() {

            
public void startDocument() throws SAXException {
                System.
out.println("XML document starts ");
            }


            
public void endDocument() throws SAXException {
                System.
out.println("XML document ends ");
            }


            
public void startElement(String uri, String localName,
                    String qualifiedName, Attributes attributes)
                    throws SAXException 
{
                System.
out.println("element " + qualifiedName + "starts ");
            }


            
public void endElement(String uri, String localName,
                    String qualifiedName) throws SAXException 
{
                System.
out.println("element " + qualifiedName + "ends ");
            }


            
public void characters(char[] ch, int start, int length) {
                System.
out.println(new String(ch, start, length));
            }


        }
;
        
        parser.parse(
new File(args[0]), myHandler);
        
    }

}



在这段代码中,我们通过SAXParserFactory获取一个parser,然后自定义一个Handler去处理由SAX读取XML文件时触发的事件,如startDocument表示文档开始,endElement表示元素读取结束,characters表示在元素体内读到内容等等。这里我为了方便直接写成匿名内部类了,Exception也没有做任何处理,这在实际中通常是不合理的。

基本上SAX的实现和使用都很直截了当,就是处理一个个事件罢了。
 [XML学习笔记][3.2]通过JAXP使用DOM
 

DOM的调用方法看上去跟SAX也很类似:

/*
 * Created on 2005-2-24
 * All rights reserved.
 *
 
*/

package sean.home.test;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * @author Sean GAO 
 * <p>
 * gaoyuxiang@gmail.com
 * </p>
 * 
 
*/

public   class  DOMTest  {

    
public static void main(String[] args) throws Exception {

        DocumentBuilderFactory factory 
= DocumentBuilderFactory.newInstance();
        DocumentBuilder builder 
= factory.newDocumentBuilder();
        Document myDocument 
= builder.parse(new File(args[0]));
        Node root 
= myDocument.getDocumentElement();

        
// 这时我们已经有一个完整的反映出所处理XML文档的树型结构,并取得了它的根节点
        
        System.
out.println(root.getNodeName());
        
        
// 
        
    }

}



在这里,我们取得了想要的DOM模型,之后我们就可以对它进行遍历或操作了。对于org.w3c.dom.Document类型的对象,我们可以调用如下常用的方法:

getDocumentElement()
getElementsByTagName(String)
getChildNodes()
getParentNode()
getFirstChild()
getLastChild()
getPreviousSibling()

获取到org.w3c.dom.Node对象后,我们可以:

getAttributes()
getNodeName()
getNodeType()
getNodeValue()
getNamespaceURI()
hasAttributes()
hasChildNodes()

这些方法从名称就知道是干什么的了,对吧?我就不多解释了。
 [XML学习笔记][3.3]通过JAXP使用XSLT
 

最后我们来看看如何通过JAXP调用XSLT,同样很简单:

/*
 * Created on 2005-2-24
 * All rights reserved.
 *
 
*/

package sean.home.test;

import java.io.File;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

/**
 * @author Sean GAO
 * <p>
 * gaoyuxiang@gmail.com
 * </p>
 * 
 
*/

public   class  XSLTest  {

    
public static void main(String[] args) throws Exception {
        
        TransformerFactory factory 
= TransformerFactory.newInstance();
        Source xmlSource 
= new StreamSource(new File(args[0]));
        Source xlsSource 
= new StreamSource(new File(args[1]));
        Transformer transformer 
= factory.newTransformer(xlsSource);
        transformer.transform(xmlSource, 
new StreamResult(new File(args[3])));

    }

}



是不是也跟SAX、DOM的接口很像?也是通过工厂方法获取一个Transformer实例然后提供输入和输出的文件路径,用它来transform即可。
 [XML学习笔记][4]结语
 

至此我的XML学习笔记就截止了,大家也看到,这些都是十分基础的内容,然而我们平时很少去关心它。我的初衷是在做了N久的J2EE后回过头来温习一下XML的基本概念和用法,并不要求自己太深入,目的也达到了。具体的语法细节我想大家可以参考W3C和SUN官网上的资料和JavaDoc。

希望能当作XML的Java版快速入门来看,这些都是我们做Java的需要了解的最基本的XML常识,了解这些以后对一般的XML处理工作也基本上够了。

谢谢大家!祝大家天天开心,日日上进!:)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值