2007年4月25日星期三

如何让我的M-Audio MobilePre在Ubuntu下正常使用

安装Ubuntu6.10的时候,Device Manager似乎都识别出了我的两个声卡。。
一个是我的KT600主板上自带的Realtec AC97兼容声卡,好像Chip是ALCxxxx。。
另一个就是我作音乐用的,支持ASIO的M-Audio MobilePre USB声卡。。。。

可是Ubuntu用了一种Alsa驱动,只能驱动我的Realtec AC97,而我根本就不想用这个声卡。。。
我的MobilePre在M-Audio的官方网站上有各种MS Windows和Mac操作系统下的驱动。。。
简直是其实我们GNU/Linux用户嘛。。。

怎么办,Google it!,,,
keyword: linux driver MobilePre M-audio。。。
就会发现www.opensound.com,实际上在M-Audio的官方也可以搜得到相关的FAQ上人家介绍说:
有个叫4Front的组织,提供免费的多种Prefessional Audio Interface在Unix和Unix like下的驱动,
个人免费使用,支持和商业使用需要money。。。很公平,不是么。。。

于是,去opensound下载名为:oss-linux_v4.0-1002.deb的deb包,然后根据它的install instruction:
ctr+alt+<F1>进入console;
以root身份登录;
运行dpkg -I oss-linux_v4.0-1002.deb;
然后重新启动。。。

然后,居然听到login theme music,瓦哈哈哈哈!
赶紧打开VLC,打开mp3,mav,avi,全都有声音,质量也不错,哈哈哈,不错!!

到device manager里看看:



多了两个OSS Sequencer Device,当然一个是为AC97,一个MobilePre。。
再看MobilePre下多了:
一个USB Audio OSS Control Device
两个USB Audio OSS PCM Device。。。。

2007年4月22日星期日

使用CSS+dvi之后何时使用table

转自:http://www.chinaz.com/Design/Rules/03225T92007.html
使用WEB标准之后,并不是说排除表格的使用,表格并不是鸡肋,而正好相反是一道大餐, 之所以在很多关于CSS布局的文章中常提到"为什么使用表格排版是不明智的"这句话,可能是大家对他的理解有误,这里注意一点"使用表格排版"是"不明智 "的.指的是我们使用了很多年的,用表格来排版是不明智的,表格归根截底是一种显示"数据"的方式,大家可以想象一下EXCEL,表格就是起这个使用的, 有的时候信息使用表格显示让我们能清晰易读,所以才使用表格,比如公司员工联系表,产品与型号对应表等.

那么所谓表格大餐呢,其实意见上升到了一个层次,也就是说你如果能像专业市场分析公司那样,灵活使用表格来显示客户数据和调查数据等消息的时候,那才是真正利用了表格的优势.

所以,关于那句使用以久的话,应该改为"使用表格作为网页排版, 布局页面元素是不合理的,表格是用来显示数据的"。

关于其它元素

我这里按我的使用经验,把XHTML标准中的一些元素,分为三大类:

第一类是我称之为辅助布局设计元素:

这里我指的是DIV,SPAN等,这类元素的主要功能是用来布局整个页面的,灵活使用这些元素的各种属性,可以让你的页面表现丰富多彩.

第二类我称为结构化元素或叫信息元素

这里指的是TABLE,UL,PRE,CODE类元素是一种信息显示与整理方式,比如TABLE很明显就是用来显示表格信息的,UL是用来显示列化信息的,当需要用表格或列表的时候,用这二种方式来显示是明智的。

第三类指的是 这样的,完全是为了实现一些功能,如填上关键字的META keyword,还有做链接的A

那么正确的符合标准的设计思路是:

使用DIV等布局元素来制作页面的设计布局,定位,色块,图片等

使用TABLE,UL等这样的元素来显示页面中需要展示数据

当然,DIV也起整理数据的作用,使用DIV的ID属性可以很方便的将一个DIV作为一个你名命的数据块。

所以使用WEB标准来制作网站,实际是一个信息合理化整合的一个过程,什么地方该用什么元素还是照用不误,别把表格当布局工具就行。

2007年4月16日星期一

合成器系列----粒子合成器
转载自:http://ch.midifan.com/m_TechArticle/Detail.aspx?id=542
【上】坚果壳中的声音



离子合成(Granular Synthesis)的声音合成方法越来越多的出现在现今的软件合成器中,何谓离子?离子合成又是怎样的?本文来做简单解释。

现 成的一个声音,将被切碎成成千上万的部分,每个部分就叫做一个微粒(grain),离子合成也就因此而得名,再使用这些微粒进行重新排列组合和处理,就得 到了新的声音,这便是离子合成的大致过程。这种使用无数微粒合成声音的方法可以追溯到1947年,一个叫做Denis Gabor的物理学家在《Nature》(自然)杂志发表了一篇名为《Acoustic Quanta and the Theory of Hearing》(声学量子与听觉理论)的论文,在那之后离子合成有了众多的追随者,其中著名的有Iannis Xenakis,Curtis Roads(最先将离子合成与电脑结合起来的人),Barry Truax。

那为什么离子合成在近两年才流行起来呢?按照离子合成的原 理,你不仅可以改变那些成千上万的微粒的音色、长度、音高、频率,还可以将他们按不同顺序再重新排列组合起来。由于可调参数众多,而离子数量更是多的离 谱,在电脑技术和速度都很低的50年代,实现起来有很大的难度。所以离子合成直到90年代才“死灰复燃”了,可见理论永远走在成品的前面。

离子合成,就像坚果壳中的声音!

坚果壳由两个部分组成,果壳和壳中的果肉。在离子合成中,果壳就是声音包络,而果肉就是组成声音的波形。单独的声音微粒也许看不出什么,但成千上万的微粒组成一个完整声音的时候,“果壳”和“果肉”将决定这个声音的最终形态。

首先来看“果肉”——微粒的波形

微 粒的“果肉”可以由任何波形构成,最简单的波形就是正弦波了,其也是最纯净的波形,不含有任何谐波,但在离子合成中,最纯净的正弦波并不适于创造出非常棒 的声音,但因为其波形简单,便于理解,所以我们还是使用正弦波为例子。下图为正弦波的波形。(加法合成就是使用正弦波的,而离子合成的基础就是加法合成)



你 可以定义正弦波的频率(也就是每秒种震荡的次数),但因为正弦波是无限延伸的,所以在一般的合成器上无法定义其震荡的时间长度,而离子合成就可以做到这一 点,不过被限定时间长度的正弦波在这里就不叫正弦波了,而被称为正弦微粒。下图为一个正弦微粒,其时间被限定为0.020秒,而两端的振幅都被衰减了,看 起来像一个坚果壳。



不仅是简单的正弦波形,采样音色也可以作为微粒使用。采样音色的长度将被拉伸或压缩到你需要的微粒长度,而且是只改变采样音色的长度而音高保持不变。

在离子合成中有两类采样音色:长采样和短采样,他们在离子合成中的使用方法是不同的。短采样的长度可以直接当做一个微粒来使用,而长采样可以被切割成多达一系列的微粒使用,当然你可以只使用其中某几个微粒。

下图为一个采样音色:



下图为此采样音色被作为微粒使用,两端的振幅都被衰减了,大体看起来像一个坚果壳。



再来了解“果壳”——微粒的包络

“果壳”决定了微粒的长度和振幅。为微粒加包络的处理方法叫做“开窗术”(windowing,是一种振幅调制的技术),其方法如下图所示。我们不是声音工程师没必要了解如何加包络,所以下图的内容也不必理会,我们需要了解的是:微粒的包络是怎样的。



微 粒的包络不是我们熟悉的ADSR(Attack-Decay-Sustain-Release),而包含了更为丰富的内容:Attack(上冲)、 Sustain(保持)、Decay(衰减)、Amplitude(振幅)、Duration(持续时间)。下图为一个微粒的包络,如果你对声音合成比较 了解的话,不用我讲看图就都明白了。



Duration(持续时间):其决定了一个微粒的持续时间,一般来说10-50毫秒是最佳时间长度。如果微粒的持续时间较短,其会占用更多的频谱带宽而带来噪音,使得声音浑浊不清。

Amplitude(振幅):振幅决定着微粒的音量,最大只能到100%,也就是说微粒的声音不能变大,只能按比例减小。

Attack(上冲):上冲时间决定着微粒从最开始到最大音量持续的时间长短,很短的上冲时间会带来噪音,还有一些边带频谱,这都是我们不希望得到的。

Sustain (保持):保持时间决定着在上冲之后,微粒在最大振幅停留的时间。如果微粒的duration时间很长而sustain时间很短,就会产生一些噪音。一般 来说在离子合成中不能调整Sustain的时间,其长短是由duration-attack-decay得出的。

Decay(衰减):衰减时间决定了微粒由最大振幅到无声的时间,在离子合成中decay的时间与attack时间可以不相同(也就是说果壳的两头不一定是一样尖的),但是不同的attack和decay会带来噪音和频谱的边带,所以一般情况下果壳的两头还是一样尖的。

看到这里,也许你会认为,啊原来微粒的包络都是这个样子的:



哈,那你就小瞧了离子合成中的微粒的,实际上他还可以是这个样子的:



甚至还可以是这个样子:



看完上面3个图你明白了吧,微粒包络中的振幅,可以是直线,也可以是带有拐点的直线,甚至可以是曲线!

本文根据《Sound in a nutshell—Granular Synthesis》以及《real-time granular synthesis》部分内容编译

【下】微粒的截取与组合
转载自:http://ch.midifan.com/m_TechArticle/Detail.aspx?id=543



在上一讲我们已经了解了离子合成的概念,以及微粒的两个特性:果壳和果肉。那么这些成千上万的微粒是如何组合在一起形成最后的声音的呢?方法有二:同步和异步。

首先看同步的离子合成:

使用同步的离子合成方法,所有的微粒的时间长度都是相同的,或者是一种线性递增/递减的关系。

同步的离子合成可以分别调节每个微粒的Amplitude(振幅)、Grain Density(微粒密度)、Pitch(音高)、Inter-onset time(开始时间)。

Grain Density(微粒密度)是离子合成器中比较重要的一个参数,其决定了微粒的分布,以每秒内的微粒数量为单位。每秒低于30个微粒就算是低密度了,这样 做可以使最后发出的声音带有一些节奏感。就像我说哎——呦——啊(长音连读),在低密度情况下,就成了哎(停)哎(停)呦(停)呦(停)啊(停)啊 (停),中间加入了小段的停顿,带来一些节奏的感觉。随着密度的增大,声音频谱就会越复杂,声音的振幅(也就是音量)也会越大,音高会变高。

密度与微粒持续时间之间的关系也会带来声音的变化,单个微粒的持续时间越短,微粒密度越大,那么声音产生的重叠就越多。

Inter-onset time(开始时间)决定了两个临近微粒间的持续时间,这个参数不能自己定义,而是使用密度计算出来的。

再来看异步的离子合成:

使 用异步的离子合成方法,所有微粒都是随机截取的,他们之间的时间关系不像同步离子合成那样是线性的,而是完全没有规律的。但其可调参数与同步离子合成是相 同的,包含了Amplitude(振幅)、Grain Density(微粒密度)、Pitch(音高)、Inter-onset time(开始时间)。

Grain Density(微粒密度)参数同样是以每秒内的微粒数量为单位。在同步离子合成中200微粒/秒表示在一秒的时间内平均截取200个微粒,密度越大音高越高。而在异步离子合成中,这200个微粒是随机截取的,密度与音高没有任何关系。

不管是同步还是异步,所有微粒最后都是按照截取的顺序来排列的,这样才能形成与原采样类似的声音。当然如果是直接使用离子合成新的声音而不是改造采样音色,那么微粒的顺序也可以随机排列。

修整所有微粒组成的声音:

打个比方,每个微粒就好比大树的每片叶子,叶子的形状、颜色都决定了整棵树的外观,不同的叶子代表了不同的树。而微粒组成的整个音色就好比由所有叶子组成的整棵大树,园丁在修剪树木时不是修剪每片叶子(如果是这样,园丁早就累死了),而是对睁棵树的形状、长势做修整。

在离子合成中,我们可以对单个微粒做细致的修改,当然也可以对所有微粒组成的整个声音做修改。我们可以使用几乎所有合成方法来为所有微粒组成的整个声音做修改,在不同的离子合成器中使用的方法也都不同,这里就不列举了。

好 了,到此为止你应该大致了解了离子合成的概念了。简单的说就是将一个采样音色分为成千上万个的微粒,每个微粒的包络都是可调的,而截取微粒的时间长度,密 度也是可调的,截取之后再按照原来的顺序拼接在一起,形成新的声音。当然你也可以使用各种波形比如正弦波、锯齿波、脉冲波组成成千上万个微粒,通过改变包 络,和一些上面讲到的参数,组成全新的充满个性的声音,这就比较难了,而且合成出的声音可能会比较“没谱”,不要气馁,慢慢探索,声音合成光有理论是不够 的,就是要多试多鼓捣,时间长了你就是声音合成的大师了,哈,大师们慢走,以后见。

本文根据《Sound in a nutshell—Granular Synthesis》以及《real-time granular synthesis》部分内容编译




安装Gaim,beta2.03之后就内置qq插件了

1。#安装SVN工具
代码:
sudo apt-get install subversion

2。#安装编译工具和依赖包
代码:
sudo apt-get install build-essential libglib2.0-dev libgtk2.0-dev libgnutls-dev intltool libtool libgstreamer0.10-dev libgtkspell-dev

3。#让gaim支持声效
代码:
sudo apt-get install libao-dev libaudiofile-dev gstreamer0.10-plugins-good

4。#取回源代码
代码:
svn co https://svn.sourceforge.net/svnroot/gaim/trunk gaim

5。
代码:
cd gaim
./autogen.sh
./configure --enable-gnutls=yes
make
sudo make install

2007年4月15日星期日

在linux上安装JDK,very helpful...

转自:http://forum.ubuntu.org.cn/about34307.html

Sun JDK/JRE在Windows上安装很方便,但是在Linux上安装给很多人造成了不少麻烦,这几天我查了不少文章,终于总结出一套较为完整的方案。我是在Ubuntu 6.10上试验的,当然也适合于其他版本的Linux。

Sun发布的JDK/JRE有两种版本,一种是.rpm.bin格式的,另一种则是.bin格式的,前者我没有试,但是我想应该是适合于rpm的,可能会 安装到/usr里面去,而且自动化程度可以高一些。后者则完全是绿色软件,只是做一个解压的动作。下面我就来讲后者的安装全攻略。

1、首先我们要到Sun的网站上去下载JDK/JRE(点这里进入),最新的正式版本已经是6.0(也就是1.6),当然老的版本Sun也仍然提供下载,点上面的“Previous Releases”就可以找到了。下载.bin文件,下面假设这个文件的名字是jdk1.x.bin。

2、把安装文件解压出来。假设我们下载的文件保存在/opt下。

打开终端,运行以下命令:
引用:
cd /opt
chmod a+x jdk1.x.bin
./jdk1.x.bin


你会看到版权提示,不管它,按空格键翻页。然后会提示你是否同意版权协议[yes/no],此时输入yes,回车,安装程序就会把文件解压到当前目录下的jdk1.x这样的目录下面(JRE应该大体相同)。

3、让JDK/JRE支持中文。由于默认安装的JDK/JRE不带中文字体,不支持中文显示,所以我们要自行修改某些字体相关的配置,让它们支持中文。

设定字体有两种方法:

第一种方法是把你的中文字体目录做个连接到jdk/jre/lib/fonts里面,这种方法很简便。看命令:
引用:
cd /opt/jdk1.x/jre/lib/fonts
ln -s /usr/share/fonts/truetype/windows fallback (假设我们的中文字体放在/usr/share/fonts/truetype/windows目录里,这个目录里我放的是从Windows那边copy过来的字体)

为什么要做fallback这个连接,我也是从网上看到的,我想应该是Sun做的设定吧,设定JDK/JRE在运行时会到这个目录里去找那些非西 方字体。这种方法对JDK/JRE 1.4/1.5/1.6都适用,但是由于没有在fontconfig.properties文件里面详细设定字体,所以这种方法显示出来的字体很难看。

第二种方法是把配置好的fontconfig.properties做个连接到jdk1.x/jre/lib里面。看命令:
引用:
cd /opt/jdk1.x/jre/lib
ln -s /etc/java/fontconfig.properties (假设我们的fontconfig.properties放在/etc/java目录里)

这种方法对JDK/JRE 1.4/1.5/1.6都适用,只不过1.4版本的文件名是font.properties而不是fontconfig.properties。当然你也 可以直接把fontconfig.properties文件复制到/opt/jdk1.x/jre/lib里面,这样就不用做连接,但是如果你同时安装几 个不同版本的JDK,还是做连接比较方便。在下面我会把我配置好的font.properties和fontconfig.properties的内容贴 出来,大家稍作修改就可以用了。

3、让Web浏览器支持Java插件(也就是支持Java Applets)。

做一个连接就可以了。看命令:
引用:
cd /usr/lib/firefox/plugins (Ubuntu的firefox插件目录在这里,其它版本以此参考)
ln -s /opt/jdk1.x/jre/plugin/i386/ns7/libjavaplugin_oji.so

然后运行firefox,在地址栏里打入about:plugins,回车,可以看到firefox的插件列表里已经有了Java插件。

如果你用的是其它的浏览器,方法大体也差不多,就是进入浏览器的plugins目录,做一个连接。不过要注意的是,如果你用的浏览器是 mozilla 1.4/netscape 7.0以上的版本,用上面的命令没问题,但是如果你用的浏览器是mozilla 1.2/netscape 7.0以下的版本,Sun有提供另一个插件。这样的话,命令就要改一下了:
引用:
cd /usr/lib/mozilla/plugins
ln -s /opt/jdk1.x/jre/plugin/i386/ns7-gcc29/libjavaplugin_oji.so


4、让Web浏览器支持Java Web Start程序。(可选安装)

如果你不知道Java Web Start程序是什么,看这里:
http://www.stcore.com/java/2006/06/18/1150640682d28890.html

所谓安装,其实就是添加一个mimetype(类似于文件关联),让浏览器知道,遇到Java Web Start程序该用什么程序来处理。

对应mozilla/netscape浏览器的方法:
点击菜单:Edit->Preferences->Navigator->Helper Applications
然后新建一个mimetype:
mimetype是:application/x-java-jnlp-file
extention是:jnlp
关联程序是:/opt/jdk1.x/jre/bin/javaws

对应firefox浏览器的方法:
由于firefox没有直接添加mimetype的方法,所以要改的话需要安装一个Mime Type Editor扩展,看这里:
http://forums.mozine.org/index.php?showtopic=5521

5、为firefox浏览器加入Java Console菜单项。(可选安装)

mozilla/netscape装好java插件之后就有Java Console菜单项,可以方便地调用Java控制台,这对程序员调试程序有用。但是firefox还没有这个菜单项,添加的方法就是解压一个zip文件 到firefox/extension目录。现在我们就来添加,看命令:

引用:
cd /usr/lib/firefox/extensions
unzip /opt/jdk1.x/jre/lib/deploy/ffjcext.zip


重启firefox,就可以看到工具菜单里多了一个Java Console菜单项。

JDK/JRE 1.5及以下版本并没有提供这个firefox扩展,如果要安装的话到这里安装:

https://addons.mozilla.org/firefox/141/

6、把Java工具加入系统菜单。(可选安装)

Ubuntu自带的JDK/JRE会在系统菜单中添加两个Java工具,就是Java Plugin Control Panel和Java Policy Tool。下面我们也为自己安装的JDK/JRE添加两个菜单项。

在Ubuntu的主菜单上点击右键->编辑菜单->首选项->新建项目:

第一项:
图标是:/opt/jdk1.x/jre/plugin/desktop/sun_java.png
名称是:Java Plugin Control Panel (这个随便写)
命令是:/opt/jdk1.x/jre/bin/ControlPanel

第二项:
图标是:/opt/jdk1.x/jre/plugin/desktop/sun_java.png
名称是:Java Policy Tool (这个随便写)
命令是:/opt/jdk1.x/jre/bin/policytool

7、添加JAVA_HOME/JRE_HOME环境变量。(Java开发人员必备)

这里以最常用的bash命令解释器为例,编辑用户目录下的.bashrc或.profile文件。如果你想在所有用户的shell下都生效,就编辑/etc/profile文件。同样都是加入以下内容:

引用:
export JAVA_HOME=/opt/jdk1.x
export JRE_HOME=/opt/jdk1.x/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH


至此,Sun JDK/JRE在Linux上的安装过程结束。

XML 和 Java 技术: 数据绑定的多种用法

转载自:http://www.ibm.com/developerworks/cn/xml/x-xjavaforum2.html?S_TACT=105AGX52&S_CMP=techcsdn

XML 和 Java 技术: 数据绑定的多种用法

绑定哪些数据,如何使用它们?


级别: 中级

Brett McLaughlin (brett@newInstance.com), 作家兼编辑, O'Reilly Media Inc.

2007 年 4 月 13 日

除 将 XML 用作一种简单数据格式之外,数据绑定是 XML 最流行的用法之一。即使刚刚入门的程序员也能在一种原生编程语言中使用 XML,并且在大多数情况下完全不需要任何的 XML 专门知识。本文并不是介绍解决方案,取而代之,Brett 介绍了一些讨论主题,鼓励您思考如何使用 XML 和数据绑定。欢迎在 XML 和 Java 技术讨论论坛上与别人一起分享您的想法。

XML 用于业务而非技术

随着 XML 的日趋盛行,人们也越来越注重可用性。 换句话说,程序员和管理者并不希望把 XML 看作是一项技术,拥有自己的语义和词汇结构,而认为它更像是纯粹的数据,访问时不用担心 XML 数据格式的细节。

完成 XML 从技术到业务格式的转换,最简单是方法就是数据绑定,这种说法还有待论证。数据绑定就是使用应用程序编程接口(Application Programming Interface,API)操作 XML 文档中的数据,这样程序员就不必过多地了解 XML,不必使用角括号,或者考虑 CDATA 部分或实体引用等等之类的事情。但即使是使用数据绑定,您也会发现在继续操作之前有大量的选项和重要问题需要仔细考虑。

出于本文讨论的目的,我将介绍两个与数据绑定相关的基本问题:

  1. 通过数据绑定 API 表示数据的方法。
  2. 当数据被视为业务数据时的用法。






表示 XML 数据

在最普通的情况下,数据绑定就是将 XML 文档中的数据转换成正在使用的编程语言中的对象。

用于数据绑定的基于对象的 API

比方说,查看下面这段 XML 代码:

<person>
<firstName>Brett</firstName>
<lastName>McLaughlin</lastName>
<email>brett@newInstance.com</email>
</person>

我们可以将这段代码转换成对象,比方说在 Java™ 代码中,这是一个 Person 类的实例,拥有成员变量 firstNamelastNameemail。实例应该包含代码段中的数据,并且能通过方法调用访问该数据,例如 myPerson.getFirstName() 方法。

用于数据绑定的基于文档的 API

尽管这是最常见的数据绑定方法,但是使用 XML 文档并把整个文档表示成一个对象的 API 也是数据绑定的一种形式。这些 API 包括文档对象模型(Document Object Model,DOM)、JDOM 和 dom4j,所有这些 API 都用于在 Java 编码中创建 XML 文档的对象模型。

在这些模型中,我们使用 rootElement.getChild("firstName").getValue() 之类的调用(或者与之相似的调用,取决于 API 的细节)。虽然这确实需要一些 XML 的基础知识(理解元素是什么以及文档的基本结构),但还是对程序员抽象了解析的细节。这就是数据绑定的本质:能够更多地注意到数据而不是数据显示的格式。

程序员更轻松(有点)

一旦采用了更普通的数据绑定解决方案,如 Sun's JAXB,那么需要注意的底层 XML 语法将会更少。可以真正完全地使用 Java(或者您偏好的编程语言)对象、方法和变量。即使是元素的细节和文档结构也隐藏在了数据绑定处理创建的对象之下。

但是,此处的关键是(经常没有考虑到的)仍然需要将 XML 数据结构与系统中的对象匹配,或者需要在系统中创建匹配所使用的 XML 数据格式的对象。这两种情况到 XML 的映射都不太明显,但它仍然是处理的一部分。

那么是哪一种情况呢?

我在这里概述了两种基本的方法,但是这两种方法并不是像第一眼看上去那样区别很大。使用 DOM 或者 JDOM 之类的 API 时,不管是加载 XML 还是访问数据都需要不断地处理文档的结构。在第二种方法中,使用 JAXB 之类的 API 时,需要预先处理 XML,建立使用 XML 的对象模型(或者有时使用工具为您创建需要的类和对象)。然后,在运行时,将数据更多地作为业务数据来使用,可以不用考虑 XML 了。

如果 XML 不是非常易读的格式,或者并非如希望那样以业务目的分开,或者其格式会经常变化,则第一种方法将会是很好的选择。该方法需要更多一点的 XML 知识以及使用 API(更多地以技术为中心而不是以业务为中心)的能力。

另一方面,如果 XML 是按照业务需求组织的,并且 XML 结构很少变化,则可以一次性的创建类和对象,然后在运行时将数据作为业务数据使用,完全不用担心数据底层的 XML。







如何使用数据?

开发人员常常会疏于考虑:如何根据选择的数据绑定解决方案使用 XML 文档中的数据。但是,这可能是正确决定数据绑定方法的一个最重要的因素。

将对象用于持久数据

将 XML 数据转换成对象实例的数据绑定方法只适用于那些要多次使用的数据。获取 XML 文档中的数据并将其转换为多个对象中的成员变量数据涉及大量的处理工作。要从这个方法中获利,需要多次使用到该数据。

仔细查看一条数据的访问次数,同时也考虑一下使用了多少数据。比如说,假设 XML 中为每个人存储了 20 条数据,但应用程序中只访问了其中的一条,使用大量的资源转换数据却只是为了访问其中的一条。不论怎样计算这都不可能获利。

使用对象在其它组件中隐藏 XML

隐藏存储介质是使用基于对象的方法的另一个重要原因。因此应用程序中可能有一个组件对 Person 对象执行一些特殊的处理。可以从数据库或者 XML 文档或者属性文件中读取 people 数据,然后把这些数据转换成 Person 对象,再把这些对象传递给处理组件。

即使只是暂时使用数据,这也是用对象表示数据的一种很合理的情形。在本例中,如果将数据表示为对象格式,并且应用程序的其它部分已了解如何使用该格 式,则可以获益。同时还避免了组件的数据转化和数据加载,而您只希望使用某种类型的对象来实现相应操作,这很好地实现了应用程序中的关系隔离,而它正是应 该遵循的一条重要的设计原则(应用程序中的每个组件只实现一个功能,并实现好该功能)。

短期,只使用一次的数据

如果没有要重用的数据,而且不以对象的形式将数据传递给应用程序中的另一个组件,则可以考虑使用 DOM 或者 JDOM 之类的 API。这比将 XML 转换成非文档格式所使用的资源少,从而可以全面受益。此方法比以高昂的代价将数据转化为特定于业务的对象、以后却只使用该数据一二次要好得多。

尽管本文的主题是数据绑定,但有一点值得提到的是在这些情况下甚至可以考虑使用 SAX(Simple API for XML)这样的 API,它完全不提供对象模型(以文档或对象格式)。使用它处理 XML 只使用很少的内存和时间,如果确实只需要使用一条数据一到两次,则此方法可让您获益巨大。使用像 SAX 这样的 API 需要更多的了解 XML 的知识,但了解这些知识是非常值得的。

2007年4月13日星期五

Apache FOP Project, mark一下

Apache FOP这个Apache Project好像比较有意思,mark一下


FOP是格式对象处理器的意思,它是一个打印格式化器,它由XSL格式化对象(XSL-FO)驱动。
同时它是一个java应用程序,读入格式化对象(FO)树,并且渲染结果页面成特定的输出格式。目前支持的输出格式包括PDF,PCL,PS,SVG,XML等等。
这种想法和我想移植google doc的实现办法有些相似:
  • ajax结合XML,处理XML文档
  • XML通过XSL保存为ps后台文档,ps后台文档可以处理成PDF输出
  • XML文档同时也可以通过前台XSL显示为“可见”的HTML格式化文档,这个HTML文档和PDF文档应该显示一致。
  • 因而这两个XSL的设计就比较重要。

以下转载自:
http://xmlgraphics.apache.org/fop/

Apache FOP

Introduction

Apache FOP (Formatting Objects Processor) is the world's first print formatter driven by XSL formatting objects (XSL-FO) and the world's first output independent formatter. It is a Java application that reads a formatting object (FO) tree and renders the resulting pages to a specified output. Output formats currently supported include PDF, PCL, PS, SVG, XML (area tree representation), Print, AWT, MIF and TXT. The primary output target is PDF.

Render Diagram

The previous version of FOP (0.20.5) is a partial implementation of the XSL-FO Version 1.0 W3C Recommendation.

The latest stable version of FOP (0.93) is the first stable release after a large redesign effort and implements a larger subset than 0.20.5 of the XSL-FO Version 1.0 W3C Recommendation as well as some parts of the XSL-FO Version 1.1 Working Draft.

Support for each of the standard's objects and properties is detailed in FOP Compliance. Download options include a precompiled version, source code, and many example files to get you started. Resources include links to XSL-FO introductions and many other useful references. A checklist for Getting Help will guide you toward maximizing the usefulness of FOP.

FOP is proud to be part of Apache's XML Graphics project.

Demonstration

Formatting Diagram

This image is a demonstration of a real two page document. The xml data on the left is formatted into the two pages on the right. The document contains static areas that appear on every page, an external graphic, a footnote on the first page, and a table that goes across both pages.

FOP uses the standard XSL-FO file format as input, lays the content out into pages, then renders it to the requested output. One great advantage to using XSL-FO as input is that XSL-FO is itself an XML file, which means that it can be conveniently created from a variety of sources. The most common method is to convert semantic XML to XSL-FO, using an XSLT transformation.

FOP Objectives

The goals of the Apache FOP project are to deliver an XSL-FO to PDF formatter that is compliant to at least the Basic conformance level described in the W3C Recommendation from 15 October 2001, and that complies with the 11 March 1999 Portable Document Format Specification (Version 1.3) from Adobe Systems.

Conformance to the XML 1.0 Recommendation, XSLT 1.0 Recommendation and the XML Namespaces Recommendation is understood. Other relevant documents, such as the XPath and XLink Working Drafts, are referenced as necessary. The FOP Project will attempt to use the latest version of evolving specifications.

The FOP layout system is currently being rewritten to better support the XSL-FO standard.

可爱的 Python: Decorator 简化元编程

转载自:http://www.ibm.com/developerworks/cn/linux/l-cpdecor.html



可爱的 Python: Decorator 简化元编程

用于元编程的最新 Python 工具简介





级别: 高级

David Mertz, Ph. D. (mertz@gnosis.cx), 开发人员, Gnosis Software, Inc.

2007 年 1 月 23 日

Python 使元编程成为可能,不过每个版本的 Python 都有一些细微的区别(并且不是完全兼容),这使我们实现元编程的道路变得更加崎岖。一类函数对象的使用由来已久,同样还有一些技术用于探索和实现魔术般的 属性。在版本 2.2 中,Python 增加了一种很有帮助的定制元类机制,但是其代价就是令用户绞尽脑汁。最近,在 2.4 版本中,Python 增加了 “decorator” ,这是适于执行大部分元编程的最新方式 —— 也是到目前为止对用户最友好的方式。

少劳多得

Decorator 与 Python 之前引入的元编程抽象有着某些共同之处:即使没有这些技术,您也一样可以实现它们所提供的功能。正如 Michele Simionato 和我在 可爱的 Python 专栏的早期文章 中指出的那样,即使在 Python 1.5 中,也可以实现 Python 类的创建,而不需要使用 “元类” 挂钩。

Decorator 根本上的平庸与之非常类似。Decorator 所实现的功能就是修改紧接 Decorator 之后定义的函数和方法。这总是可能的,但这种功能主要是由 Python 2.2 中引入的 classmethod()staticmethod() 内置函数驱动的。在旧式风格中,您可以调用 classmethod(),如下所示:



清单 1. 典型的 “旧式” classmethod
       
class C:
def foo(cls, y):
print "classmethod", cls, y
foo = classmethod(foo)

虽然 classmethod() 是内置函数,但并无独特之处;您也可以使用自己的方法转换函数。例如:



清单 2. 典型的 “旧式” 方法的转换
       
def enhanced(meth):
def new(self, y):
print "I am enhanced"
return meth(self, y)
return new
class C:
def bar(self, x):
print "some method says:", x
bar = enhanced(bar)

decorator 所做的一切就是使您避免重复使用方法名,并且将 decorator 放在方法定义中第一处提及其名称的地方。例如:



清单 3. 典型的 “旧式” classmethod
       
class C:
@classmethod
def foo(cls, y):
print "classmethod", cls, y
@enhanced
def bar(self, x):
print "some method says:", x

decorator 也可以用于正则函数,采用的是与类中的方法相同的方式。令人惊奇的是,这一切是如此简单(严格来说,甚至有些不必要),只需要对语法进行简单修改,所有东 西就可以工作得更好,并且使得程序的论证更加轻松。通过在方法定义的函数之前列出多个 decorator,即可将 decorator 链接在一起;良好的判断可以有助于防止将过多 decorator 链接在一起,不过有时候将几个 decorator 链接在一起是有意义的:



清单 4. 链接 decorator
       
@synchronized
@logging
def myfunc(arg1, arg2, ...):
# ...do something
# decorators are equivalent to ending with:
# myfunc = synchronized(logging(myfunc))
# Nested in that declaration order

Decorator 只是一个语法糖,如果您过于急切,那么它就会使您搬起石头砸了自己的脚。decorator 其实就是一个至少具有一个参数的函数 —— 程序员要负责确保 decorator 的返回内容仍然是一个有意义的函数或方法,并且实现了原函数为使连接有用而做的事情。例如,下面就是 decorator 两个不正确的用法:



清单 5. 没有返回函数的错误 decorator
       
>>> def spamdef(fn):
... print "spam, spam, spam"
...
>>> @spamdef
... def useful(a, b):
... print a**2 + b**2
...
spam, spam, spam
>>> useful(3, 4)
Traceback (most recent call last):
File "", line 1, in ?
TypeError: 'NoneType' object is not callable

decorator 可能会返回一个函数,但这个函数与未修饰的函数之间不存在有意义的关联:



清单 6. 忽略传入函数的 decorator
       
>>> def spamrun(fn):
... def sayspam(*args):
... print "spam, spam, spam"
... return sayspam
...
>>> @spamrun
... def useful(a, b):
... print a**2 + b**2
...
>>> useful(3,4)
spam, spam, spam

最后,一个表现更良好的 decorator 可以在某些方面增强或修改未修饰函数的操作:



清单 7. 修改未修饰函数行为的 decorator
       
>>> def addspam(fn):
... def new(*args):
... print "spam, spam, spam"
... return fn(*args)
... return new
...
>>> @addspam
... def useful(a, b):
... print a**2 + b**2
...
>>> useful(3,4)
spam, spam, spam
25

您可能会质疑,useful() 到底有多么有用?addspam() 真的是那样出色的增强 吗?但这种机制至少符合您通常能在有用的 decorator 中看到的那种模式。







高级抽象简介

根据我的经验,元类应用最多的场合就是在类实例化之后对类中的方法进行修改。decorator 目前并不允许您修改类实例化本身,但是它们可以修改依附于类的方法。这并不能让您在实例化过程中动态添加或删除方法或类属性,但是它让这些方法可以在运行时根据环境的条件来变更其行为。现在从技术上来说,decorator 是在运行 class 语句时应用的,对于顶级类来说,它更接近于 “编译时” 而非 “运行时”。但是安排 decorator 的运行时决策与创建类工厂一样简单。例如:



清单 8. 健壮但却深度嵌套的 decorator
       
def arg_sayer(what):
def what_sayer(meth):
def new(self, *args, **kws):
print what
return meth(self, *args, **kws)
return new
return what_sayer

def FooMaker(word):
class Foo(object):
@arg_sayer(word)
def say(self): pass
return Foo()

foo1 = FooMaker('this')
foo2 = FooMaker('that')
print type(foo1),; foo1.say() # prints: this
print type(foo2),; foo2.say() # prints: that

@arg_sayer() 绕了很多弯路,但只获得非常有限的结果,不过对于它所阐明的几方面来说,这是值得的:

  • Foo.say() 方法对于不同的实例有不同的行为。在这个例子中,不同之处只是一个数据值,可以轻松地通过其他方式改变这个值;不过原则上来说,decorator 可以根据运行时的决策来彻底重写这个方法。

  • 本例中未修饰的 Foo.say() 方法是一个简单的占位符,其整个行为都是由 decorator 决定的。然而,在其他情况下,decorator 可能会将未修饰的方法与一些新功能相结合

  • 正如我们已经看到的一样,Foo.say() 的修改是通过 FooMaker() 类工厂在运行时严格确定的。可能更加典型的情况是在顶级定义类中使用 decorator,这些类只依赖于编译时可用的条件(这通常就足够了)。

  • decorator 都是参数化的。或者更确切地说,arg_sayer() 本身根本就不是一个真正的 decorator;arg_sayer() 所返回的 函数 —— what_sayer() 就是一个使用了闭包来封装其数据的 decorator 函数。参数化的 decorator 较为常见,但是它们将所需的函数嵌套为三层。






迈进元类领域

正 如上一节中介绍的一样,decorator 并不能完全取代元类挂钩,因为它们只修改了方法,而未添加或删除方法。实际上,这样说并不完全正确。作为一个 Python 函数,decorator 完全可以实现其他 Python 代码所实现的任何功能。通过修饰一个类的 .__new__() 方法(甚至是其占位符版本),您实际上可以更改附加到该类的方法。尽管尚未在现实中看到这种模式,不过我认为它有着某种必然性,甚至可以作为 _metaclass_ 指派的一项改进:



清单 9. 添加和删除方法的 decorator
       
def flaz(self): return 'flaz' # Silly utility method
def flam(self): return 'flam' # Another silly method

def change_methods(new):
"Warning: Only decorate the __new__() method with this decorator"
if new.__name__ != '__new__':
return new # Return an unchanged method
def __new__(cls, *args, **kws):
cls.flaz = flaz
cls.flam = flam
if hasattr(cls, 'say'): del cls.say
return super(cls.__class__, cls).__new__(cls, *args, **kws)
return __new__

class Foo(object):
@change_methods
def __new__(): pass
def say(self): print "Hi me:", self

foo = Foo()
print foo.flaz() # prints: flaz
foo.say() # AttributeError: 'Foo' object has no attribute 'say'

change_methods() decorator 示例中,我们添加并删除了几个固定的方法,不过这是毫无意义的。在更现实的情况中,应使用上一节中提到的几个模式。例如,参数化的 decorator 可以接受一个能表示要添加或删除的方法的数据结构;或者由数据库查询之类的某些环境特性做出这一决策。这种对附加方法的操作也可以像之前一样打包到一个函 数工厂中,这将使最终决策延迟到运行时。这些新兴技术也许比 _metaclass_ 指派更加万能。例如,您可以调用一个增强了的 change_methods(),如下所示:



清单 10. 增强的 change_methods()
       
class Foo(object):
@change_methods(add=(foo, bar, baz), remove=(fliz, flam))
def __new__(): pass







修改调用模型

您将看到,有关 decorator 的最典型的例子可能是使一个函数或方法来实现 “其他功能”,同时完成其基本工作。例如,在诸如 Python Cookbook Web 站点(请参见 参考资料 中的链接)之类的地方,您可以看到 decorator 添加了诸如跟踪、日志记录、存储/缓存、线程锁定以及输出重定向之类的功能。与这些修改相关(但实质略有区别)的是修饰 “之前” 和 “之后”。对于修饰之前/之后来说,一种有趣的可能性就是检查传递给函数的参数和函数返回值的类型。如果这些类型并非如我们预期的一样,那么这种 type_check() decorator 就可能会触发一个异常,或者采取一些纠正操作。

与这种 decorator 前/后类似的情况,我想到了 R 编程语言和 NumPy 特有的函数的 “elementwise” 应用。在这些语言中,数学函数通常应用于元素序列中的每个元素,但也会应用于单个数字。

当然,map() 函数、列表内涵(list-comprehension)和最近的生成器内涵(generator-comprehension 都可以让您实现 elementwise 应用。但是这需要较小的工作区来获得类似于 R 语言的行为:map() 所返回的序列类型通常是一个列表;如果您传递的是单个元素而不是一个序列,那么调用将失败。例如:



清单 11. map() 调用失败
       
>>> from math import sqrt
>>> map(sqrt, (4, 16, 25))
[2.0, 4.0, 5.0]
>>> map(sqrt, 144)
TypeError: argument 2 to map() must support iteration

创建一个可以 “增强” 普通数值函数的 decorator 并不困难:



清单 12. 将函数转换成 elementwise 函数
       
def elementwise(fn):
def newfn(arg):
if hasattr(arg,'__getitem__'): # is a Sequence
return type(arg)(map(fn, arg))
else:
return fn(arg)
return newfn

@elementwise
def compute(x):
return x**3 - 1

print compute(5) # prints: 124
print compute([1,2,3]) # prints: [0, 7, 26]
print compute((1,2,3)) # prints: (0, 7, 26)

当然,简单地编写一个具有不同返回类型的 compute() 函数并不困难;毕竟 decorator 只需占据几行。但是作为对面向方面编程的一种认可,这个例子让我们可以分离 那些在不同层次上运作的关注事项。我们可以编写各种数值计算函数,希望它们都可转换成 elementwise 调用模型,而不用考虑参数类型测试和返回值类型强制转换的细节。

对于那些对单个事物或事物序列(此时要保留序列类型)进行操作的函数来说,elementwise() decorator 均可同样出色地发挥作用。作为一个练习,您可尝试去解决如何允许相同的修饰后调用来接受和返回迭代器(提示:如果您只是想迭代一次完整的 elementwise 计算,那么当且仅当传入的是一个迭代对象时,才能这样简化一些。)

您 将碰到的大多数优秀的 decorator 都在很大程度上采用了这种组合正交关注的范例。传统的面向对象编程,尤其是在诸如 Python 之类允许多重继承的语言中,都会试图使用一个继承层次结构来模块化关注事项。然而,这仅会从一个祖先那里获取一些方法,而从其他祖先那里获取其他方法,因 此需要采用一种概念,使关注事项比在面向方面的思想中更加分散。要充分利用生成器,就要考虑一些与混搭方法不同的问题:可以处于方法本身的 “核心” 之外的关注事项为依据,使 方法以不同方式工作。





回页首


修饰 decorator


在结束本文之前,我想为您介绍一种确实非常出色的 Python 模块,名为 decorator,它是由与我合著过一些图书的 Michele Simionato 编写的。该模块使 decorator 的开发变得更加美妙。decorator 模块的主要组件具有某种自反式的优雅,它是一个称为 decorator() 的 decorator。与未修饰的函数相比,使用 @decorator 修饰过的函数可以通过一种更简单的方式编写。(相关资料请参看 参考资料)。

Michele 已经为自己的模块编写了很好的文档,因此这里不再赘述;不过我非常乐意介绍一下它所解决的基本问题。decorator 模块有两大主要优势。一方面,它使您可以编写出嵌套层次更少的 decorator,如果没有这个模块,您就只能使用更多层次(“平面优于嵌套”);但更加有趣的是这样一个事实:它使得修饰过的函数可以真正地与其在元 数据中未修饰的版本相匹配,这是我的例子中没有做到的。例如,回想一下我们上面使用过的简单 “跟踪” decorator addspam()



清单 13. 一个简单的 decorator 是如何造成元数据崩溃的
       
>>> def useful(a, b): return a**2 + b**2
>>> useful.__name__
'useful'
>>> from inspect import getargspec
>>> getargspec(useful)
(['a', 'b'], None, None, None)
>>> @addspam
... def useful(a, b): return a**2 + b**2
>>> useful.__name__
'new'
>>> getargspec(useful)
([], 'args', None, None)

尽管这个修饰过的函数的确完成 了自己增强过的工作,但若进一步了解,就会发现这并不是完全正确的,尤其是对于那些关心这种细节的代码分析工具或 IDE 来说更是如此。使用 decorator,我们就可以改进这些问题:



清单 14. decorator 更聪明的用法
       
>>> from decorator import decorator
>>> @decorator
... def addspam(f, *args, **kws):
... print "spam, spam, spam"
... return f(*args, **kws)
>>> @addspam
... def useful(a, b): return a**2 + b**2
>>> useful.__name__
'useful'
>>> getargspec(useful)
(['a', 'b'], None, None, None)

这对于编写 decorator 更加有利,同时,其保留行为的元数据的也更出色了。当然,阅读 Michele 开发这个模块所使用的全部资料会使您回到大脑混沌的世界,我们将这留给 Simionato 博士一样的宇宙学家好了。



参考资料

学习

在ubuntu上安装 XAMPP 进行方便集成开发

转载自:http://www.ibm.com/developerworks/cn/linux/l-xampp/


XAMPP 简介

XAMPP 是一个功能全面的 AMPP (Apache、MySQL、PHP、Perl)软件包,这是 Linux 平台上可以使用的几种非商业 AMPP 中间件之一。采用这种紧密的集成,XAMPP 可以运行任何程序:从个人主页到功能全面的产品站点(虽然这仅仅用于开发目的;出于安全考虑,XAMPP 还不适于用在产品服务器上)。

XAMPP 实际上在以下几个方面大放光彩:

  • 易于安装和设置。
  • 包含很多有用的软件包,可以简化诸如生成流量报告和加速 PHP 内容之类的任务。
  • 已经在 SUSE、Red Hat、Mandrake、Debian Linux 发行版以及 Windows® 和 Solaris 上进行了完整的测试。

对于本文来说,我们将在 Mandrake Linux 10.0 上安装 XAMPP。现在我们首先看看 XAMPP 中提供的缺省软件包。

基本的软件包

基本的软件包包括系统、编程和服务器软件:

  • Apache,著名的 Web 服务器
  • MySQL,一种杰出、免费的开源数据库
  • PHP,一种编程语言(在撰写本文时版本为 4.3.8 和 5.0.1)
  • Perl,一种编程语言
  • ProFTPD,一个 FTP 服务器
  • OpenSSL,可以支持安全套接字层

图形软件包

XAMPP 包括以下与图形有关的软件包:

  • GD,“Graphics Draw”库
  • libpng,官方的 PNG 参考实现库
  • libjpeg,官方的 JPEG 参考实现库
  • ncurses,字符图形库

数据库软件包

如果没有以下的数据库软件包,怎么还能叫集成软件呢?

  • gdbm,标准的 UNIX® dbm 库的 GNU 实现
  • SQLite,一个相当小的、无需任何配置的 SQL 数据库引擎
  • FreeTDS,一个数据库,让 UNIX 和 Linux 程序可以访问 Microsoft® SQL 和 Sybase 数据库

XML 软件包

为了开发 XML 程序,XAMPP 应该包含以下软件包:

  • expat,一个 XML 解析器库
  • Salbotron,一个 XML 工具包
  • libxml,一个 XML C 解析器和 GNOME 工具包

PHP 软件包

为了开发 PHP 程序,XAMPP 应该包括以下软件包:

  • PEAR,PHP 库
  • 一个 pdf 类,可以使用 PHP 生成动态的 PDF 文档
  • TURCK MMCache,一个 PHP 性能增强器

其他软件包

最后,XAMPP 中包含了以下软件包来展示自己的强大功能:

  • zlib,一个压缩库
  • mod_perl,在 Apache 中嵌入了一个永久的 Perl 解释器
  • gettext,一个工具集,可以帮助 GNU 软件包生成多语言的消息
  • mcrypt,一个加密程序
  • Ming,一个 Flash (SWF) 输出库
  • Freetype2,一个软件前端引擎
  • IMAP C-Client,一个邮件编程 API

现在让我们讨论一下安装 XAMPP 的问题。





回页首


安装并作为守护进程运行

要安装 XAMPP,请从 Apache Friends Web 站点上下载最新的二进制文件(请参阅 参考资料 中的链接)。使用下面的命令将其解开到 /opt 目录中:

tar xvfz xampp-linux-1.4.7.tar.gz -C /opt

就是这样!XAMPP 现在已经被安装到 /opt/lampp 目录中了。之前安装在 /opt 目录中的内容都已经被覆盖了。如果您正在运行一个旧版本的 XAMPP,并且不想再次下载整个软件包,Apache Friends 中还提供了一个升级包来下载需要的软件包。

现在所有的软件都已经安装好了,让我们启动新的守护进程。将当前的工作目录切换到 /opt/lampp ( cd /opt/lampp)并输入下面的命令:

./lampp start

您应该会看到下面的结果:

Starting XAMPP for Linux 1.4.7...
XAMPP: Starting Apache with SSL (and PHP5)...
XAMPP: Starting MySQL...
XAMPP: Starting ProFTPD...
XAMPP for Linux started.

XAMPP 现在就启动并运行了。最好的验证方法是打开一个浏览器并在地址栏中输入 localhost,并按回车键。此时浏览器会被重定向到 XAMPP 的 welcome 页面。



图 1. XAMPP welcome 页面
XAMPP welcome 页面

点击左边导航栏中的 Status 链接,就可以看到必需的服务已经正确启动了。如果所有的服务都运行正常,您就会看到下面的页面:



图 2. Service status 页面
Service status 页面

恭喜!您现在已经安装和设置好了一个完整的 AMPP 开发环境了。现在让我们安装一个简单的应用程序来展示一下如何使用这种环境。





回页首


安装一个简单的应用程序

要利用 XAMPP 的基本特性,您需要一个简单的应用程序。最好的应用程序是一个在后端使用数据库的程序;并使用一个相当简单的数据库,其中包含了一个精心设计的表。

测试数据库包含一个只有一列的表。让我们按照测试程序的(计算机)传统,设计在我们的表中存放一条记录“Hello World!”。我们将使用一个 Perl 和 一个 PHP 脚本来访问这个数据库。这两个脚本都可以访问这个数据库,从中检索这行记录,并将其输出到屏幕上。

工具

我 们的数据库将使用 phpMyAdmin 来创建和管理,这是使用 PHP 编写的一个杰出的基于 Web 的 MySQL 管理工具。它有一个非常友好的用户界面,可以允许您处理各种复杂的任务,包括创建/删除/修改数据库和表,以及导出数据、管理关键字和处理 SQL 文件。phpMyAdmin 是一个杰出的工具,因为:

  • 它可以帮助初学者熟悉 MySQL,而不用使用命令行接口来处理这些任务。
  • 它允许高级用户更快更容易地执行简单的任务和例行的任务。
  • 当您希望为某些用户授权访问数据库而不想让他们完全访问 shell 时,对于这种情况非常有用。

创建数据库

要在 phpMyAdmin 中创建一个数据库,请遵循下面的步骤:

  1. 转换到 XAMPP 的 start 页面 (localhost)。
  2. 在左边导航栏的 Tools 下面选择 phpMyAdmin
  3. 在 phpMyAdmin 主页的 Create New Database 域中,输入 hello_world,并点击 Create

现在您必须在数据库中创建一个表,并指定该表中应该包含哪些字段(字段与列类似)。让我们将自己的表称为“hello_table”,并让它只包含一个字段,其中保存记录“Hello world!”。在 Name 文本域中输入 hello_table,并在 Fields 文本域中输入 1。输入完之后,点击 Go

现在应该执行创建数据库的最后一个步骤了:为列选择一个名字和一个数据类型定义。让我们选中“hello”并将其命名为“hello_column”;并在 Field 文本域中输入 hello_column

由于我们要在列中存储字符串“Hello World!”,因此其类型必须是 char,长度为 12 (字符串 "Hello World!" 的长度)。缺省类型 varchar 就足够了。在 Type 后面的 Length/Values 文本域中,输入 12,表示最大长度是 12 个字符。不用关心该页面中其他域的设置,继续点击 Save

如果一切正常,您应该会看到下面的界面:



图 3. Hello World 数据库摘要
Hello World 数据库摘要

现在让我们插入记录 "Hello World!"。点击 Insert 标签,并在 Value 文本域中输入 "Hello World!"。 Function 下拉列表在这个例子中可以保留不变。点击 Go,将 "Hello World!" 记录插入数据库中。

要确认记录已经成功插入数据库,请点击 Browse 标签。现在会显示 "hello world"。

脚本

现在后端软件已经启动并运行了,应该处理脚本部分了。我们将使用两个脚本,一个使用 Perl 编写,另外一个使用 PHP 编写。对于每个脚本来说,惟一的要求就是一个数据库连接、数据库访问权限以及在屏幕上输出检索到的行。



清单 1. 简单的数据库连接,以及在 PHP 中使用 PEAR::DB 进行检索
    

require_once 'DB.php'; // must be included in any script that uses PEAR::DB
// it is a huge security risk to store your database connection information
// in the same file as your code. We have done it here solely for the purpose
// of this example. Please store your database connection information in another
// file that is not in your document root directory and adequately protected.
// database connection information
$db_host = "localhost"; // hostname of the database server
$db_user = "root"; // database user's username
$db_pass = ""; // database user's password, nothing by default
$db_name = "hello_world"; // the name of the database to connect to
$db_type = "mysql"; // the type of database server.
// your data source name string. This contains the connection
// information for your database.
$dsn = "$db_type://$db_user:$db_pass@$db_host/$db_name";
// creates a database connection object or a database error
// object based on the success of the database connection.
$db = DB::connect($dsn, TRUE);
// if an error was encountered, the script exits with an error message
if (DB::isError($db)) {
die($db->getMessage());
}
// SQL query that you wish to use to query the database
$sql = "SELECT * FROM hello_table";
// query the database, store result in $result
$result = $db->query($sql);
// exits with an error message if the query was unsuccessful
if(DB::isError($result)){
die($result->getMessage());
}
// fetch rows from the database until no more rows exist.
// output the "hello_column" field of each row to the screen.
// once no more rows exist, exit with an error message.
while($row = $result->fetchRow(DB_FETCHMODE_OBJECT)){
if(DB::isError($row)){
die($row->getMessage());
}
print("

$row->hello_column

");
$result->free();
}
$db->disconnect(); //disconnect from the database

这 两个脚本都会连接到数据库上,并检索一行数据,并将该行输出到屏幕上。PHP 的数据库访问是使用 PEAR::DB 完成的,这是一个方便的数据库抽象层,不管数据库是如何实现的,它都可以使用相同的数据库访问代码。不幸的是,XAMPP 中并没有包含一个用于 Perl 的数据库抽象层。

存放脚本

因此,现在我们已经做好了所需的一切。数据库已经启动并运行了,并且已经有了两个测试用的脚本。现在需要做的工作是将这些脚本放到正确的地方。让我们快速了解一下 XAMPP 是如何存放在硬盘上的,如 清单 2 所示。

我 们现在感兴趣的目录是 /opt/lampp/htdocs/,也就是 Apache 的 Documents 目录。在 Web 站点的根目录中显示的任何 Web 页面和相关文件都位于这个目录中。由于我们现在能够看到 XAMPP 的 welcome 页面,因此这个目录中已经存在一些文件了。现在让我们快速了解一下这个目录的内容:(输入 ls /opt/lampp/htdocs):

drwxr-xr-x 2 root root 4096 Jan 24 2003 apache
-rwxr-xr-x 1 nobody root 163 Oct 31 2003 index.html
drwxr-xr-x 2 nobody root 4096 Sep 12 21:54 webalizer
drwxr-xr-x 5 root root 4096 Jun 15 06:24 xampp

正如您可以看到的一样,这个目录中早已存在一些文件了。让我们在这个目录中建立一个自己的目录 hello_world ( mkdir hello_world)来存放脚本。从现在开始,您就可以输入 localhost/hello_world 来访问 hello_world 目录中的所有文件了。现在,将这两个脚本保存到这个目录中。到此为止,所有一切都已经完成了!

测试应用程序

要测试这个应用程序,首先切换到浏览器中,输入 localhost/hello_world。您应该会看到下面的界面:



图 4. Hello World!
Service status 页面

恭喜!您已经设置好 XAMPP 上的一个应用程序了。





回页首


增强安全性

XAMPP 的目标是一个开发环境。这种配置为程序员提供了一种对工具集没有任何限制的自由控制能力。作为自由的结果,缺省的 XAMPP 安装是非常不安全的。例如,有些操作几乎无需登录。

对于 0.9.5 以及更新版本的 XAMPP 来说,您可以运行下面的命令来增强安全性:

/opt/lampp/lampp security

此时会给出一些提示说明现有的不安全的地方,您可以选择是否修复这个问题。虽然这样可以使 XAMPP 安装更加安全,但是您仍然不应当在产品服务器中使用 XAMPP。清单 3 列出了安全性提示:



清单 3. XAMPP 中的安全性提示
    

XAMPP: Quick security check...
XAMPP: Your XAMPP pages are NOT secured by a password.
XAMPP: Do you want to set a password? [yes] yes
XAMPP: Password:
XAMPP: Password (again):
XAMPP: Password protection active. Please use 'lampp' as user name!
XAMPP: MySQL is accessable via network.
XAMPP: Normaly that's not recommended. Do you want me to turn it off? [yes] yes
XAMPP: Turned off.
XAMPP: Stopping MySQL...
XAMPP: Starting MySQL...
XAMPP: The MySQL/phpMyAdmin user pma has no password set!!!
XAMPP: Do you want to set a password? [yes] yes
XAMPP: Password:
XAMPP: Password (again):
XAMPP: Setting new MySQL pma password.
XAMPP: Setting phpMyAdmin's pma password to the new one.
XAMPP: MySQL has no root passwort set!!!
XAMPP: Do you want to set a password? [yes] yes
XAMPP: Write the password somewhere down to make sure you won't forget it!!!
XAMPP: Password:
XAMPP: Password (again):
XAMPP: Setting new MySQL root password.
XAMPP: Setting phpMyAdmin's root password to the new one.
XAMPP: The FTP password is still set to 'lampp'.
XAMPP: Do you want to change the password? [yes] yes
XAMPP: Password:
XAMPP: Password (again):
XAMPP: Reload ProFTPD...
XAMPP: Done.





回页首


执行备份

因此,假设您的 XAMPP 安装已经启动并运行了几周了,并向其中输入了很多数据,那么您就应该防范出现硬盘崩溃的风险。您需要做哪些备份工作呢?

使用 XAMPP 非常简单。将工作目录切换到 /opt/lampp ( cd /opt/lampp) 中,并输入下面的命令:

./lampp backup

如果您已经设置了 MySQL 的 root 密码,那么在这个命令后面就要添加上 root 用户的密码。您应该会看到下面的内容:

Backing up databases...
Backing up configuration, log and htdocs files...
Calculating checksums...
Building final backup file...
Backup finished.
Take care of /opt/lampp/backup/xampp-backup-15-09-04.sh

要恢复以前的备份,请以 root 用户的身份运行下面的命令:

sh backupfilename

如果一切正常,您将看到下面的结果:

Checking integrity of files...
Restoring configuration, log and htdocs files...
Checking versions...
Installed: XAMPP 1.4.7
Backup from: XAMPP 1.4.7
Restoring MySQL databases...
Restoring MySQL user databases...
Backup complete. Have fun!
You may need to restart XAMPP to complete the restore.

重新启动 XAMPP ( cd /opt/lampp, ./lampp restart),恢复的数据应该可用了。





回页首


结束语

虽然这种集成解决方案软件是否可以完全与 J2EE 竞争,尚需时日来进行验证,但是最近的发行版 PHP 5.0 (主要改进包括完全的面向对象的支持)与 MySQL 数据库的共同快速增长已经证明了它在开发人员之间越来越流行。这意味着像 XAMPP 这种开放源码中间件在低端软件市场上还是有一定的存活空间的。



参考资料

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文

  • Apache Friends 上下载 XAMPP,这是一个非盈利组织,目标是增强 Apache Web 服务器。该网站上有最新的 XAMPP 信息和发行版本。

  • PHP 简介 (developerWorks,2000 年 12 月) 可以引导您入门 PHP 脚本语言。当您阅读这篇文章时,只需在搜索域中输入“PHP”,即可查找 IBM 提供的许多丰富的 PHP 资源。

  • 更佳编程之路 系列文章 (developerWorks) 是一组优秀的系列文章,可让您更加深入地了解 Perl 语言。要想了解有关 Perl 的更多内容,请搜索 developerWorks 站点。

  • 将 PHP 应用程序连接到 Apache Derby (developerWorks,2004 年 9 月)和 使用 Apache Derby 开发 Perl 应用程序 (developerWorks,2004 年 10 月)这两篇文章是 PHP 和 Perl 开发人员必读的文章。

  • phpMyAdmin 项目 包含了很多有用的信息,并可以下载这个杰出的基于 Web 的 MySQL 管理工具。

  • Practical Unix & Internet Security (O'Reilly & Associates,1996) 是一本有关系统安全性各个方面的优秀参考书,内容涉及从用户管理到起草安全策略。

  • PHP.net 提供了一个在线的可搜索函数库,它对于查找有关 PHP 方法的详细信息和学习语言构造有很大的帮助。

  • The PHP Extension and Application Repository (PEAR) 提供了一些可以简化 PHP 编程的组件,包括非常流行的 PEAR::DB

  • 有关 MySQL 的帮助, MySQL reference manual 中包含了有关这个流行数据库各个方面的详细信息。

  • 请访问 Apache HTTP Server Project,可以找到有关 Web 的最流行 http 服务器的最新版本和信息。

  • developerWorks Linux 专区 中可以找到更多为 Linux 开发者准备的资源。

  • 从 developerWorks 的 Speed-start your Linux app 专区下载运行于 Linux 之上的 IBM 中间件产品的免费测试版本,其中包括 WebSphere® Studio Application Developer、WebSphere Application Server、DB2® Universal Database、Tivoli® Access Manager 和 Tivoli Directory Server,并可学习 how-to 文章和获得技术支持。

  • 通过参与 developerWorks blogs 来参与 developerWorks 社区的工作。

  • 在 Developer Bookstore 的 Linux 区域中购买有关 Linux 的打折书籍


关于作者


Nils-Erik Frantzell 目前在位于圣克鲁斯的加州大学学习计算机科学。他的兴趣包括 Linux、Web 编程(尤其是 PHP)、网络、开源技术以及一些计算机硬件。他的业余时间用于饲养一些食肉性的鱼和欣赏电子音乐。您可以通过 nfrantze@ucsc.edu 与 Nils-Erik 联系。