当前页面: 开发资料首页 → Eclipse 专题 → 使用 XML: 使用 XML:集成 XM 和 Eclipse
摘要: 作家和专栏写作者 Beno?t Marchal 对 Eclipse 和插件 API 学习得越多,就越喜欢他所了解的内容。在本专栏文章中,Beno?t 将其正在进行的项目继续放在集成 XM(基于 XML 和 XSLT 的简单内容管理和发布解决方案)和 Eclipse(一个开放源码项目,用来定义针对 Java 开发人员的下一代集成开发环境)之上。当 XM 从 IDE 启动时,他的努力得到了回报。有个意外的收获,Beno?t 发现了工具箱中早已隐藏的基本 XML 编辑器!
Eclipse 是出色的集成开发环境(IDE),因为它促进了可扩展的体系结构。Eclipse 认识到现代开发需要许多技能。它不再满足于仅仅使用 Java 或HTML 或C++。现代的 IDE 需要支持所有这些语言以及其它一些语言。
为满足这一需要,Eclipse 使用插件。插件扩展了 IDE,以支持新的语言、编译器以及其它开发工具。在 Eclipse 中没有缺省语言。Eclipse 通过插件支持每种语言 - 包括 Java 语言。因此,倘若您编写适当的插件,那么 Eclipse 所能支持的语言数目是没有限制的。正如我通过此项目发现的,编写 Eclipse 插件并不是那么困难。要从 Eclipse 启动 XM,我只需编写两个类。对于开发人员,这是个特棒的消息。根据我的经验,无论供应商在工具箱中包括了什么 - 不管它是自产的实用程序、第三方工具或是软件管理 - 我始终需要其它工具。
任何 IDE 都可以启动外部工具,但是这往往意味着我必须在 IDE 和外部工具之间来回切换。我确信使用 Eclipse 可以将工具集成到 IDE 中并且有条理地组织每样东西。要学习如何编写这样的插件,请继续阅读。
向 Eclipse 开发团队脱帽致敬 - 我开始非常喜欢你们的工作了。
XM 背景知识
距离我上次在本专栏讨论 XM 已有很长时间了。从我所收到的邮件来看,一些读者对它究竟是什么产生了误解。XM 是用于发布使用 XML 和 XSLT 的静态网站的低成本解决方案。它和 WebSphere Portal 或 Cocoon 并非竞争关系。我发起 XM 是因为我发现用于 XML 发布的简单解决方案很缺乏,对此深感不便。
大多数发布项目最后都发展到同一个终点:它们需要应用程序服务器,但并不是每个项目一开始就有数量巨大的文档。XM 旨在在早期阶段帮助您。例如,撰写这篇专栏文章时,我刚访问一个 XM 新用户后回来。这个组织大约有 400 个极少更新的简单 XML 文档。它们的样式表长度少于 100 行。那么,仅仅为了发布这 400 个文档而获取并安装成熟的应用程序服务器有意义吗?我认为没什么意义,而他们也持相同观点。目前,每个晚上批处理运行 XM 更有意义。显然,当他们更熟悉 XML 时,他们会想要功能更强大的解决方案,但是现在 XM 满足了他们的需求,它也满足了许多小到中型网站的需求。
为 XM 编写插件
编写 Eclipse 插件时,第一步是决定扩展哪个元素。插件可以扩展导航器或概述文件、添加菜单项、替换编辑器或绘制新的控制台和状态窗口。
如图 1 所示,我决定从将新的 Run XM项添加到导航器的弹出菜单开始。我还添加了新的 XM Console窗口来显示状态消息。通过这两个添加,有可能不用离开 Eclipse 窗口就可使用 XM。
这儿有个难题是确定何时显示
Run XM 菜单。在 XM 开发的较早时期,我选择了消除配置文件。遗憾的是,没剩下什么可以在上面单击鼠标右键了。因此,第一步是定义
.xmp
(XM 项目)文件。配置插件以使
Run XM 和
.xmp
文件相关联。
简而言之,
.xmp
文件是带有以下四个特性的 Java 特性文件,这四个特性对应于命令行参数(请参阅
清单 1,以获取示例):
source
:指向源目录(缺省值:
src
)
publish
:指向发布或目标目录(缺省值:
publish
)
rules
:指向样式表目录(缺省值:
rules
)
build
:为
true
或
false
值 -
true
强制执行重新构建,其中,XM 处理每个文件(缺省值:
false
)
# this publishes the ananas.org site
source=src
publish=ananas-html
rules=style-sheet
build=false
</td></tr></table>XM 控制台
XM 控制台是在
MessengerView
中实现的。它是一个
部件(part)- 工作台中“窗口”的 Eclipse 术语。因为
上个月的专栏文章包括了用作部件的插件,因此代码对您来说应该很熟悉了,所以我将只是重新生成摘录(请查阅
参考资料以下载所有该代码)。如果您没有阅读上一篇专栏文章(该文件简介了 Eclipse 插件体系结构),那么我建议您现在就回头阅读它。
本文和上个月的专栏文章最显著的差异是使用 SWT 表代替了标签。该表有两列,其中第一列包含了消息状态(出错、警告等),第二列包含了消息本身。对于一列消息来说,表很方便,因为它允许用户用滚动栏上下翻页。
在 SWT 中,表是
org.eclipse.swt.widgets.Table
的实例。使用
TableColumn
类定义每个列的宽度及其标题,如清单 2 所示。
table = new Table(parent,SWT.SINGLE);
TableColumn column = new TableColumn(
table
,SWT.NONE);
column.setText("Status");
column.setWidth(50);
column = new TableColumn(
table
,SWT.NONE);
column.setText("Message");
column.setWidth(500);
table.setHeaderVisible(true);
</td></tr></table>请注意,这里没有
addColumn()
方法。相反,您把表实例传入
TableColumn
构造器中。
TableItem
代表了表行。要对它进行初始化,将字符串数组(每列一个字符串)传递给它的
setText()
方法,如清单 3 所示。
TableItem item = new TableItem(table,SWT.NONE);
String[] text = new String[2];
text[0] = type;
text[1] = t.getLocalizedMessage();
item.setText(text);
</td></tr></table>
MessengerView
还实现了
Messenger
接口。老读者会记得
Messenger
是 XM 用来打印消息的接口。
MessengerView
只是将消息重定向到窗口。
运行 XM 菜单
弹出菜单在
XMRunner
类中实现。当用户选择菜单时,Eclipse 使用
IObjectActionDelegate
接口通知插件。
XMRunner
可在清单 4 中获得。
package org.ananas.xm.eclipse.runner;
import java.io.*;
import java.util.*;
import org.ananas.xm.*;
import org.eclipse.ui.*;
import org.eclipse.ui.actions.*;
import org.eclipse.jface.action.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.core.resources.*;
public class XMRunner
extends ActionDelegate
implements IObjectActionDelegate
{
public static final String PLUGIN_ID =
"org.ananas.xm.eclipse.runner";
public static final String CONSOLE_ID =
"org.ananas.xm.eclipse.runner.view.Console";
private IFile selectedFile;
private IWorkbenchPart part;
public void run(IAction action)
{
try
{
if(part != null)
{
saveDirtyEditors();
MessengerView messenger = showConsole();
if(messenger != null)
{
messenger.clean();
runXM(messenger);
}
else
throw new NullPointerException("Failed.");
}
}
catch(Exception x)
{
ErrorDialog.openError(part.getSite().getShell(),
"XM","Exception.",makeStatus(x));
}
}
public void selectionChanged(IAction action,
ISelection selection)
{
selectedFile = null;
if(selection instanceof IStructuredSelection)
{
IStructuredSelection structuredSelection =
(IStructuredSelection)selection;
if(structuredSelection.size() == 1)
{
Object selectedResource =
structuredSelection.getFirstElement();
if(selectedResource instanceof IFile)
selectedFile = (IFile)selectedResource;
}
}
}
public void setActivePart(IAction action,
IWorkbenchPart targetPart)
{
part = targetPart;
}
private MessengerView showConsole()
throws PartInitException
{
IWorkbenchPage page =
part.getSite().getWorkbenchWindow().getActivePage();
MessengerView messenger = null;
if(page != null)
messenger = (MessengerView)page.showView(CONSOLE_ID);
return messenger;
}
private void runXM(Messenger messenger)
throws CoreException, IOException, XMException
{
InputStream is = selectedFile.getContents();
Properties properties = new Properties();
properties.load(is);
String rulesPath =
properties.getProperty("rules","rules"),
sourcePath =
properties.getProperty("source","src"),
publishPath =
properties.getProperty("publish","publish"),
buildString =
properties.getProperty("build","false");
boolean build =
Boolean.valueOf(buildString).booleanValue();
IResource parent = selectedFile.getParent();
if(parent != null)
{
IPath parentPath = parent.getLocation();
rulesPath =
parentPath.append(rulesPath).toOSString();
sourcePath =
parentPath.append(sourcePath).toOSString();
publishPath =
parentPath.append(publishPath).toOSString();
}
DirectoryWalker walker =
new DirectoryWalker(messenger,rulesPath,build);
walker.walk(sourcePath,publishPath);
}
private IStatus makeStatus(Exception x)
{
Throwable t = MessengerView.popThrowables(x);
if(t instanceof CoreException)
return ((CoreException)t).getStatus();
else
return new Status(IStatus.ERROR,
PLUGIN_ID,
IStatus.ERROR,
x.getMessage(),
t);
}
private void saveDirtyEditors()
{
IWorkbenchWindow window =
part.getSite().getWorkbenchWindow();
IWorkbenchWindow[] windows =
window.getWorkbench().getWorkbenchWindows();
for(int i = 0;i < windows.length;i++)
{
IWorkbenchPage[] pages = windows[i].getPages();
for(int j = 0;j < pages.length;j++)
pages[j].saveAllEditors(false);
}
}
}
</td></tr></table>您应该把这个类当作
事件侦听器。Eclipse 工作台使用它将用户的选择转发给插件。该类从
ActionDelegate
继承 - ActionDelegate 为
IObjectActionDelegate
的大部分提供了缺省实现。当用户选择导航器中的新文件时,Eclipse 工作台调用
selectionChanged()
。当用户选择菜单时,它调用
run()
方法,了解这一点非常重要。
在
run()
中,插件保存编辑器的内容(如果用户正在编辑文件,就保存它),将 XM 控制台调到前台并启动 XM。
runXM()
和 XM 本身的
main()
方法之间的主要区别在于,
main()
从命令行获得其参数,而
runXM()
从特性文件读取这些参数。
额外时间
这样就完成了本月专栏文章要介绍的集成工作。但是请稍候,这里还有一个工具!我发现 Eclipse 提供了基本 XML 编辑器。您只须编译它。现在您编辑 XML 文档时语法会突出显现,并且可以通过 XM 发布它们。
XML 编辑器
Eclipse 的项目向导可以生成基本 XML 编辑器。过程如下:
org.ananas.eclipse.xml.editor
,然后单击
Next。
editor.jar
的 JAR 压缩文档。要从 Eclipse 创建 JAR,使用
File菜单中的
Export选项。这很重要 - 如果不生成 JAR 文件,Eclipse 就不会装入您的插件。
workspace
目录下寻找新项目。
workspace
复制到
plug-in
目录,然后重新启动 Eclipse。
当您双击 XML 文件时,XML 编辑器自动启动。要与更多文件相关联(比如
.xsl
),请选择
Window > Preferences > Workbench,然后选择
File Associations。
XM 更新
当我使用 XM 时,我修正了几个错误并添加一个选项以更改文件扩展名。缺省情况下,XM 把
这一特性和 XM 链接管理完全集成在了一起,因此您的所有链接都保持有效。 工作将继续进行
只用了两个类就从 Eclipse 启动了 XM,这是对插件功能的证明。在我的下一篇专栏文章中,我打算编写向导插件来初始化新的 XM 项目。同时,您可以下载并测试 XM 运行器插件。您将看到通过 Eclipsee 编辑和发布网站是件很愉快的事。然而,要提醒的是:目前插件只可用于 JDK 1.4。如果需要在 JDK 1.3.x 中运行 Eclipse,您必须安装 Xalan 并相应地调整插件。 关于作者<table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td colspan="3"></td></tr><tr align="left" valign="top"><td></td><td></td><td width="100%"> Beno?t Marchal 是住在比利时那慕尔的顾问和作家。他刚出版了
XML by Example
第二版,该版包括了不断发展的 XML 标准的最新特性(包括最终的 XML Schema 建议书和 XSL 的最新进展)。在
marchal.com上可获得更多的详细信息。可以通过
bmarchal@pineapplesoft.com与 Beno?t 联系。
.html
扩展名给 HTML 文件。XML 文件得到
.xml
扩展名。有些用户可能需要将缺省值更改成
.htm
、
.shtml
、
.rss
、
.wml
或其它扩展名。如果您需要这项功能,请复制清单 5 的代码。请注意新的
rules:extension
属性。
清单 5. 更改文件扩展名
<table bgcolor="#eeeeee" width="100%" cellpadding="5" cellspacing="0" border="1"><tr><td>
</td></tr></table>
<?xml version="1.0"?>
<table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td>
</td></tr></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tr align="right"><td>
<table border="0" cellpadding="0" cellspacing="0"><tr><td valign="middle">
</td><td valign="top" align="right"></td></tr></table></td></tr></table>
<table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td>
</td></tr></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tr align="right"><td>
<table border="0" cellpadding="0" cellspacing="0"><tr><td valign="middle">
</td><td valign="top" align="right"></td></tr></table></td></tr></table>
<table border="0" cellpadding="0" cellspacing="0"><tr><td valign="middle">
</td><td valign="top" align="right"></td></tr></table></td></tr></table>
<table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td>
</td></tr></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tr align="right"><td>
<table border="0" cellpadding="0" cellspacing="0"><tr><td valign="middle">
</td><td valign="top" align="right"></td></tr></table></td></tr></table>
↑返回目录
前一篇: 使用 XML: 创建项目
后一篇: 利用视图链接使 Eclipse 应用程序更丰富