posts - 13,  comments - 3,  trackbacks - 0

DocBook与Eclipse - 教程

Lars Vogel

李墨耘


0. 翻译说明

本文翻译自Lars Vogel的DocBook with Eclipse教程, http://www.vogella.de/articles/DocBook/article.html

在翻译过程中,本人保留原文的一切链接。

原文一切权利归原作者所有,译文一切权利归本人所有。如欲转载原文,请征得作者授权。如欲转载译文,请注明本文原始链接。

本文的翻译已获得原作者授权。

1. DocBook介绍

1.1. 概要

DocBook是一种文档标准,用以创建结构化的纯文本文档。用DocBook创建的文档能够方便的在不同的操作系统之间以及不同的文本处理 工具之间进行移植,并可以通过XSLT 转为其他的输出格式。XSLT是EXtensible Stylesheet Language Transformation的缩写。 由于DocBook是使用纯文本编辑的,因此你可以使用任何一个文本 编辑器来编写DocBook,并纳入版本控制系统的管理。

目前,有多种不同的样式表,能够把DocBook文件转换为不同的输出格式,例如转换为HTML,pdf,java help以及Unix man pages.

DocBook有两种主要的文档,一种是book,另一种是article。其中

  • Article: 用来写一些技术文章,下文都以article为例。article通常是由一系列的section组成。

  • Book: 用来写一些更长的描述。book比article多了一种结构:chapter。

 

1.2. 实例

下面就是一个DocBook文档的例子。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "../docbook-xml-4.5/docbookx.dtd">
<article>
<articleinfo>
<title>DocBook Intro</title>
<author>
<firstname>Lars</firstname>
<surname>Vogel</surname>
</author>
</articleinfo>
<sect1 label="1.0">
<title>An introduction to DocBook</title>
<para>
This is text.
</para>
</sect1>
</article>

Note

请注意,在上面的例子中,DTD文件的位置:当前目录的上一级目录,其中的docbook-xml-4.5文件夹内。

1.3. 所需的工具

想要创建DocBook文件并转换成其他格式,你需要以下工具:

  • DocBook的DTD文件。这个文件定义了DocBook文档的格式。

  • XSLT样式表,用来把DocBook文档转换成其他格式。

  • XSLT解析器

我们使用Eclipse 作为XML编辑器,Xalan作为XSLT解析器,并使用 Apache Ant 来进行XSLT的转换。

2. 安装

2.1. Eclipse

你需要安装Eclipse,可以参看这篇文章 Eclipse IDE 来学习Eclipse的安装和使用。我们需要用到的Ant已经被集成到Eclipse里面了,因此关于Ant我们不需要安装任何额外的东西。

2.2. Docbook和样式表

你还需要下载Docbook的DTD,以及用来转换的Docbook文档的样式表。Docbook的DTD可以在 http://www.oasis-open.org/docbook/xml/4.5下载, 而XSLT样式表可以在 http://docbook.sourceforge.net/ 下载。在写这篇文档时,最新的版本是“1.75.2”(译者注:在翻译这篇文档时,最新的版本是1.76.1)。你需要下载的docbook-xsl的发布文件, 例如“docbook-xsl-1.75.2.zip”。

2.3. XSL处理器

要命的是JVM自带的XSL处理器在处理XSLT样式表的时候有问题……所以我们需要从 http://xml.apache.org/xalan-j/ 下载Xalan,用来作为我们的XSL处理器。

3. 把Docbook转换为HTML

3.1. 工程设置

可以在Eclipse中,创建一个"de.vogella.docbook.first"的新工程,方法是File -> New -> Project,并从弹出的 窗口中选择General -> Projects.

在工程中创建如下的目录结构:

  • output : Docbook转换成其他格式时的输出目录

  • docbook-xml-4.5: 用来放Docbook的DTD定义文件

  • docbook-xsl: 用来放进行Docbook转换的样式表文件

  • lib: 用来包含你需要的库文件(用来创建pdf)

  • documents: 用来放你的DocBook文件

把DocBook的DTD和XSLT的样式表放入相应的文件夹中。

在lib文件夹下创建xalan文件夹,并把xalan相关的jar包拷入这个文件夹中。 结果应该看起来是这样的:

project

3.2. 第一个Docbook文档

在“documents”文件夹里面,创建一个“book.xml”文件,并输入下面的xml文件

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "../docbook-xml-4.5/docbookx.dtd">
<article>
<articleinfo>
<title>DocBook Intro</title>
<author>
<firstname>Lars</firstname>
<surname>Vogel</surname>
</author>
</articleinfo>
<sect1 label="1.0">
<title>An introduction to DocBook</title>
<para>
This is text.
</para>
</sect1>
</article>

在xml文件中,“../docbook-xml-4.5/docbook.dtd”对应于我们刚刚创建的文件夹以及放入的DTD文件。

3.3. 使用Ant把Docbook转换为HTML格式

接下来我们配置ANT。在工程目录中,创建build.xml文件如下:

<?xml version="1.0"?>
<!--
- Author: Lars Vogel
-->
<project name="docbook-src" default="build-html">
<description>
This Ant buildhtml.xml file is used to transform DocBook XML to html output
</description>
<!--
- Configure basic properties that will be used in the file.
-->
<property name="docbook.xsl.dir" value="docbook-xsl" />
<property name="doc.dir" value="output" />
<property name="documents" value="documents" />
<property name="html.stylesheet" value="${docbook.xsl.dir}/html/docbook.xsl" />
<!-- Making xalan available -->
<path id="xalan.class.path">
<pathelement location="lib/xalan/serializer.jar" />
<pathelement location="lib/xalan/xalan.jar" />
<pathelement location="lib/xalan/xercesImpl.jar" />
<pathelement location="lib/xalan/xml-apis.jar" />
</path>
<!--
- target: usage
-->
<target name="usage" description="Prints the Ant build.xml usage">
<echo message="Use -projecthelp to get a list of the available targets." />
</target>
<!--
- target: clean
-->
<target name="clean" description="Cleans up generated files.">
<delete dir="${doc.dir}" />
</target>
<!--
- target: depends
-->
<target name="depends">
<mkdir dir="${doc.dir}" />
</target>
<!--
- target: build-html
- description: Iterates through a directory and transforms
- .xml files into .html files using the DocBook XSL.
-->
<target name="build-html" depends="depends" description="Generates HTML files from DocBook XML">
<xslt style="${html.stylesheet}" extension=".html" basedir="${documents}" destdir="${doc.dir}">
<include name="**/*book.xml" />
<include name="**/*article.xml" />
<param name="html.stylesheet" expression="style.css" />
<classpath refid="xalan.class.path" />
</xslt>
<!-- Copy the stylesheet to the same directory as the HTML files -->
<copy todir="${doc.dir}">
<fileset dir="lib">
<include name="style.css" />
</fileset>
</copy>
</target>
</project>

运行build.xml文件(右键 -> Run As -> Ant Build)。运行之后,在你的output文件夹里面, 应该已经有一个“book.html”了。

恭喜你完成了第一个Docbook文档,并顺利的转成了HTML格式!

4. Docbook examples

下面是一些使用Docbook标签的概览。

4.1. 标签

Table 1. Docbook一些重要的标签

Tag 说明
<![CDATA[ 此处可输入特殊字符,e.g. & ]]> 在标签中可以输入某些特殊字符,例如某些xml以及Docbook的特殊字符。
<programlisting> </programlisting> 表示该文本是程序代码
<emphasis> </emphasis> 表示用强调(Highlight)该文本
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="example1.txt" /> 包含example1.xml的内容。该文件可以是一个独立的xml文件
<ulink url="http://www.heise.de/newsticker">German IT News</ulink> [a] 在文档中创建一个超链接
&amp; 在文档中插入“&”符号

[a] 译者注:Docbook5改变了超链接的格式。关于Docbook5以及更详细的Eclipse配置Docbook教程,会很快放出。 不过,即使是在Docbook5的环境下,使用ulink一样可以顺利的用XSLT转换,只不过Eclipse的xml编辑器会提示有错误。

4.2. 表格

下面是一个创建表格的例子

<table frame='all'>
<title>Sample Table</title>
<tgroup cols='2' align='left' colsep='1' rowsep='1'>
<colspec colname='c1' />
<colspec colname='c2' />
<thead>
<row>
<entry>a4</entry>
<entry>a5</entry>
</row>
</thead>
<tfoot>
<row>
<entry>f4</entry>
<entry>f5</entry>
</row>
</tfoot>
<tbody>
<row>
<entry>b1</entry>
<entry>b2</entry>
</row>
<row>
<entry>d1</entry>
<entry>d5</entry>
</row>
</tbody>
</tgroup>
</table>

生成的表格看起来是这样的

Table 2. Sample Table

a4 a5
f4 f5
b1 b2
d1 d5

4.3. 列表

没有序号的列表可以这样创建:

<itemizedlist>
<listitem>
<para>Item1</para>
</listitem>
<listitem>
<para>Item2</para>
</listitem>
<listitem>
<para>Item3</para>
</listitem>
<listitem>
<para>Item4</para>
</listitem>
</itemizedlist>

输出结果如下:

  • Item1

  • Item2

  • Item3

  • Item4

而带编号的列表可以这样写:

<orderedlist>
<listitem>
<para>This is a list entry</para>
</listitem>
<listitem>
<para>This is another list entry</para>
</listitem>
</orderedlist>

输出结果如下:

  1. This is a list entry

  2. This is another list entry

4.4. 链接

链接可以用下面的方法来创建:[a]

<para>
We use the Ant integrated into Eclipse. See
<ulink url="http://www.vogella.de/articles/ApacheAnt/article.html"> Apache Ant Tutorial</ulink>
for an introduction into Apache Ant.
</para>

4.5. 插入图片

插入图片可以使用下面的方式。

<para>
<mediaobject>
<imageobject>
<imagedata fileref="images/antview10.gif" format="gif">
</imagedata>
</imageobject>
</mediaobject>
</para>

5. 创建pdf输出

5.1. 安装

Docbook转成pdf的过程是:先由docbook转成XSL-FO格式,再利用Apache FOP把FO转成 pdf。因此,我们首先需要Apache FOP相关的库。

XML FO,是XML Formating Object的意思,FO格式是一种处理打印、印刷介质的XML标准。

可以从http://xmlgraphics.apache.org/fop/下载FOP的最新版本。

从下载的FOP发行版中,把所有的jar文件都拷贝到你的lib文件夹中,并把这些库都加入到ant 的build path中。可以参考 Apach Ant Tutorial来修改ant的build path。

5.2. 定义Ant Task

要在ant中使用fop,我们首先应当定义一个fop相关的ant task,然后在后面的脚本中使用这个任务。 下面的这个例子演示了怎样定义一个ant task并怎样调用。第二个例子是一个完整的build.xml文件的例子。

<!--
- Defines the ant task for fop
-->
<taskdef name="fop" classname="org.apache.fop.tools.anttasks.Fop" />
<!-- Transformation into pdf
- Two steps
- 1.) First create the FO files
- 2.) Then transform the FO files into pdf files
-->
<!--
- target: build-pdf
- description: Iterates through a directory and transforms
- .xml files into .fo files using the DocBook XSL.
-->
<target name="build-pdf" depends="depends, xinclude"
description="Generates HTML files from DocBook XML">
<!-- Convert DocBook Files into FO -->
<xslt style="${fo.stylesheet}" extension=".fo" basedir="${src.tmp}"
destdir="${src.tmp}">
<include name="**/*book.xml" />
<include name="**/*article.xml" />
<param name="section.autolabel" expression="1" />
</xslt>
<!-- Convert FO Files into pdf -->
<fop format="application/pdf" outdir="${doc.dir}">
<fileset dir="${src.tmp}">
<include name="**/*.fo" />
</fileset>
</fop>
</target>
<?xml version="1.0"?>
<!--
- Author: Lars Vogel
-->
<project name="docbook-src" default="all">
<description>
This Ant build.xml file is used to transform DocBook XML to
various output formats
</description>
<!--
- Defines the ant task for xinclude
-->
<taskdef name="xinclude" classname="de.vogella.xinclude.XIncludeTask" />
<!--
- Defines the ant task for xinclude
-->
<taskdef name="fop" classname="org.apache.fop.tools.anttasks.Fop" />
<!--
- Configure basic properties that will be used in the file.
-->
<property name="javahelp.dir" value="${basedir}/../Documentation/output/vogella/javahelp" />
<property name="src" value="${basedir}/documentation" />
<property name="output.dir" value="${basedir}/../Documentation/output/vogella/articles" />
<property name="output.tmp" value="${basedir}/output.tmp" />
<property name="lib" value="${basedir}/lib/" />
<property name="docbook.xsl.dir" value="${basedir}/docbook-xsl-1.72.0" />
<property name="xinclude.lib.dir" value="${basedir}/lib/" />
<!--
- Usage of the differect style sheets which will be used for the transformation
-->
<property name="eclipse.stylesheet" value="${docbook.xsl.dir}/eclipse/eclipse.xsl" />
<property name="html.stylesheet" value="${docbook.xsl.dir}/html/docbook.xsl" />
<property name="fo.stylesheet" value="${docbook.xsl.dir}/fo/docbook.xsl" />
<property name="javahelp.stylesheet" value="${docbook.xsl.dir}/javahelp/javahelp.xsl" />
<property name="chunk-html.stylesheet" value="${docbook.xsl.dir}/html/chunk.xsl" />
<!--
- target: usage
-->
<target name="usage" description="Prints the Ant build.xml usage">
<echo message="Use -projecthelp to get a list of the available targets." />
</target>
<!--
- target: clean
-->
<target name="clean" description="Cleans up generated files.">
<delete dir="${output.dir}" />
</target>
<!--
- target: depends
-->
<target name="depends">
<mkdir dir="${output.dir}" />
</target>
<!--
- target: copy
- Copies the images from the subdirectories to the target folder
-->
<target name="copy">
<echo message="Copy the images" />
<copy todir="${output.dir}">
<fileset dir="${src}">
<include name="**/images/*.*" />
</fileset>
</copy>
</target>
<!--
- target: xinclude
- description: Creates one combined temporary files for the different inputs files.
- The combined file will then be processed via different ant tasks
-->
<target name="xinclude">
<xinclude in="${src}/DocBook/article.xml" out="${output.tmp}/DocBook/article.xml" />
<xinclude in="${src}/JavaConventions/article.xml" out="${output.tmp}/JavaConventions/article.xml" />
<xinclude in="${src}/JUnit/article.xml" out="${output.tmp}/JUnit/article.xml" />
<xinclude in="${src}/EclipseReview/article.xml" out="${output.tmp}/EclipseReview/article.xml" />
<xinclude in="${src}/HTML/article.xml" out="${output.tmp}/HTML/article.xml" />
<xinclude in="${src}/Eclipse/article.xml" out="${output.tmp}/Eclipse/article.xml" />
<xinclude in="${src}/Logging/article.xml" out="${output.tmp}/Logging/article.xml" />
<!--
<xinclude in="${src}/ant/article.xml" out="${src.tmp}/ant/article.xml" />
-->
</target>
<!--
- target: build-html
- description: Iterates through a directory and transforms
- .xml files into .html files using the DocBook XSL.
-->
<target name="build-html" depends="depends, xinclude" description="Generates HTML files from DocBook XML">
<xslt style="${html.stylesheet}" extension=".html" basedir="${output.tmp}" destdir="${output.dir}">
<include name="**/*book.xml" />
<include name="**/*article.xml" />
<param name="html.stylesheet" expression="styles.css" />
<param name="section.autolabel" expression="1" />
<param name="html.cleanup" expression="1" />
<outputproperty name="indent" value="yes" />
</xslt>
<!-- Copy the stylesheet to the same directory as the HTML files -->
<copy todir="${output.dir}">
<fileset dir="lib">
<include name="styles.css" />
</fileset>
</copy>
</target>
<!--
- target: build-javahelp
- description: Iterates through a directory and transforms
- .xml files into .html files using the DocBook XSL.
-->
<target name="build-javahelp" depends="depends, xinclude" description="Generates HTML files from DocBook XML">
<xslt style="${javahelp.stylesheet}" extension=".html" basedir="${output.tmp}" destdir="${javahelp.dir}">
<include name="**/*book.xml" />
<include name="**/*article.xml" />
<outputproperty name="indent" value="yes" />
</xslt>
</target>
<!--
- target: chunks-html
- description: Iterates through a directory and transforms
- .xml files into seperate .html files using the DocBook XSL.
-->
<target name="build-chunks" depends="depends, xinclude" description="Generates chunk HTML files from DocBook XML">
<xslt style="${html.stylesheet}" extension=".html" basedir="${output.tmp}" destdir="${output.dir}">
<include name="**/*book.xml" />
<include name="**/*article.xml" />
<param name="html.stylesheet" expression="styles.css" />
<param name="section.autolabel" expression="1" />
<param name="html.cleanup" expression="1" />
<param name="chunk.first.selection" expression="1" />
</xslt>
<!-- Copy the stylesheet to the same directory as the HTML files -->
<copy todir="${output.dir}">
<fileset dir="lib">
<include name="styles.css" />
</fileset>
</copy>
</target>
<!-- Transformation into pdf
- Two steps
- 1.) First create the FO files
- 2.) Then transform the FO files into pdf files
-->
<!--
- target: build-pdf
- description: Iterates through a directory and transforms
- .xml files into .fo files using the DocBook XSL.
- Relativebase is set to true to enable FOP to find the graphics which are included
- in the images directory
-->
<target name="build-pdf" depends="depends, xinclude" description="Generates HTML files from DocBook XML">
<!-- Convert DocBook Files into FO -->
<xslt style="${fo.stylesheet}" extension=".fo" basedir="${output.tmp}" destdir="${output.tmp}">
<include name="**/*book.xml" />
<include name="**/*article.xml" />
<param name="section.autolabel" expression="1" />
</xslt>
<!-- Convert FO Files into pdf -->
<fop format="application/pdf" outdir="${output.dir}" relativebase="true">
<fileset dir="${output.tmp}">
<include name="**/*.fo" />
</fileset>
</fop>
</target>
<!--
- target: chunks-html
- description: Iterates through a directory and transforms
- .xml files into seperate .html files using the DocBook XSL.
-->
<target name="build-eclipse" depends="depends, xinclude" description="Generates Eclipse help files from DocBook XML">
<xslt style="${eclipse.stylesheet}" basedir="${output.tmp}" destdir="${output.dir}">
<include name="**/*book.xml" />
<include name="**/*article.xml" />
</xslt>
</target>
<target name="all" depends="copy, build-html, build-pdf, build-chunks, build-eclipse">
</target>
</project>

7. 控制输出格式

我们可以通过修改XSLT样式表的参数来影响输出的结果。下面其中一些参数的介绍。

7.1. HTML参数

Table 3. HTML参数

参数 说明
name="section.autolabel" expression="1" 为section自动编号(例如,第一个section是1,其下一集的section是1.1,以此类推)
name="chapter.autolabel" expression="1" 为chapter自动编号
name="html.stylesheet" expression="styles.css" 定义html使用的样式表
name="html.cleanup" expression="1" 清理html使之更具可读性

7.2. 为html增加内容

Docbook允许在转换成html的时候,导入并包含一个外部的html文件。你可以使用这种技术,在生成 html的时候向其中插入javascript代码。

下面是一个包含html文件的例子。

 <?dbhtml-include href="../../myadditonalcontent.html"?>

Inserting external HTML code 有更多的描述。

7. 用Eclipse XSL完成XInclude功能

7.1. 概述

XInclude技术能帮你重新组织你的docbook文件。你可以在书写每一个章节的时候,都使用 一个单独的xml文件,然后用一个总的xml文件把这些章节都组合起来。简单的说,XInclude 能把不同的xml文件组合成为一个大的xml文件。

例如,假设你要引入一个“foo.xml”文件,则可以写成:

 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="foo.xml" />

下面这个例子是要把导入的文件当做文本: [1]

<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="bar.xml" />

Eclipse XSL project提供一个XInclude的ant task。在此,我很自豪的告诉各位:这个ant task是我提供给XSL project 的:)

7.2. Eclipse XSL工具

Eclipse XSL工具提供了对XSLT的支持,包括XSL的编辑以及debug的支持。虽然我们这里仅仅使用其中的ant task, 但还是得完整的安装整个包。

安装XSL工具可以通过Eclipse的update manager完成。 [2] 你可以通过 Using the Eclipse update manager 来获得更多信息。

installxsl

7.3. 在Ant中使用XInclude

在你的Eclipse安装路径中找到“org.eclipse.wst.xsl.core.jar”并把这个jar包加入到ANT的classpath中。 这样,你应该就可以创建和运行xinclude tast了。下面是一个build.xml文件的例子:

<?xml version="1.0"?>
<!--
- Author: Lars Vogel
-->
<project name="docbook-src" default="usage">
<description>
This Ant build.xml file is used to transform DocBook XML to various
output formats
</description>
<!--
- Configure basic properties that will be used in the file.
-->
<property name="doc.dir" value="${basedir}/output" />
<property name="src" value="${basedir}/src" />
<property name="src.tmp" value="${basedir}/src.tmp" />
<property name="lib" value="${basedir}/lib/" />
<property name="docbook.xsl.dir" value="${basedir}/docbook-xsl-1.72.0" />
<property name="html.stylesheet" value="${docbook.xsl.dir}/html/docbook.xsl" />
<property name="xinclude.lib.dir" value="${basedir}/lib/" />
<!--
- target: usage
-->
<target name="usage" description="Prints the Ant build.xml usage">
<echo message="Use -projecthelp to get a list of the available targets." />
</target>
<!--
- target: clean
-->
<target name="clean" description="Cleans up generated files.">
<delete dir="${doc.dir}" />
</target>
<!--
- target: depends
-->
<target name="depends">
<mkdir dir="${doc.dir}" />
</target>
<!--
- target: xinclude
- description: Creates one combined temporary files for the different inputs files.
- The combined file will then be processed via different ant tasks
-->
<target name="xinclude">
<xsl.xinclude in="${src}/DocBook/article.xml" out="${src.tmp}/DocBook/article.xml" />
</target>
<!--
- target: build-html
- description: Iterates through a directory and transforms
- .xml files into .html files using the DocBook XSL.
-->
<target name="build-html" depends="depends, xinclude" description="Generates HTML files from DocBook XML">
<xslt style="${html.stylesheet}" extension=".html" basedir="${src.tmp}" destdir="${doc.dir}">
<include name="**/*book.xml" />
<include name="**/*article.xml" />
<param name="html.stylesheet" expression="styles.css" />
</xslt>
<!-- Copy the stylesheet to the same directory as the HTML files -->
<copy todir="${doc.dir}">
<fileset dir="lib">
<include name="styles.css" />
</fileset>
</copy>
</target>
</project>


[1] 译者注:这块儿没看明白,哪位高人指点一下?

[2] 译者注:XSL工具被包含在WTP(Web Develop Platform)中。 如果你装的Eclipse是J2EE版本,很可能这个工具在你的Eclipse上已经有了。

posted @ 2011-08-07 02:00 Antony Lee 阅读(2096) | 评论 (2)编辑 收藏
     摘要: Core Python Programming学习笔记7 - if, 循环,迭代器,列表解析,生成器解析  阅读全文
posted @ 2011-06-13 15:40 Antony Lee 阅读(193) | 评论 (0)编辑 收藏
     摘要: Core Python Programming 学习笔记6 - Mapping and Set  阅读全文
posted @ 2011-06-10 15:23 Antony Lee 阅读(444) | 评论 (1)编辑 收藏
     摘要: Core Python Programming学习笔记5 - 字符串,列表,元组  阅读全文
posted @ 2011-06-09 12:20 Antony Lee 阅读(800) | 评论 (0)编辑 收藏
     摘要: Core Python Programming 学习笔记4 - 数字相关  阅读全文
posted @ 2011-06-09 12:17 Antony Lee 阅读(221) | 评论 (0)编辑 收藏
     摘要: Core Python Programming 学习笔记(3)  阅读全文
posted @ 2011-03-15 22:15 Antony Lee 阅读(309) | 评论 (0)编辑 收藏
     摘要: Core Python Programming 2 学习笔记(2)  阅读全文
posted @ 2011-03-13 22:30 Antony Lee 阅读(229) | 评论 (0)编辑 收藏
     摘要: Core Python学习笔记(一) : Python基础  阅读全文
posted @ 2011-03-13 20:50 Antony Lee 阅读(286) | 评论 (0)编辑 收藏
     摘要: 速成Java与XML系列文章之一
本文介绍XML的基础知识和概念,是用Java进行XML解析的基础。  阅读全文
posted @ 2011-01-09 16:12 Antony Lee 阅读(508) | 评论 (0)编辑 收藏

我会争取在近期用Python写个图形界面。之所以现在不写,是因为现在我还不会……

原理很简单,就是用程序去获得腾讯星座网站的源码,然后简单解析一下就可以了。原来试图用dom解析,结果发现腾讯和新浪的网站都会解析出错,一狠心干脆直接用字符串的替换。

Java那个程序的功能多一些,写了读取“明天”、“本周”、“下周”、“本月”、“下月”的功能,主函数中提供了读取“明天”的功能,默认会在当前工作目录下生成“yuncheng_XXX.txt”文件。实在懒得写客户端了,甚至于命令行客户端都不想写了,因为昨天写这个破东西写到了11点半,原以为很简单的呢,结果郁闷坏了。真是水平大幅度下滑啊。

今天晚上用python写了一个程序,这是我用Python写的第一个程序哟~~(如果不算helloworld的话。。。)这个程序功能比较简单,只能获得明日运程。

刚刚写出来而已,注释很乱,代码很乱。写这篇博客只是因为母鸡心态:好歹有了个新东西了,怎么也得让我叫唤两声吧。

下载地址:

http://www.rayfile.com/files/bc9485dc-88e8-11de-b777-0014221f469f/
posted @ 2009-08-15 00:32 Antony Lee 阅读(542) | 评论 (0)编辑 收藏
最近在学习Spring。某大人跟我说,Spring的AOP其实就是Java反射中的动态代理。OK,那我就从动态代理开始看起。

一、基本概念
所谓动态代理,基本上是如下场景:假设我有个接口IHelloWorld

public interface IHelloWorld{
void sayHello();
}


我再有一个实现类HelloWorldImpl实现了IHelloWorld接口
public class HelloWorldImpl implements IHelloWorld{
public void sayHello(){
System.out.println(
"Hello, World");
}
}


这样,我就可以创建一个HelloWorldImpl对象,来实现IHelloWorld中定义的服务。

 问题是,现在,我打算为HelloWorldImpl增强功能,需要在调用sayHello方法前后各执行一些操作。在有些情况下,你无法修改HelloWorldImpl的源代码,那怎么办呢?
从道理上来说,我们可以拦截对HelloWorldImpl对象里sayHello()函数的调用。也就是说,每当有代码调用sayHello函数时,我们都把这种调用请求拦截下来之后,做自己想做的事情。

 那怎么拦截呢?

 首先,需要开发一个InvocationHandler。这个东东表示的是,你拦截下函数调用之后,究竟想干什么。InvocationHandler是一个接口,里面的声明的函数只有一个:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
这个函数表示一次被拦截的函数调用。因此,proxy表示这个被拦截的调用,原本是对哪个对象调用的;method表示这个被拦截的调用,究竟是调用什么方法;args表示这个被拦截的调用里,参数分别是什么。

 我们下面写一个拦截器,让他在函数调用之前和之后分别输出一句话。

import java.lang.reflect.*;

public class HelloHandler implements InvocationHandler{
Object oriObj;

public HelloProxy(Object obj){
oriObj 
= obj;
}

public Object invoke(Object proxy, Method m, Object[] args) throws Throwable{
Object result 
= null;

//在函数调用前输出一些信息
    System.out.println("################################");
String methodName 
= m.getName();
System.out.println(
"method name : " + methodName);
doBefore();

//利用反射,进行真正的调用
    result = m.invoke(oriObj, args);

//在函数调用后执行
    doAfter();
System.out.println(
"################################");
return result;
}

public void doBefore(){
System.out.println(
"Do Before");
}
public void doAfter(){
System.out.println(
"Do After");
}
}

 有了这个Handler之后,下面要做的,就是把这个Handler和一个IHelloWorld类型的对象装配起来。重点的函数只有一个,那就是java.lang.reflect.Proxy类中的一个静态工厂方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
这个方法返回一个对象,我们称返回的对象为代理对象(proxy)。
而后,我们就不把真正的原对象暴露给外接,而使用这个代理对象。这个代理对象接受对源对象的一切函数调用(也就是把所有调用都拦截了),然后根据我们写的InvocationHandler,来对函数进行处理。

 产生代理对象的过程,我把它理解成一个装配的过程:由源对象、源对象实现的接口、InvocationHandler装配产生一个代理对象。

 相应的测试代码如下:

public class TestHello{
public static void main(String args[])throws Exception{
HelloWorldImpl h 
= new HelloWorldImpl();

Object proxy 
= Proxy.newProxyInstance(
h.getClass().getClassLoader(),
new Class[]{IHelloWorld.class},
new HelloProxy(h)
);
((IHelloWorld)proxy).sayHello();
}
}

 利用ant编译运行的结果:
[java] ################################
[java] method name : sayHello
[java] Do Before
[java] Hello, World
[java] Do After
[java] ################################


二、更多理解
我们看产生代理对象的newProxyInstance函数的声明:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

 这个函数的第一个参数是ClassLoader,第三个参数是InvocationHandler,基本都没什么问题。
第二个参数是一个Class类型的数组,名字叫interfaces,表示的是产生的动态代理对象实现的接口。

 仔细想想,有两个问题。第一,产生一个代理对象,需要源对象么?第二,我能不能产生一个动态代理对象,来实现源对象没有实现的接口?

 第一个问题和第二个问题其实是一致的。我们完全可以脱离源对象,而直接产生一个代理对象,也可以利用动态代理,让源对象实现更多的接口,为源对象增强功能。

 例如,假设我们希望让源对象实现java.io.Closeable接口,则首先修改一下我们的Handler的invoke方法,让他在获取colse方法时,不要传递给源对象(因为源对象没有实现该方法):

public Object invoke(Object proxy, Method m, Object[] args) throws Throwable{
Object result 
= null;

//在函数调用前输出一些信息
  System.out.println("################################");
String methodName 
= m.getName();
System.out.println(
"method name : " + methodName);
doBefore();

//判断是否是Closeabled的方法
  if (m.getDeclaringClass().isAssignableFrom(java.io.Closeable.class)){
System.out.println(
"I got the close() method!");
}
else{
//传递给源对象
//利用反射,进行真正的调用
    result = m.invoke(oriObj, args);
}

//在函数调用后执行
  doAfter();
System.out.println(
"################################");
return result;
}

 然后,我们在装配的过程中,改变一下参数,并强转之后调用一下close方法:

Object proxy = Proxy.newProxyInstance(
h.getClass().getClassLoader(),
new Class[]{IHelloWorld.class,java.io.Closeable.class},
new HelloProxy(h)
);
((Closeable)proxy).close();

 ant运行结果:
[java] ################################
[java] method name : close
[java] Do Before
[java] I got the close() method!
[java] Do After
[java] ################################

三、更多的代理~
我们现在能够让sayHello()函数执行之前和之后,输出一些内容了。那如果我还想在装配一个Handler呢?
最简单的方法:

Object proxy = Proxy.newProxyInstance(
h.getClass().getClassLoader(),
new Class[]{IHelloWorld.class, java.io.Closeable.class},
new HelloProxy(h)
);
Object proxy2 
= Proxy.newProxyInstance(
h.getClass().getClassLoader(),
new Class[]{IHelloWorld.class, java.io.Closeable.class},
new HelloProxy(proxy)
);
((IHelloWorld)proxy2).sayHello();

ant运行结果:
[java] ################################
[java] method name : sayHello
[java] Do Before
[java] ################################
[java] method name : sayHello
[java] Do Before
[java] Hello, World
[java] Do After
[java] ################################
[java] Do After
[java] ################################

不用我解释了吧!

posted @ 2009-03-02 22:28 Antony Lee 阅读(512) | 评论 (0)编辑 收藏

和人讨论设计模式的时候,看到这样一句话:

         
大阿亮<yighter@qq.com> 22:24:40
java扩展功能就是继承和组合。肯定结构都很相似。模式思想都是从解决问题背景和目的来区分的。

恍然大悟。原来,很多情况下,所谓设计模式,是对同一种技术、实现的不同角度的理解。

所以,设计无所谓好坏,只要能解决问题的,就是好设计。至于所谓“强耦合”,“Bad Smell”,本质上是因为采用这些设计无法解决问题(就是无法快速应对需求变化)。

“不管黑猫白猫,只要能抓住耗子,就是好猫”,这句话蕴含着深刻的设计思想。

 

posted @ 2009-02-28 23:31 Antony Lee 阅读(130) | 评论 (0)编辑 收藏

在啃《The Java Programming Language 4th Edition》时看到的一个小知识点。先描述一下问题。

一个类中,静态初始代码块中的代码会在类加载时自动运行。考虑下面这种情况:

ClassA定义了静态初始代码块,其中调用了ClassB的一个方法m(静态非静态均可)。而在ClassB的m方法中,又使用了ClassA类的信息。则,当虚拟机在没有ClassB类的情况下,加载ClassA类时,会遇到这样一条线索:

加载ClassA --> 调用ClassA的静态初始化代码块 --> 调用ClassB的m方法 --> 加载ClassB --> 使用ClassA的信息

注意这条线索的一头一尾,我们要在对ClassA还没完成加载时,使用ClassA的信息!

示例代码:

 1public class TestStaticInit{
 2 public static void main(String args[]){
 3  ClassA a= new ClassA();
 4 }

 5}

 6
 7class ClassA{
 8 static int a1;
 9 static int a2;
10 static{
11  a1 = 10;
12  ClassB.print();
13  a2 = 30;
14 }

15}

16
17class ClassB{
18 public static void print(){
19  System.out.println(ClassA.a1);
20  System.out.println(ClassA.a2);
21 }

22}

23
24

 

首先,编译器无法解决这个问题,因为在编译ClassA类时,无法找到ClassB的代码,也就无法检查是否存在静态初始化代码块循环问题。事实上,上述程序在java中是能够编译通过的。

其次,运行时的结果。当程序运行到第3行时,JVM加载ClassA类,此时,会执行ClassA类中的静态初始化代码块。当程序执行到第12行时,调用ClassB的print方法,此时,程序跳转到18行。

关键在这儿:此时的print方法需要调用ClassA的信息,并打印其静态属性。而ClassA的信息正在加载过程中。此时,JVM采用的策略是:在print方法中使用ClassA不完整的信息。在print方法中ClassA的信息,是在第12行对ClassB.print方法之前的信息。此时ClassA.a1已经被赋值为10,而ClassA.a2还未被赋值,它的值为默认值。因此,最后打印出的是10、0。

posted @ 2009-01-05 23:48 Antony Lee 阅读(418) | 评论 (0)编辑 收藏

<2009年1月>
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

常用链接

留言簿(1)

随笔分类

随笔档案

文章分类

搜索

  •  

最新评论

阅读排行榜

评论排行榜