Friday, April 6, 2007

设计模式总结

玻璃杯中的花生壳--设计模式总结

Christopher Alexander 说过:"每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动" 。
模式描述为:在一定环境中解决某一问题的方案,包括三个基本元素--问题,解决方案和环境。
阅读类图和对象图请先学习UML
创建模式 结构模式 行为模式
创建模式:对类的实例化过程的抽象。一些系统在创建对象时,需要动态地决定怎样创建对象,创建哪些对象,以及如何组合和表示这些对象。创建模式描述了怎样构造和封装这些动态的决定。包含类的创建模式和对象的创建模式。
结构模式:描述如何将类或对象结合在一起形成更大的结构。分为类的结构模式和对象的结构模式。类的结构模式使用继承把类,接口等组合在一起,以形成更大的结构。类的结构模式是静态的。对象的结构模式描述怎样把各种不同类型的对象组合在一起,以实现新的功能的方法。对象的结构模式是动态的。
行为模式:对在不同的对象之间划分责任和算法的抽象化。不仅仅是关于类和对象的,并是关于他们之间的相互作用。类的行为模式使用继承关系在几个类之间分配行为。对象的行为模式则使用对象的聚合来分配行为。
设计模式使用排行:

频率
所属类型
模式名称
模式
简单定义
5
创建型
Singleton
单件
保证一个类只有一个实例,并提供一个访问它的全局访问点。
5
结构型
Composite
组合模式
将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。
5
结构型
FAÇADE
外观
为子系统中的一组接口提供一致的界面,facade提供了一高层接口,这个接口使得子系统更容易使用。
5
结构型
Proxy
代理
为其他对象提供一种代理以控制对这个对象的访问
5
行为型
Iterator
迭代器
提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。
5
行为型
Observer
观察者
定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。
5
行为型
Template Method
模板方法
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,Template Method使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。
4
创建型
Abstract Factory
抽象工厂
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。
4
创建型
Factory Method
工厂方法
定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。
4
结构型
Adapter
适配器
将一类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以一起工作。
4
结构型
Decorator
装饰
动态地给一个对象增加一些额外的职责,就增加的功能来说,Decorator模式相比生成子类更加灵活。
4
行为型
Command
命令
将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。
4
行为型
State
状态
允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。
4
行为型
Strategy
策略模式
定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。
3
创建型
Builder
生成器
将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。
3
结构型
Bridge
桥接
将抽象部分与它的实现部分相分离,使他们可以独立的变化。
3
行为型
China of Responsibility
职责链
使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系
2
创建型
Prototype
原型
用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。
2
结构型
Flyweight
享元
享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。
2
行为型
Mediator
中介者
用一个中介对象封装一些列的对象交互。
2
行为型
Visitor
访问者模式
表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这个元素的新操作。
1
行为型
Interpreter
解释器
给定一个语言,定义他的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
1
行为型
Memento
备忘录
在不破坏对象的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

 
一 : 单例模式(Singleton)
单例模式:Singleton的作用是保证在应用程序中,一个类Class只有一个实例存在。并提供全局访问。
结构:
账本类:1 单一实例 2 给多个对象共享 3 自己创建
网页计数器
public class LazySingleton
{
     private static LazySingleton newInstance = null;
  private LazySingleton ()
{
}
public static synchronized  LazySingleton getInstance ()
{
               if (newInstance == null)
{
                newInstance = new LazySingleton ();
          }
          return newInstance;
}
}
singleton
限制了实例个数,有利于gc的回收。
二:策略模式(Strategy)  
策略模式:策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模式把行为和环境分开。环境类负责维持和查询行为类,各种算法在具体的策略类中提供。由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。
结构:
使用QQ泡MM时使用外挂  客户端 :ME 抽象类: 外挂 具体:策略(图片,笑话,名人名言)
图书销售算法(不同书本折扣的算法)
三:原型模式(Prototype)
原型模式:通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法
结构:
复印技术: 1 不是同一个对象 2 属同类
短消息(转发) 1-n个MM
因为Java中的提供clone()方法来实现对象的克隆,所以Prototype模式实现一下子变得很简单.
四:门面模式(Façade)
门面模式:外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用,减少复杂性。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。
1 门面角色 2 子系统角色
结构:
Facade典型应用就是数据库JDBC的应用和Session的应用
ME---àMM--- à(father,mum,sister,brother)
五:备忘录模式(Memento)
Memento模式:Memento对象是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到原先保存的状态。模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。模式所涉及的角色有三个,备忘录角色、发起人角色和负责人角色。
备忘录角色的作用:
(1) 将发起人对象的内部状态存储起来,备忘录可以根据发起人对象的判断来决定存储多少发起人对象的内部状态。
(2) 备忘录可以保护其内容不被发起人对象之外的任何对象所读取。
发起人角色的作用:
(1) 创建一个含有当前内部状态的备忘录对象。
(2) 使用备忘录对象存储其内部状态。
负责人角色的作用:
(1) 负责保存备忘录对象。
(2) 不检查备忘录对象的内容
结构:
备份系统时使用
GHOST
六 : 命令模式(Command)
命令模式:命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。
结构:
 
MM(客户端)--à ME(请求者)--à 命令角色--à(具体命令)-à 代理处(接收者)--àMM
上网 IE 输入 http地址 发送命令
七: 解释器(Interpreter)
解释器模式:给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。在解释器模式中需要定义一个代表文法的命令类的等级结构,也就是一系列的组合规则。每一个命令对象都有一个解释方法,代表对命令对象的解释。命令对象的等级结构中的对象的任何排列组合都是一个语言。
结构:
编译原理之编译器
文言文注释:一段文言文,将它翻译成白话文
八:调停者模式(Mediator)
调停者模式:包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用。调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。
结构:
法院和原告,被告的关系
九:责任链模式(CHAIN OF RESPONSIBLEITY)
责任链模式:执行者的不确定性 在责任链模式中,很多对象由每一个对象对其下家的引用而接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。
结构:
典型的对象结构:
喝酒时通过成语接龙决定谁喝酒(马到成功-功不可没-没完没了)
十:工厂模式(Factory)
工厂模式:定义一个用于创建对象的接口,让接口子类通过工厂方法决定实例化哪一个类。
结构:
水果园—〉(葡萄园,苹果园)--〉(葡萄,苹果)(各自生产)
十一:抽象工厂模式(Abstract Factory)
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
结构:
女娲造人---〉(阴,阳)--〉(人,兽)----〉(男人,女人,公兽,母兽)(人和兽属于不同的产品类)
十二:建造模式(Builder)
建造模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构建它们.用户不知道内部的具体构建细节.Builder模式是非常类似抽象工厂模式,细微的区别大概只有在反复使用中才能体会到。
将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。
结构:
交互图:

 


 

汽车制造
十三:合成模式(Composite)
合成模式:将对象以树形结构组织起来,以达成"部分-整体" 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. 合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。
结构:
windows的目录树(文件系统)
十四:装饰模式(DECORATOR)
装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。
使用Decorator的理由是:这些功能需要由用户动态决定加入的方式和时机.Decorator提供了"即插即用"的方法,在运行期间决定何时增加何种功能.
结构:
在visio中文件可以使用背景进行装饰
变废为宝
十五:设计模式之Adapter(适配器)    
适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端
将两个不兼容的类纠合在一起使用,属于结构型模式,需要Adaptee(被适配者)和Adaptor(适配器)两个身份.
为何使用?
我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:修改各自类的接口,但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口。 怎么办? 使用Adapter,在这两种接口之间创建一个混合接口(混血儿).
如何使用?
实现Adapter方式,其实"think in Java"的"类再生"一节中已经提到,有两种方式:组合(composition)和继承(inheritance).
结构:
对象结构:
充电器(手机和220V电压)
jdbc-odbc桥
十六:桥梁模式(Bridge)
桥梁模式:将抽象化与实现化脱耦,使得二者可以独立的变化。也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。
结构:
jdbc驱动程序
十七:代理模式(Proxy)
代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。
结构:
运行时的代理结构:
用代理服务器连接出网
销售代理(厂商)律师代理(客户)
foxmail
枪手
十八:享元模式(Flyweight)
享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态,它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来,将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象,而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。
结构:
共享方法:
字体的26个字母和各自的斜体等
十九:状态模式(State)
状态模式:状态模式允许一个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一样。状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。
 

Gmail: keyboard shortcut

Gmail: Help Center - What are the keyboard shortcuts?

What are the keyboard shortcuts?

Keyboard shortcuts help you save time since you never have to take your hands off the keyboard to use the mouse. You'll need a Standard 101/102-Key or Natural PS/2 Keyboard to use the shortcuts.

To turn these case-sensitive shortcuts on or off, click Settings, and then pick an option next to Keyboard shortcuts.

Shortcut Key Definition Action
c Compose Allows you to compose a new message. <Shift> + c allows you to compose a message in a new window.
/ Search Puts your cursor in the search box.
k Move to newer conversation Opens or moves your cursor to a more recent conversation. You can hit <Enter> to expand a conversation.
j Move to older conversation Opens or moves your cursor to the next oldest conversation. You can hit <Enter> to expand a conversation.
n Next message Moves your cursor to the next message. You can hit <Enter> to expand or collapse a message. (Only applicable in 'Conversation View.')
p Previous message Moves your cursor to the previous message. You can hit <Enter> to expand or collapse a message. (Only applicable in 'Conversation View.')
o or <Enter> Open Opens your conversation. Also expands or collapses a message if you are in 'Conversation View.'
u Return to conversation list Refreshes your page and returns you to the inbox, or list of conversations.
y Archive*
Remove from current view
Automatically removes the message or conversation from your current view.
  • From 'Inbox,' 'y' means Archive
  • From 'Starred,' 'y' means Unstar
  • From any label, 'y' means Remove the label
* 'y' has no effect if you're in 'Spam,' 'Sent,' or 'All Mail.'
m Mute Archives the conversation, and all future messages skip the Inbox unless sent or cc'd directly to you. Learn more .
x Select conversation Automatically checks and selects a conversation so that you can archive, apply a label, or choose an action from the drop-down menu to apply to that conversation.
s Star a message or conversation Adds or removes a star to a message or conversation. Stars allow you to give a message or conversation a special status.
! Report spam Marks a message as spam and removes it from your conversation list.
r Reply Reply to the message sender. <Shift> + r allows you to reply to a message in a new window. (Only applicable in 'Conversation View.')
a Reply all Reply to all message recipients. <Shift> +a allows you to reply to all message recipients in a new window. (Only applicable in 'Conversation View.')
f Forward Forward a message. <Shift> + f allows you to forward a message in a new window. (Only applicable in 'Conversation View.')
<Esc> Escape from input field Removes the cursor from your current input field.

<Ctrl> + s

Save draft

Holding the <Ctrl> key while pressing s when composing a message will save the current text as a draft. Make sure your cursor is in one of the text fields -- either the composition pane, or any of the To, CC, BCC, or Subject fields -- when using this shortcut.

Macintosh users should use <Cmd> + s.

#

Delete

Moves the conversation to Trash.

Combo-keys - Use the following combinations of keys to navigate through Gmail.

Shortcut Key Definition Action
<tab> then <Enter> Send message After composing your message, use this combination to send it automatically. (Supported in Internet Explorer and Firefox, on Windows.)
y then o Archive and next Archive your conversation and move to the next one.
g then a Go to 'All Mail' Takes you to 'All Mail,' the storage site for all mail you've ever sent or received (and have not deleted).
g then s Go to 'Starred' Takes you to all conversations you have starred.
g then c Go to 'Contacts' Takes you to your Contacts list.
g then d Go to 'Drafts' Takes you to all drafts you have saved.
g then i Go to 'Inbox' Returns you to the inbox.

Eclipse 实用快捷键大全

玻璃杯中的花生壳--Eclipse 实用快捷键大全

Eclipse 实用快捷键大全
[ 2007-3-13 10:01:49 | By: 玻璃杯中的花生壳 ]
 
 俗话说,工欲善其事,必先利其器,如果大家对开发程序稍微有点发烧的话,都知道快捷键对编程中有多大的作用了(当然当年Dos用natepad开发程序的除外了),我就是这样一个发烧友了,对各种IDE中的快捷功能颇感兴趣,尤其是对快捷键这一部分乐此不彼了.再加上Eclipse又是本人的最爱,因此Eclipse中的快捷键就是本人重视的重点了,当然,Eclipse的快捷键暂时不是最强的,本人见过快捷键最优秀的IDE还是当属IDEA了,里面的快捷键为程序员考虑的面面俱到,几乎到了只要你想不到,没有按不到的地步了(嘻,好像给它做广告了).不过说实话很多功能都是Eclipse借鉴Idea过来的了.但至今我发现在快捷键这方面和别的智能开发方面Eclipse还是稍逊一筹了(这仅仅是从Java IDE的角度),废话少说,直接就切入正题了.

  今天写的这些快捷键都是本人在实际运用中总结出来的,自己感觉很实用,都是以自己的喜好程度来排列了,对于的Eclipse如果没有特别说明都使用有Eclipse3.0.X以上了,个别如果出现不符合的话要么是版本的问题,要么是和别的系统级的快捷键有冲突,譬如输入法的冲突了,这时就需要修改输入法了.下面的快捷键都是Eclipse特有的,尤其是针对Java Editer的,但有些对Eclipse里面的Text也是实用的了,下面就是这些快捷键了(住:这些快捷键随着自己学习不断的深入和Eclipse版本不断的提高会慢慢的完善的,有些太普通的就没有列出来,如Ctrl+A一类):

Ctrl+1 快速修复(最经典的快捷键,就不用多说了)

Ctrl+D: 删除当前行     

Ctrl+Alt+↓ 复制当前行到下一行(复制增加)

Ctrl+Alt+↑ 复制当前行到上一行(复制增加)

Alt+↓  当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)

Alt+↑   当前行和上面一行交互位置(同上)

Alt+←  前一个编辑的页面

Alt+→  下一个编辑的页面(当然是针对上面那条来说了)

Alt+Enter 显示当前选择资源(工程,or 文件 or文件)的属性

Shift+Enter 在当前行的下一行插入空行(这时鼠标可以在当前行的任一位置,不一定是最后)

Shift+Ctrl+Enter 在当前行插入空行(原理同上条)

Ctrl+Q   定位到最后编辑的地方

Ctrl+L  定位在某行  (对于程序超过100的人就有福音了)

Ctrl+M 最大化当前的Edit或View (再按则反之)

Ctrl+/   注释当前行,再按则取消注释

Ctrl+O   快速显示 OutLine

Ctrl+T   快速显示当前类的继承结构

Ctrl+W  关闭当前Editer

Ctrl+K   参照选中的Word快速定位到下一个

Ctrl+E 快速显示当前Editer的下拉列表(如果当前页面没有显示的用黑体表示)

Ctrl+/(小键盘) 折叠当前类中的所有代码

Ctrl+×(小键盘) 展开当前类中的所有代码

Ctrl+Space 代码助手完成一些代码的插入(但一般和输入法有冲突,可以修改输入法的热键,也可以暂用Alt+/来代替)

Ctrl+Shift+E 显示管理当前打开的所有的View的管理器(可以选择关闭,激活等操作)

Ctrl+J  正向增量查找(按下Ctrl+J后,你所输入的每个字母编辑器都提供快速匹配定位到某个单词,如果没有,则在stutes line中显示没有找到了,查一个单词时,特别实用,这个功能Idea两年前就有了)

Ctrl+Shift+J 反向增量查找(和上条相同,只不过是从后往前查)

Ctrl+Shift+F4 关闭所有打开的Editer

Ctrl+Shift+X   把当前选中的文本全部变味小写

Ctrl+Shift+Y   把当前选中的文本全部变为小写

Ctrl+Shift+F  格式化当前代码

Ctrl+Shift+P 定位到对于的匹配符(譬如{}) (从前面定位后面时,光标要在匹配符里面,后面到前面,则反之)

下面的快捷键是重构里面常用的,本人就自己喜欢且常用的整理一下(注:一般重构的快捷键都是Alt+Shift开头的了)

Alt+Shift+R 重命名 (是我自己最爱用的一个了,尤其是变量和类的Rename,比手工方法能节省很多劳动力)

Alt+Shift+M 抽取方法 (这是重构里面最常用的方法之一了,尤其是对一大堆泥团代码有用)

Alt+Shift+C 修改函数结构(比较实用,有N个函数调用了这个方法,修改一次搞定)

Alt+Shift+L 抽取本地变量( 可以直接把一些魔法数字和字符串抽取成一个变量,尤其是多处调用的时候)

Alt+Shift+F 把Class中的local变量变为field变量 (比较实用的功能)

Alt+Shift+I 合并变量(可能这样说有点不妥Inline)

Alt+Shift+V 移动函数和变量(不怎么常用)

Alt+Shift+Z 重构的后悔药(Undo)


 初用Eclipse

Eclipse插件使用links目录的用法:

  假设插件安装在d:\myplugin目录中,则myplugin的目录结构一定要是这样的:

  d:\myplugin\eclipse\plugins\**  和 d:\myplugin\eclipse\features\**

  例如安装EclipseME插件到d:\myplugin目录中,则目录结构为d:\myplugin\eclipse\plugins\eclipseme_0.4.5。
  再假设eclipse安装在d:\eclipse目录中,则在eclipse目录中创建名称为links的目录,在links目录中建立一个    
        link  文件,比如myplugin.link,该文件内容为path=d:\myplugin。  

  启动eclipse,可以打开Windows->Preference查看插件的安装,如果想暂时不启动插件,只需把myplugin.link文件删除即可。

    补充说明:

 1. 插件可以分别安装在多个自定义的目录中。
 2. 一个自定义目录可以安装多个插件。
 3. link文件的文件名及扩展名可以取任意名称,比如myplugin.txt,goodplugin都可以。
 4. link文件可以有多行path=插件目录,对应多个自定义插件目录,每一行的path参数都将生效。
 5. 在links目录也可以有多个link文件,每个link文件中的path参数都将生效。
 6. 插件目录可以使用相对路径,如果我们把myplugin目录创建在eclipse安装目录中,如上例中的d:\eclipse目 
    录中,则只需设置path=myplugin即可。

java编程中更新xml文档的常用方法

java编程中更新xml文档的常用方法   
文章出处:ibm dw中国 作者:黄理     发布时间:2004-12-31   点击:0
 

  本文简要的讨论了java语言编程中更新xml文档的四种常用方法,并且分析这四种方法的优劣。其次,本文还对如何控制java程序输出的xml文档的格式做了展开论述。 

  jaxp是java api for xml processing的英文字头缩写,中文含义是:用于xml文档处理的使用java语言编写的编程接口。jaxp支持dom、sax、xslt等标准。为了增强jaxp使用上的灵活性,开发者特别为jaxp设计了一个pluggability layer,在pluggability layer的支持之下,jaxp既可以和具体实现dom api、sax api 的各种xml解析器(xml parser,例如apache xerces)联合工作,又可以和具体执行xslt标准的xslt处理器(xslt processor,例如apache xalan)联合工作。应用pluggability layer的好处在于:我们只需要熟悉jaxp各个编程接口的定义即可,而不需要对所采用的具体的xml解析器、xslt处理器有很深入的了解。比如在某个java程序中,通过jaxp调用xml解析器apache crimson对xml文档进行处理,如果我们希望使用别的xml解析器(比如apache xerces),以便提高该程序的性能,那么原程序代码可能不需要任何改变,直接就可以使用(你所需要做的事情只是将包含apache xerces代码的jar文件加入到环境变量classpath中,而将包含apache crimson代码的jar文件在环境变量classpath中删除)。 

  目前jaxp已经应用的十分普遍了,可以说是java语言中处理xml文档的标准api。有些初学者在学习使用jaxp的过程中,经常会提出这样的问题:我编写的程序对dom tree做了更新,但是当程序退出以后,原始的xml文档并没有改变,还是老样子,如何实现对原始xml文档和dom tree的同步更新呢?咋一看来,在jaxp中似乎没有提供相应的接口/方法/类,这是很多初学者都感到困惑的问题。本文的主旨就在于解决这个问题,简单的介绍几种常用的同步更新原始xml文档和dom tree的方法。为了缩小讨论的范围,本文所涉及的xml解析器仅包括apache crimson和apache xerces,而xslt处理器仅仅使用apache xalan。 

  方法一:直接读写xml文档 

  这也许是最笨最原始的办法了。当程序获取dom tree之后,应用dom模型的node接口的各个方法对dom tree进行更新,下一步应该对原始的xml文档进行更新了。我们可以运用递归的办法或者是应用treewalker类,遍历整个dom tree,与此同时,将dom tree的每一个节点/元素依次写入到预先打开的原始xml文档中,当dom tree被遍历完全之后,dom tree和原始的xml文档就实现了同步更新。实际中,这个方法极少使用,不过如果你要编程实现自己的xml解析器,这种方法还是有可能用得上的。 

  方法二:使用xmldocument类 

  使用xmldocument类?jaxp中分明没有这个类呀!是不是作者搞错了?没有错!就是使用xmldocument类,确切的说,是使用xmldocument类的write()方法。 

  在上文已经提到过,jaxp可以和各种各样的xml解析器联合使用,这次我们选用的xml解析器是apache crimson。xmldocument(org.apache.crimson.tree.xmldocument)是apache crimson的一个类,并不包含于标准的jaxp中,难怪在jaxp的文档中找不到xmldocument类的芳踪呢。现在问题出来了,如何应用xmldocument类来实现更新xml文档的功能?在xmldocument类中提供了下面三个write()方法(根据crimson最新的版本------apache crimson 1.1.3): 

public void write (outputstream out) throws ioexception
public void write (writer out) throws ioexception
public void write (writer out, string encoding) throws ioexception


  上述三个write()方法的主要作用就是输出dom tree中的内容到特定的输出介质中,比如文件输出流、应用程序控制台等等。那么又如何使用上述三个write()方法呢?请看下面的java程序代码片断: 

string name="fancy";
documentbuilder parser;
documentbuilderfactory factory = documentbuilderfactory.newinstance();
try 
{
parser = factory.newdocumentbuilder();
document doc = parser.parse("user.xml");
element newlink=doc.createelement(name);
doc.getdocumentelement().appendchild(newlink);
((xmldocument)doc).write(new fileoutputstream(new file("xuser1.xml")));
}
catch (exception e) 
{
//to log it 
}


  在上面的代码中,首先创建了一个document对象doc,获取完整的dom tree,然后应用node接口的appendchild()方法,在dom tree的最后追加了一个新节点(fancy),最后调用xmldocument类的write(outputstream out)方法,把dom tree中的内容输出到xuser.xml中(其实也可以输出到user.xml,更新原始的xml文档,在这里为了便于做对比, 故而输出到xuser.xml文件中)。需要注意的是不能直接对document对象doc直接调用write()方法,因为jaxp的document接口并没有定义任何write()方法,所以必须将doc由document对象强制转换为xmldocument对象,然后才能调用write()方法,在上面的代码中使用的是write(outputstream out)方法,这个方法使用缺省的utf-8编码输出dom tree中的内容到特定的输出介质中,如果dom tree中包含中文字符,那么输出的结果有可能是乱码,亦即存在所谓的"汉字问题",解决的办法是使用write (writer out, string encoding)方法,显式指定输出时的编码,例如将第二个参数设为"gb2312",这时即不存在"汉字问题",输出结果能够正常显示中文字符。 

  完整的例子请参考下列文件: addrecord.java(见附件)、user.xml(见附件)。该例子的运行环境为:windows xp professional、jdk 1.3.1。为了能够正常编译运行addrecord.java这个程序,你需要到网址 http://xml.apache.org/dist/crimson/ 去下载apache crimson,并将所获取的crimson.jar文件加入到环境变量classpath中。 
 
  注意: 
  apache crimson的前身是sun project x parser,后来不知何故,由x parser演变为apache crimson,至今apache crimson的很多代码都是从x parser中直接移植过来的。比如上文用到的xmldocument类,它在x parser中是com.sun.xml.xmldocument,到了apache crimson中摇身一变,就变成了org.apache.crimson.tree.xmldocument类 ,其实它们的绝大部分代码是一样的,可能就package语句和import语句以及文件开头的一段lience有所不同而已。早期的jaxp是和x parser捆绑在一起的,因此一些老的程序使用了com.sun.xml包,如果你现在重新编译它们,有可能不能通过,肯定就是因为这个原因。后来的jaxp和apache crimson捆绑在一起,比如jaxp 1.1,如果你使用jaxp 1.1,那么不需要额外下载apache crimson,也能够正常编译运行上面的例子( addrecord.java)。最新的jaxp 1.2 ea(early access)改弦更张,采用性能更好的apache xalan和apache xerces分别作为xslt处理器和xml解析器,不能直接支持apache crimson了,所以如果你的开发环境采用了jaxp 1.2 ea或者是java xml pack(内含jaxp 1.2 ea),那么将无法直接编译运行上面的例子(addrecord.java),你需要额外下载并安装apache crimson。 

  方法三:使用transformerfactory和transformer类 

  在jaxp中所提供的标准的更新原始xml文档的方法就是调用xslt引擎,亦即使用transformerfactory和transformer类。请看下面的java代码片断: 

//首先创建一个domsource对象,该构造函数的参数可以是一个document对象
//doc代表更改后的dom tree。
domsource doms = new domsource (doc);

//创建一个file对象,代表dom tree所包含的数据的输出介质,这是一个xml文件。
file f = new file ("xmloutput.xml");

//创建一个streamresult对象,该构造函数的参数可以取为file对象。
streamresult sr = new streamresult (f);

//下面调用jaxp中的xslt引擎来实现输出dom tree中的数据到xml文件中的功能。
//xslt引擎的输入为domsource对象,输出为streamresut对象。
try 
{
//首先创建一个transformerfactory对象,再由此创建transformer对象。transformer
//类相当于一个xslt引擎。通常我们使用它来处理xsl文件,但是在这里我们使
//用它来输出xml文档。
transformerfactory tf=transformerfactory.newinstance(); 
transformer t=tf.newtransformer ();

//关键的一步, 调用transformer对象 (xslt引擎)的transform()方法,该方法的第一
//个参数是domsource对象,第二个参数是streamresult对象。
t.transform(doms,sr); 
}
catch (transformerconfigurationexception tce)
{ 
system.out.println("transformer configuration exception\n-----");
tce.printstacktrace(); 
}
catch (transformerexception te) 
{ 
system.out.println ("transformer exception\n---------"); 
te.printstacktrace (); 
} 


  在实际的应用中,我们可以应用传统的dom api从xml文档中获取dom tree,然后根据实际的需求对dom tree执行各种操作,得到最终的document对象,接下来可以由此document对象创建domsource对象,剩下的事情就是照搬上面的代码了,程序运行完毕后, xmloutput.xml就是你所需要的结果(当然了,你可以随意更改streamresult类构造函数的参数,指定不同的输出介质,而不必是千篇一律的xml文档)。 

  这个方法最大的好处在于可以随心所欲的控制dom tree中的内容输出到输出介质中的格式,但是光靠transformerfactory类和transformer类并不能实现这个功能,还需要依赖outputkeys类的帮助。 完整的例子请参考下列文件: addrecord2.java(见附件)、user.xml(见附件)。该例子的运行环境为:windows xp professional、jdk 1.3.1。为了能够正常编译运行addrecord2.java这个程序,你需要到网址http://java.sun.com去下载安装jaxp 1.1或者java xml pack(java xml pack已经内含jaxp了)。 

  outputkeys类 
  javax.xml.transform.outputkeys类和java.util.properties类配合使用,可以控制jaxp的xslt引擎(transformer类)输出xml文档的格式。请看下面的代码片断: 

//首先创建一个transformerfactory对象,再由此创建transformer对象。
transformerfactory tf=transformerfactory.newinstance(); 
transformer t=tf.newtransformer ();

//获取transformser对象的输出属性,亦即xslt引擎的缺省输出属性,这是一个
//java.util.properties对象。
properties properties = t.getoutputproperties(); 

//设置新的输出属性:输出字符编码为gb2312,这样可以支持中文字符,xslt引擎所输出
//的xml文档如果包含了中文字符,可以正常显示,不会出现所谓的"汉字问题"。
//请留意outputkeys类的字符串常数outputkeys.encoding。
properties.setproperty(outputkeys.encoding,"gb2312"); 

/更新xslt引擎的输出属性。
t.setoutputproperties(properties); 

//调用xslt引擎,按照输出属性中的设置,输出dom tree中的内容到输出介质中。
t.transform(domsource_object,streamresult_object); 


  从上面的程序代码,我们不难看出,通过设置xslt引擎(transformer类)的输出属性,可以控制dom tree中的内容的输出格式,这对于我们定制输出内容是很有帮助的。那么jaxp的xslt引擎(transformer类)有那些输出属性可以设置呢? javax.xml.transform.outputkeys类定义了很多字符串常数,它们都是可以自由设置的输出属性,常用的输出属性如下所示:  

public static final java.lang.string method 


  可以设为"xml"、"html"、"text"等值。 

public static final java.lang.string version 


  所遵循规范的版本号,如果method设为"xml",那么它的值应该设为"1.0",如果method设为"html",那么它的值应该设为"4.0",如果method设为"text",那么这个输出属性会被忽略。 

public static final java.lang.string encoding 


  设置输出时所采用的编码方式,比如"gb2312"、"utf-8"等等,如果将其设置为"gb2312",可以解决所谓的"汉字问题"。 
  public static final java.lang.string omit_xml_declaration 

  设置输出到xml文档中时是否忽略xml声明,亦即类似于: 

<?xml version="1.0" standalone="yes" encoding="utf-8" ?> 


  这样的代码。它可选的值有"yes"、"no"。 

public static final java.lang.string indent 


  ident设定xslt引擎在输出xml文档时,是否自动添加额外的空格,它可选的值为"yes"、"no"。 

public static final java.lang.string media_type 


  media_type设定输出文档的mime类型。 

  如果设定xslt引擎的输出属性呢?下面我们来总结一下: 

  首先是获取xslt引擎(transformer类)的缺省输出属性的集合,这需要使用transformer类的getoutputproperties()方法,返回值是一个java.util.properties对象。 

properties properties = transformer.getoutputproperties(); 


  然后是设定新的输出属性,比如: 

properties.setproperty(outputkeys.encoding,"gb2312");
properties.setproperty(outputkeys.method,"html");
properties.setproperty(outputkeys.version,"4.0");

……………………………………………………… 


  最后是更新xslt引擎(transformer类)的缺省输出属性的集合,这需要使用transformer类的setoutputproperties()方法,参数是一个java.util.properties对象。 

  我们编写了一个新的程序,其中应用了outputkeys类,用以控制xslt引擎的输出属性,该程序的架构和前一个程序(addrecord3.java)大致相同,不过输出结果略有不同。完整的代码请参考下列文件: addrecord3.java(见附件)、user.xml(见附件)。该例子的运行环境为:windows xp professional、jdk 1.3.1。为了能够正常编译运行addrecord3.java这个程序 ,你需要到网址http://java.sun.com去下载安装jaxp 1.1或者java xml pack(java xml pack内含jaxp了)。 

  方法四:使用xalan xml serializer 

  方法四其实是方法三的一个变种,它需要apache xalan和apache xerces的支持才能够运行。例子代码如下所示: 

//首先创建一个domsource对象,该构造函数的参数可以是一个document对象
//doc代表更改后的dom tree。
domsource domsource = new domsource (doc); 

//创建一个domresult对象,临时保存xslt引擎的输出结果。
domresult domresult = new domresult();

//下面调用jaxp中的xslt引擎来实现输出dom tree中的数据到xml文件中的功能。
//xslt引擎的输入为domsource对象,输出为domresut对象。
try 
{
//首先创建一个transformerfactory对象,再由此创建transformer对象。transformer
//类相当于一个xslt引擎。通常我们使用它来处理xsl文件,但是在这里我们使
//用它来输出xml文档。
transformerfactory tf=transformerfactory.newinstance(); 
transformer t=tf.newtransformer (); 

//设置xslt引擎的属性(必不可少,否则会产生"汉字问题")。
properties properties = t.getoutputproperties(); 
properties.setproperty(outputkeys.encoding,"gb2312");
t.setoutputproperties(properties); 

//关键的一步, 调用transformer对象 (xslt引擎)的transform()方法,该方法的第一
//个参数是domsource对象,第二个参数是domresult对象。
t.transform(domsource,domresult);

//创建缺省的xalan xml serializer,使用它将临时存放在domresult对象
//(domresult)中的内容以输出流的形式输出到输出介质中。
serializer serializer = serializerfactory.getserializer
(outputproperties.getdefaultmethodproperties("xml"));

//设置xalan xml serializer的输出属性,这一步必不可少,否则也可能产生
//所谓的"汉字问题"。
properties prop=serializer.getoutputformat();
prop.setproperty("encoding","gb2312");
serializer.setoutputformat(prop);

//创建一个file对象,代表dom tree所包含的数据的输出介质,这是一个xml文件。
file f = new file ("xuser3.xml");

//创建文件输出流对象fos,请留意构造函数的参数。
fileoutputstream fos=new fileoutputstream(f);

//设置xalan xml serializer的输出流。
serializer.setoutputstream(fos);

//串行化输出结果。
serializer.asdomserializer().serialize(domresult.getnode());
}
catch (exception tce)
{ 
tce.printstacktrace(); 
}


  这个方法不太常用,而且似乎有点画蛇添足,所以我们就不展开讨论了。完整的例子请参考下列文件: addrecord4.java(见附件)、user.xml(见附件)。该例子的运行环境为:windows xp professional、jdk 1.3.1。为了能够正常编译运行addrecord4.java这个程序,你需要到网址 http://xml.apache.org/dist/去下载安装apache xalan和apache xerces。 

  或者是到网址http://java.sun.com/xml/download.html去下载安装java xml pack。因为最新的java xml pack(winter 01 版)包含了apache xalan和apache xerces技术在内。 

  结论: 
  本文简略的讨论了java语言编程中更新xml文档的四种方法。第一种方法是直接读写xml文件,这种方法十分繁琐,而且比较容易出错,极少使用,除非你需要开发自己的xml parser,否则不会使用这种方法。第二种方法是使用apache crimson的xmldocument类,这种方法极为简单,使用方便,如果你选用apache crimson作为xml解析器,那么不妨使用这种方法,不过这种方法似乎效率不高(源于效率低下的apache crimson),另外,高版本的jaxp或者是java xml pack、jwsdp不直接支持apache crimson,亦即这种方法不通用。第三种方法是使用jaxp的xslt引擎(transformer类)来输出xml文档,这种方法也许是标准的方法了,使用起来十分灵活,特别是可以自如控制输出格式,我们推荐采用这种方法。第四种方法是第三种方法的变种,采用了xalan xml serializer,引入了串行化操作,对于大量文档的修改/输出有优越性,可惜的是要重复设置xslt引擎的属性和xml serializer的输出属性,比较麻烦,而且依赖于apache xalan和apache xerces技术,通用性略显不足。 

  除了上面讨论的四种方法以外,实际上应用别的api(比如jdom、castor、xml4j、oracle xml parser v2)也有很多办法可以更新xml文档,限于篇幅,在这里就不一一讨论了。

xml schema帮你建模(4)

xml schema帮你建模(4)   
文章出处:开放系统世界―赛迪网 作者   发布时间:2004-12-31   点击:0
 

    列表类型
  除了使用简单类型中描述的原子类型(这些原子类型可用于组合成绝大多数的其它类型,包括其它的简单类型和复合类型)外,xml schema中在简单类型范畴中还有列表类型(list type)的概念。原子类型、列表类型以及联合类型,总称为简单类型。一个原子类型的值在xml schema中是不可分割的。举例来说,nmtoken值us是不可分割的,us的任何部分,如字母s本身都是没有意义的。与之相比较,列表类型则是由一组原子类型组成,因此它的每一个部分(原子)本身都是有意义的。举例来说nmtokens是个列表类型。这个类型的元素将是nmtoken的列表,不同的nmtoken值间使用空格分隔,如"us uk fr"。xml schema有三个内置的列表类型,它们是nmtokens、idrefs和entities。 

  除了使用内置的列表类型之外,还可以通过引用现有的原子类型建立新的列表类型(不可以使用现有的列表类型来建立新的列表类型,也不能使用复合类型来建立新的列表类型)。举例来说,我们可以建立一个名为myinteger的列表类型,并在实例文档中使用它(参见代码10)。其中代码10中的后半部分即为实例文档中与列表类型listofmyinttype相一致的实例元素。 

<!--代码 0-10 myinteger列表类型的模式定义以及实例应用-->
<!-- schema fragment -->
<xsd:simpletype name="listofmyinttype">
<xsd:list itemtype="myinteger"/>
</xsd:simpletype>
<!-- instance fragment -->
<listofmyint>20003 15037 95977 95945</listofmyint>



  一些用于描述的参数能够被应用到列表类型的定义中,它们是length、minlength、maxlength和enumeration。举例来说,如果我们想定义一个列表,这个列表正好包含了六个美国的州名(sixusstates)。首先从usstate定义一个新的列表类型,称为usstatelist,然后通过限制usstatelist只有六个项来导出sixusstates。具体的定义可参见代码11。 

<!--代码11 列表类型usstatelist及其导出的列表类型sixusstates-->
<!-- schema fragment -->
<xsd:simpletype name="usstatelist">
<xsd:list itemtype="usstate"/>
</xsd:simpletype>
<xsd:simpletype name="sixusstates">
<xsd:restriction base="usstatelist">
<xsd:length value="6"/>
</xsd:restriction>
</xsd:simpletype>
<!-- instance fragment -->
<sixstates>pa ny ca ny la ak</sixstates>



  类型为sixusstates的元素必须有六个项,它们中的每一个项必须是一个枚举类型usstate的原子类型,在代码11后半部分的实例文档中就是一个具体的应用例子。 

  我们需要注意的是,从原子类型string可以导出一个列表类型,然而,在一个string中也许会带有空格,而空格在一个列表类型实例中是作为分隔符使用的。所以当在使用基类型为string的列表类型时,应当格外小心。举例来说,假设我们定义了一个length取值为3的列表类型,同时这个列表类型是基于类型string。下面由三个元素组成的列表是合法的:"asie europe afrique";而由三个元素这样组成的列表是不合法的:"asie europe amérique latine"。即使"amérique latine"在列表外可以作为单独的一个字符串存在,但当它包含在列表中,在amérique和latine之间的空格使得第四个项被有效地生成了,因此后面的那个例子不符合只有三个项的列表类型定义。 


  联合类型
  应用原子类型和列表类型,一个元素或者属性的值可以为一个或者多个原子类型(列表类型)的实例。与之相比较,一个应用联合类型(union type)包含了多个原子类型或者列表类型,而应用了联合类型的元素或是属性的值可以是这些原子类型或列表类型中的一个类型实例。为了显示这一点,我们建立一个用于表示美国州的、为两个字母缩写或者数字列表的联合类型。zipunion联合类型由一个原子类型和一个列表类型构成的(参见代码12)。 

<!--代码 12 联合类型zipunion及其实例-->
<!-- schema fragment -->
<xsd:simpletype name="zipunion">
<xsd:union membertypes="usstate listofmyinttype"/>
</xsd:simpletype>
<!-- instance fragment -->
<zips>ca</zips>
<zips>95630 95977 95945</zips>
<zips>ak</zips>



  当我们在定义一个联合类型时,元素union的membertypes属性的值包含了联合类型中所有类型的列表。现在,假定我们声明了一个zipunion类型的元素,称为zips,zips元素有效的实例可参见代码12。 

  此外,对于联合类型而言,还有两个描述性质的参数pattern和enumeration也可以应需要使用。

xml schema帮你建模(3)

xml schema帮你建模(3)   
文章出处:开放系统世界―赛迪网 作者:柴晓路      发布时间:2004-12-31   点击:0
 

    命名冲突
  我们现在已经讨论了如何定义新的复合类型(比如purchaseordertype)、声明元素(比如purchaseorder)和声明属性(如orderdate)。在这些定义行为中,一般都包含着命名,如果我们给两个对象赋予同样的名称会有何种结果? 答案取决于问题中的两个对象,一般来说这两个对象越相近,它们越有可能引起冲突。 

  下面,我们给出一些例子来说明什么时候同样的名称会导致问题。如果两个对象都是类型,而且定义了一个复合类型为usstates,同时又定义了一个简单类型为usstates,此时就出现了冲突。如果两个对象是类型和元素或者是类型和属性,当定义了一个复合类型叫usaddress时,同时又定义了一个元素称为usaddress,此时是没有冲突发生的。如果两个对象是不同类型的元素(一般地、并非是全局元素),当我们声明了一个元素名字作为usaddress类型的一部分,并且第二个元素名字作为item类型的一部分,此时就没有冲突(类似的元素有时候称为局部元素声明)。最后,如果两个对象都是类型,你自己定义了其中的一个,而xml schema规范内置定义了另外的一个,比如定义了一个简单类型称为decimal,那么此时没有冲突发生。这里之所以没有命名冲突发生的,因为它们属于不同的命名空间。 


  使用简单类型
  在购买订单模式文档po.xsd中,有几个元素和属性被声明为简单类型。其中一些简单类型如 string 和decimal是xml schema中内置的,其它的一些则是源于(如果使用对象技术的语言就是继承)内置的类型。举例来说,partnum属性的类型称为sku(stock keeping unit),它是源于string的。内置的简单类型和它们的后继版本都能够用在所有的元素和属性声明中。 

  新的简单类型通过从现有的简单类型(内置的简单类型以及源于内置简单类型的简单类型)引出定义。通常,我们通过重新约束一个现存的简单类型来引出一个新的简单类型。换句话说,新类型的合法值范围是现有类型的值范围的子集。我们使用simpletype元素来定义和命名新的简单类型,使用restriction元素来指出现有的基类型,并且用它来标识约束值范围的细节。 

  假设希望建立一个新的整数类型称为myinteger,它的值范围为10000到99999。那么定义应当基于简单类型integer,然后定义它的值范围为10000到99999。为了定义myinteger,这样来约束integer的范围,参见代码6: 

<!--代码 6 使用基类型来定义新的简单类型-->
<xsd:simpletype name="myinteger">
<xsd:restriction base="xsd:integer">
<xsd:mininclusive value="10000"/>
<xsd:maxinclusive value="99999"/>
</xsd:restriction>
</xsd:simpletype>

  代码6的例子显示了由一个基本类型定义和两个值域区间方面描述的组合,通过这三个要素对myinteger实施定义。 

  先前的购买订单模式文档包含了其它更详细的定义简单类型的例子。一个叫sku的新简单类型(参见代码7)是从(通过约束)简单类型string引出的。此外,我们使用一个称为pattern的描述,以及pattern的正则表达式值"\d{3}-[a-z]{2}"来约束sku的值。其中,该正则表达式值的语义为3个数字后面跟着一个连字号,接着跟着两个大写的英文字母。 

<!--代码7 sku简单类型定义-->
<xsd:simpletype name="sku">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{3}-[a-z]{2}"/>
</xsd:restriction>
</xsd:simpletype>


   xml schema定义了15个用于简单类型定义描述的元素。在这些元素中,enumeration特别有用,它能够被用于约束除boolean类型之外的几乎每一个简单类型。enumeration限制简单类型的值为一系列不同的枚举值。举例来说,我们可以使用enumeration来定义一个新类型称为usstate(参见代码8),usstate是从string类型引出的,同时它的值必须为美国州名的缩写。 

<!--代码8 usstate简单类型定义-->
<xsd:simpletype name="usstate">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="ak"/>
<xsd:enumeration value="al"/>
<xsd:enumeration value="ar"/>
<!-- and so on ... -->
</xsd:restriction>
</xsd:simpletype>


  usstate将会在现用的state元素声明中成为string类型的一个非常好的替换品。通过使用这个替换品可以使state元素具有合法值的校验能力。举例来说,billto和shipto元素的子元素state,将会被限制在ak、al和ar等中。注意对于特定类型的列举值必须是惟一的。 


  匿名类型定义
  使用xml schema,我们能够通过定义一系列具有名称的类型,如purchaseordertype类型。然后声明一个元素,比如purchaseorder,通过使用"type="这样的构造方法来应用类型。这种类型的模式构造非常直截了当,但有些不实用。特别是如果定义了许多只应用一次而且包含非常少约束的类型,在这种情况下,一个类型应该能够被更简单的定义。这样的简单定义通常的形式是一个节省了名称和外部引用开销的匿名类型。 

  在po.xsd(参见代码9)中类型items的定义中,有两个元素声明使用了匿名类型定义,它们是item和quantity。一般的来说,你通过元素中是否包含"type="这个属性可以判断匿名元素定义(或者是匿名属性定义)。如果出现无名称的类型定义,也可以认为是匿名元素(属性)定义。 

<!--代码 0-9 po.xsd模式定义-->
<xsd:complextype name="items">
<xsd:sequence>
<xsd:element name="item" minoccurs="0" maxoccurs="unbounded">
<xsd:complextype>
<xsd:sequence>
<xsd:element name="productname" type="xsd:string"/>
<xsd:element name="quantity">
<xsd:simpletype>
<xsd:restriction base="xsd:positiveinteger">
<xsd:maxexclusive value="100"/>
</xsd:restriction>
</xsd:simpletype>
</xsd:element>
<xsd:element name="usprice" type="xsd:decimal"/>
<xsd:element ref="comment" minoccurs="0"/>
<xsd:element name="shipdate" type="xsd:date" minoccurs="0"/>
</xsd:sequence>
<xsd:attribute name="partnum" type="sku" use="required"/>
</xsd:complextype>
</xsd:element>
</xsd:sequence>
</xsd:complextype>


  在item元素中,它被定义为一个复合匿名类型。该复杂类型是由productname、quantity、usprice、comment、shipdate元素和一个称为partnum的属性组成的。在quantity元素中,它有一个简单匿名类型从integer类型中引出,它的值范围为1到99。 

xml schema帮你建模(2)

xml schema帮你建模(2)   
文章出处:开放系统世界―赛迪网 作者:柴晓路      发布时间:2004-12-31   点击:0
 

   复合类型定义、元素和属性声明
  在xml schema中,对于那些允许元素有自己的内容,以及可以携带自身属性的复合类型与那些不能够有元素内容和属性的简单类型,它们的表示形式有着本质的不同。在实例文档中,对于能建立新的类型(无论简单和复杂)的定义和允许元素和属性有特定的名字和类型(无论是简单还是复杂)的声明,它们之间也有着显著的差别。在这一节中,将针对如何定义复合类型,以及如何声明使用复合类型的元素及其属性做较详细的描述。 

  在一个模式文档中,当需要定义新的复合类型的时候,应当使用complextype元素来定义,这样的典型定义包括元素声明、元素引用和属性声明。这些元素声明与其说是它们自身的类型,不如说是一由相关模式控制的元素名与控制这些元素名在实例文档中的表现形式的型约束之间的关联。元素是通过使用element元素来声明的,属性则是通过使用attribute元素来声明的。举例来说,usaddress被定义为一个复合类型,所以在usaddress类型定义中看到它包含了五个元素的声明和一个属性的声明(参见代码3)。 

<!--代码3 复合类型定义示例: usaddress-->
<xsd:complextype name="usaddress" >
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="street" type="xsd:string"/>
<xsd:element name="city" type="xsd:string"/>
<xsd:element name="state" type="xsd:string"/>
<xsd:element name="zip" type="xsd:decimal"/>
</xsd:sequence>
<xsd:attribute name="country" type="xsd:nmtoken" fixed="us"/>
</xsd:complextype>


  这个定义的含义是,在实例文档中出现任何类型声明为usaddress的元素(比如在po.xml中的shiptto)必须包含五个元素和一个属性,而且这些元素必须被命名为name、street、city、state和zip,这些名称应该与在模式定义中element元素的name属性的值相一致。并且这些元素必须按照模式声明中的相同顺序出现,前四个元素必须包含一个字符串元素内容,第五个必须包含一个十进制数字类型的元素内容。声明为usaddress类型的元素可以带有一个country属性,该属性必须包含字符串"us"。 

  usaddress类型定义仅仅包含了引用简单类型的元素声明,这些简单类型包括string、decimal 和nmtoken。与之对比,purchaseordertype类型定义(参阅代码4)则包含了引用复合类型的元素声明,如usaddress。这两个类型声明都使用同样的type属性来标识类型,而无需去区分类型是简单的还是复合的。 

<!--代码4 复合类型定义示例: purchase ordertype-->
<xsd:complextype name="purchaseordertype">
<xsd:sequence>
<xsd:element name="shipto" type="usaddress"/>
<xsd:element name="billto" type="usaddress"/>
<xsd:element ref="comment" minoccurs="0"/>
<xsd:element name="items" type="items"/>
</xsd:sequence>
<xsd:attribute name="orderdate" type="xsd:date"/>
</xsd:complextype>


  在purchaseordertype的类型定义中,对于shipto 和 billto这两个子元素的声明将不同的元素名与相同的复合类型相关联,这个复合类型是usaddress。这个定义的结果是,如果在实例文档中出现的任何元素(如po.xml中),当元素类型被声明为purchaseordertype时,那么这个元素必须包含两个名为shipto 和billto的元素,这两个元素都要包含五个子元素(name、street、city、state和zip),这五个子元素是作为usaddress声明的一部分出现的。根据usaddress的相关类型定义,shipto和billto元素也可以包含country属性。 

  purchaseordertype类型定义包含了一个orderdate属性声明,就像在usaddress中的country属性声明一样,它被标识为一个简单类型。实际上,所有的属性声明必须引用简单类型。这是因为属性与元素声明不同,是不能包含其它元素或者属性的。 

  迄今为止,我们描述的元素声明对每一个元素名都使用了一个现存的类型定义。然而有时候,使用一个现存的元素比应用一个类型来定义一个新的元素更为方便(参阅代码 5)。 

<!--代码 5 使用现存的元素引用来定义元素-->
<xsd:element ref="comment" minoccurs="0"/>



  代码5这个元素声明定义引用了一个现存的元素comment,该元素在购买订单模式文档中的其它部分被定义。一般来说,ref属性的值必须指向一个全局元素。也就是说应当是在元素下面被声明的,而不是作为复合类型定义的一部分声明的。代码5声明的含义是,一个叫comment的元素可以出现在实例文档关于这个定义的相关部分中,它的内容必须和那个被引用的元素的类型一致,在这个情况下是"string"。 


 
 全局元素和属性
  全局的元素和全局的属性是在全局声明时建立的,全局声明都是作为元素的直接子元素出现的。一旦经过定义,全局元素或者全局属性就可以像先前描述的那样,在一个或多个元素/属性声明中使用ref属性引用。一个引用全局元素的声明,在实例文档中允许被引用的元素出现在与声明相关的元素中。所以举例来说,po.xml中的comment元素同样可以在shipto、billto和items元素中出现,因为引用comment的复合类型定义的声明同样出现在这三个元素的声明中。 

  一个全局元素的声明也允许元素在实例文档中以顶级的文档元素出现,因此purchaseorder元素,在po.xsd中是作为一个全局元素声明的,能够作为po.xml.中的顶级元素出现。值得注意的是,基于这个基本原理comment元素作为顶级元素出现在文档如po.xml中也是被允许的。 

  关于使用全局的元素和属性有很多限制,其中一个限制是全局的声明不能够包含引用。全局的声明定义不能包含ref 属性,它们必须使用type 属性(或者像例子中使用过的跟随了一个匿名的类型定义)。第二个限制是约束不能够放在全局声明中,尽管它们能够放在引用全局声明的局部声明中。换句话说,全局声明不能够包含minoccurs、maxoccurs或者use属性。关于约束的使用,将在下一节中给出。 


  出现次数约束
  我们看到,在代码5中的元素声明中minoccurs属性的值为0 ,所以comment元素在purchaseordertype类型中是一个可选项。一般来说,当某个元素的minoccurs的值为1或者更多的时候,该元素就必须出现。一个元素可以出现的最大数量由声明中的maxoccurs属性所决定。这个值也许是一个正的整数如1,也可能是一个很大的整数100,或者以"unbounded"的形式来表明不限最大的出现数量。minoccurs和maxoccurs属性的默认值都是1。因此,当一个元素如comment,它没有定义maxoccurs属性,那么此时该元素不可以出现超过一次。如果仅仅指定了minoccurs属性值的话,那么它必须小于等于maxoccurs的默认值,也就是说minoccurs如果单独出现,其取值只能为0或者1,这是因为minoccurs的有效值必须小于等于maxoccurs的有效值。同理,如果只指定了maxoccurs属性,它就必须大于等于minoccurs的默认值,也就是必须取值为1或者更多。如果两个属性都被省略了,那么元素必须出现且仅出现一次。 

  对于属性而言,它可以有两种选择:出现一次或者根本不出现,不会有其它的出现次数。所以指定属性出现次数的语法与元素的语法有所不同。特别需要注意的,属性声明能够使用一个use属性来指明属性是否需要出现(可参见代码2,po.xsd中partnum属性的声明)。 

  属性和元素的默认值都是使用default属性来声明的,不过这个属性在不同的情况下有不同的语义。当一个属性使用默认值来声明的时候,如果属性在实例文档中出现了,那么属性的值就是属性在实例文档中出现的那个值,也就是实例文档中的值是最终有效值。如果属性没有在实例文档中出现,模式处理器将认为这个属性的值等于声明中default属性的值。需要注意的是,属性默认值只在属性本身为"可选的"时候才有意义。如果在声明中,既指定了默认值,同时又设置了use属性为除"optional"以外其它值的话(也就是必须出现),处理器就会产生错误。也就是说,属性的默认值只有当属性不在实例文档中出现的时候才会生效。 

  当一个元素声明中有默认值定义的时候,模式处理器在处理默认元素值的时候,与处理属性的默认值相比则有一些不同。如果实例文档中元素出现且带有自身内容的时候,元素的值就是实例文档中元素的内容。如果元素没有内容,那么模式处理器就认为这个元素的值(内容)等于声明中default属性的值。如果元素在实例文档中并不出现,则模式处理器根本不认为该元素出现。 

  总而言之,元素和属性默认值之间的区别可以认为是当属性不出现时默认的属性值被应用;当元素内容为空的时候,默认的元素值被应用;而元素不出现的时候,默认的元素值不被应用。 

  属性和元素声明中,都使用了fixed属性来确保属性和元素被设置为特殊的值。如po.xsd中包含了一个country属性的声明,该属性声明就有一个fixed属性,值为us。这个声明意味着在实例文档中country属性的出现是可选的(use属性的默认值是optional),但是如果属性出现它的值必须为"us";如果属性不出现,模式处理器将自动设置country属性值为"us"。需要注意的是,fixed值的概念和default值的概念是互斥的,如果同时声明fixed和default属性就会令模式处理器产生一个错误。 

  值得注意的是,在全局的元素和属性声明中,minoccurs、maxoccurs、use都没有出现,也不能出现。

xml schema帮你建模(1)

xml schema帮你建模(1)   
文章出处:开放系统世界―赛迪网 作者:柴晓路      发布时间:2004-12-31   点击:0
 

   xml schema是2001年5月正式发布的w3c(万维网联盟)的推荐标准,经过数年的大规模讨论和开发如今终于奠定下来,成为全球公认的xml环境下首选的数据建模工具。 

   由于xml是sgml(标准通用标示语言)的一个子集,它也继承了sgml用于建模的dtd。使用dtd的好处是可以利用大量现有的dtd工具,使得开发应用代价维持在一个相对较低的水平。然而,dtd有不少缺陷: 

   1. dtd是基于正则表达式的,描述能力有限; 
   2. dtd没有数据类型的支持,在大多数应用环境下能力不足; 

   3. dtd的约束定义能力不足,无法对xml实例文档做出更细致的语义限制; 

   4. dtd不够结构化,重用的代价相对较高; 
   5. dtd并非使用xml作为描述手段,而dtd的构建和访问并没有标准的编程接口,无法使用标准的编程方式进行dtd维护。 

   xml schema正是针对这些dtd的缺点而设计的,它完全使用xml作为描述手段,具有很强的描述能力、扩展能力和处理维护能力。 


  xml schema简介

  xml schema的主要目的是用来定义一类xml文档(一个xml application)。因此,模式的"实例文档"形式常常被用于描述一个与特定xml schema相一致的xml文档。事实上,文档实例和schema文档都不是必须要以文档的形式存在,它们可以以在应用之间传递的字节流的形式存在,或者作为一个数据库记录及xml的"信息项"的集合存在。然而为了简化入门,我们总是把实例和模式看作文档或者文件,认为它们总以文档实例或是模式文档的形式存在。 

  这里我们将结合一个实例来对xml schema进行简单的概述,希望大家通过阅读本节的内容初步掌握的使用方法和xml schema文档实例的具体语义。xml schema是web services技术中需要使用的一个基本工具,然而并不是xml schema的所有特性都会被广泛地使用,因此,本文将不对xml schema规范做系统的介绍。 

  在介绍xml schema语法之前,先来考虑一个xml实例文档po.xml。它描述了一个由家庭产品采购/支付应用生成的家庭产品购买订单(参阅代码1)。 

<!--代码 1 po.xml,购买订单的xml实例文档-->
<?xml version="1.0"?>
<purchaseorder orderdate="1999-10-20">
<shipto country="us">
<name>alice smith</name>
<street>123 maple street</street>
<city>mill valley</city>
<state>ca</state>
<zip>90952</zip>
</shipto>
<billto country="us">
<name>robert smith</name>
<street>8 oak avenue</street>
<city>old town</city>
<state>pa</state>
<zip>95819</zip>
</billto>
<comment>hurry, my lawn is going wild!</comment>
<items>
<item partnum="872-aa">
<productname>lawnmower</productname>
<quantity>1</quantity>
<usprice>148.95</usprice>
<comment>confirm this is electric</comment>
</item>
<item partnum="926-aa">
<productname>baby monitor</productname>
<quantity>1</quantity>
<usprice>39.98</usprice>
<shipdate>1999-05-21</shipdate>
</item>
</items>
</purchaseorder>


  这个购买订单由一个跟元素purchaseorder及其子元素shipto、billto、comment和items组成。这些子元素(除了comment)也依次包含了其它的一些子元素。 

  叶子元素包含的是一个数字而不是任何子元素,如usprice这样的子元素。元素如果包含子元素或者是带有属性的,被称为复合类型;反之元素如果仅仅包含数字、字符串或者其它数据等,但不包含任何子元素的,则被称为简单类型。在这个实例文档中,复合类型和一些简单类型是在购买定单的模式文档中定义的,而其它一些标准的简单类型则是作为xml schema内置的简单类型的形式出现的。 

  在研究这个实例文档的购买订单模式文档之前,先介绍一下购买订单实例文档和模式文档之间的联系。一个实例文档实际上并不一定需要引用模式文档,当然,在事实上的使用中,很多实例文档确实引用了模式文档,为了使入门变得更加简单,一开始我们选择不引用。同时假设任何实例文档的处理器即使从购买订单实例文档中得不到任何信息,也能够正确地进行购买订单模式文档的处理。 


  购买订单模式文档
  在代码2,给出了购买订单的模式文档。文件po.xsd在给出解释之前,大家可以使用xml的知识去尝试理解这个模式文档。 

<!--代码 2 po.xsd,购买订单的schema文档-->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/xmlschema">
<xsd:annotation>
<xsd:documentation xml:lang="en">
purchase order schema for example.com.
copyright 2000 example.com. all rights reserved.
</xsd:documentation>
</xsd:annotation>
<xsd:element name="purchaseorder" type="purchaseordertype"/>
<xsd:element name="comment" type="xsd:string"/>
<xsd:complextype name="purchaseordertype">
<xsd:sequence>
<xsd:element name="shipto" type="usaddress"/>
<xsd:element name="billto" type="usaddress"/>
<xsd:element ref="comment" minoccurs="0"/>
<xsd:element name="items" type="items"/>
</xsd:sequence>
<xsd:attribute name="orderdate" type="xsd:date"/>
</xsd:complextype>
<xsd:complextype name="usaddress">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="street" type="xsd:string"/>
<xsd:element name="city" type="xsd:string"/>
<xsd:element name="state" type="xsd:string"/>
<xsd:element name="zip" type="xsd:decimal"/>
</xsd:sequence>
<xsd:attribute name="country" type="xsd:nmtoken"
fixed="us"/>
</xsd:complextype>
<xsd:complextype name="items">
<xsd:sequence>
<xsd:element name="item" minoccurs="0" maxoccurs="unbounded">
<xsd:complextype>
<xsd:sequence>
<xsd:element name="productname" type="xsd:string"/>
<xsd:element name="quantity">
<xsd:simpletype>
<xsd:restriction base="xsd:positiveinteger">
<xsd:maxexclusive value="100"/>
</xsd:restriction>
</xsd:simpletype>
</xsd:element>
<xsd:element name="usprice" type="xsd:decimal"/>
<xsd:element ref="comment" minoccurs="0"/>
<xsd:element name="shipdate" type="xsd:date" minoccurs="0"/>
</xsd:sequence>
<xsd:attribute name="partnum" type="sku" use="required"/>
</xsd:complextype>
</xsd:element>
</xsd:sequence>
</xsd:complextype>
<!-- stock keeping unit, a code for identifying products -->
<xsd:simpletype name="sku">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{3}-[a-z]{2}"/>
</xsd:restriction>
</xsd:simpletype>
</xsd:schema>


  购买订单模式文档由一个schema元素和一系列子元素组成,大多数子元素为element、complextype和simpletype,这些决定了实例文档中元素的表现方式和内容,大家最好能熟记element、complextype、simpletype这几个元素,这些将是我们一直需要使用的几个元素。 

  同时,可以通过使用出现在schema元素中的命名空间声明xmlns:xsd="http://www.w3.org/2001/xmlschema ",使得模式文档中的每一个元素都有一个与xml schema命名空间相联系的命名空间前缀"xsd:"。尽管在语法上,可以使用任意的前缀形式,但是,命名空间前缀"xsd:"被约定用于表示xml schema命名空间。由于使用同样的前缀,所以同样的关联就会出现在内置的简单类型的名字中,例如xsd:string。这种形式关联的目的是用来表示当前的元素或简单类型是属于xml schema语言的内置定义的,而不是属于模式文档作者自己的词汇表的。为了在这里清楚并且简单地表示,我们仅提及元素的名字和简单类型名,而忽略它们的前缀"xsd:"。