65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 JavaScript 对象字面量将 WebHelp 和已编译帮助 RoboHelp 项目连接到关系数据库的可重用框架

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.60/5 (4投票s)

2005 年 5 月 10 日

18分钟阅读

viewsIcon

46711

downloadIcon

328

本文将介绍如何通过单一架构将 RoboHelp 项目与数据库挂钩,为 WebHelp 和已编译帮助页面提供数据。实现将依赖于几乎所有 Web 浏览器内置的 JavaScript 解释器,该解释器也存在于已编译帮助中。

引言

本文将介绍如何通过单一架构将 RoboHelp 项目与数据库挂钩,为 WebHelp 和已编译帮助页面提供数据。我们将介绍问题场景,评估一些解决方案,然后讨论实现。在我们的实现中,我们将依赖于几乎所有 Web 浏览器内置的 JavaScript 解释器,该解释器也可用于包含在已编译帮助输出中的页面。我们将依赖 RoboHelp 的单源布局系统及其对条件生成标签的支持来定制我们的输出选项。

对于我们的服务器端解决方案,我们也将使用 JavaScript,但这里提出的解决方案框架并未与 JavaScript 的服务器端使用耦合。然而,本文将展示 JavaScript 解释器如何通过使用对象字面量表示法,非常适合将数据与客户端进行编排的任务。最终,提出的解决方案是通用的、可重用的和可扩展的。所有项目资源都可以在引用的 .zip 存档中下载。

关于 AJAX 和 MadCap Software 的注意事项

在深入本文之前,我想指出这里描述的内容与流行的 AJAX(异步 JavaScript 和 XML)技术非常相似。我写这篇文章时不知道这个术语,但在查找有关 JavaScript 对象字面量表示法的信息,以查看是否有人为不同语言编写了解析器后,我发现了 JSON。此外,我了解到 RoboHelp X5 的未来尚不明确,但 MadCap Software 希望通过支持 RoboHelp 项目文件格式来解决这个问题。以下是一些关于此信息的链接

目录

我希望您发现本文中的技巧、代码和资源对您的 RoboHelp 项目有所帮助。

在 Web 和桌面帮助项目中提供最新数据的难题

帮助作者经常面临的一个问题是,他们必须通过两个或多个途径向用户提供帮助内容

  1. Web 交付的帮助页面(RoboHelp 术语中的 WebHelp)。
  2. 用户桌面上的独立帮助系统(已编译帮助)。

这些页面中的内容可能是静态的,不易更改,但很可能许多区域应该是动态的。对于 WebHelp,这些内容可以在发送到服务器的请求时“即时”交付给客户端。但对于已编译帮助,情况并非如此,因为分发理想情况下应该是完全独立的,并且永远不依赖于用户访问互联网连接。

应用以用户为中心的设计原则

即使在基于 Internet 的系统中,上述示例也适用,因为作为作者和开发人员,我们的目标是让最终用户以最易于访问和灵活的方式获取信息。

只要我们正确设计解决方案,就不应该出现因为我们自身缺乏技术远见而导致“理论上可以做的事情”在实践中无法灵活地为用户实现的情况。

案例研究:国际招聘公司对动态信息的需求

为了举例说明一些动态信息,请考虑一个名为 International Staffing Company (ISC) 的虚构公司的以下两个示例

  1. ISC 维护着合作伙伴组织、业务区域和公司内部职位名称等信息列表。
  2. ISC 人员的联系信息会发生变化,有时是由于轮岗、人员流失或异地调动。

ISC 拥有一个国际可访问的网站,为客户提供求职和申请服务。他们还考虑提供用户可以下载到计算机上的独立应用程序,以方便访问服务。因此,他们希望能够同时在 Web 和离线桌面部署中部署帮助系统。以下原型显示了他们希望上述数据在输出中如何显示。

期望输出的原型

在此原型中,ISC 使用绿色背景标识了动态生成区域。作为一个快速发展的公司,ISC 必须频繁更新这些信息,并且不希望每次都必须重新编译帮助项目才能向客户提供准确信息。

问题陈述

在检查了需求和原型输出后,我们可以将问题陈述分为两部分

  1. 我们如何提供一个灵活的机制,将动态数据包含到我们的 RoboHelp 项目中,而无需在数据更改时重新编译?
  2. 而且,我们如何做到这一点,使得 WebHelp 和已编译帮助使用相同的基本机制?

派生需求表

从这个陈述中,我们得出以下三个需求

数字

优先级(3 最高)

描述

R1

3

解决方案必须提供一种将动态数据包含到 WebHelp 和已编译帮助中的方法。

R2

2

解决方案应在 WebHelp 和已编译帮助中使用相同的基本机制,以简化维护和开发。

R3

1

解决方案应可扩展,以允许未来的类似添加。

继续阅读,了解如何选择和实现一个满足所有三个要求且简单、可重用且可扩展的解决方案。

可能解决方案的评估

现在我们知道需求和一些紧密相关的技术关联项

  1. 为 WebHelp 和已编译帮助提供动态数据。
  2. 确保解决方案在 IE、Netscape、Mozilla、FireFox 等浏览器中运行。
  3. 如果可能,为 WebHelp 和已编译帮助使用相同的机制。

替代评估矩阵

考虑到这些,有许多想法似乎可行

数字

替代方案

实施计划

R1?

R2?

R3?

SA1

在浏览器中使用 XML 作为“数据岛”

XML 的块可以用来提供数据段并在运行时转换。为已编译帮助提供静态副本,为 WebHelp 动态生成。

SA2

使用简单的数据库,如 MS Access

将 MDB 文件嵌入已编译帮助中,并在服务器端从 Web Help 调用。

SA3

使用 JavaScript 字面量对象作为数据存储机制

将静态 .js 文件作为 RoboHelp 的附件文件嵌入已编译帮助中,从服务器动态生成 JavaScript,用于 WebHelp

解决方案大纲

SA3 解决方案看起来是赢家。SA1 和 SA2 失败的原因是

  • SA1:虽然 XML 是存储数据的绝佳选择,但我们不能依赖用户浏览器代理能够动态解析 XML。因此,我们可以为 Web Help 在服务器端执行此操作,并依赖 Internet Explorer 的 XSL 转换来处理已编译帮助。这是可能的,但这同样是它未能满足 R3 的原因。
  • SA2:与 SA1 类似,这似乎在已编译帮助中都能正常工作,使用许多用户在渲染时系统上可用的 ADODB 库。对于 WebHelp,我们可以在服务器端使用类似的调用来渲染适当的标记。但这同样是 SA2 未能满足 R3 的原因。

即使我们选择 SA1 或 SA2,我们仍然需要弄清楚如何将动态生成的内容从服务器端放入 HTML 的静态内容中。无论如何,如果我们希望在帮助作者和开发人员之间保持任何形式的劳动力分工,这都会导致在客户端使用少量 JavaScript。

* 注意:我没有尝试过 SA1 或 SA2,但 XML 和 MDB 是我在考虑可能的解决方案时想到的两个想法,但 R2 中出现的明确问题使得这些解决方案不可行。它们可能实际上也会在 R1 或 R3 中失败,但我会在本次分析中给予它们一点好处。

JavaScript 对象字面量作为解决方案

HTML 是互联网的通用语言,但 JavaScript 是一种密切相关的本地语言。几乎所有 Web 浏览器都支持某种基本级别的 JavaScript,已编译帮助也支持,因为它在很大程度上只是 Internet Explorer 浏览器控件的包装。

客户端实现

JavaScript 可以嵌入到 HTML 文件中,并在页面加载时通过编程方式访问,以更改内容的显示方式。作为程序员,我们所需要做的就是找到一种方法将 JavaScript 嵌入到静态 HTML 页面的 HEAD 标签中,然后调用一些函数来将数据渲染成格式化的 HTML。

服务器端实现

在后端服务器上,使用什么语言或连接什么数据库并不重要,只要我们有办法将数据转换为 JavaScript 对象字面量的字符串。但是,正如本示例所示,在客户端和服务器端都使用 JavaScript 在数据编排和命令分派方面具有一些优势。

解决方案框架大纲

我们的解决方案框架将包括以下组件

  1. 一种在服务器不可用时为客户端提供静态数据的方法,以便动态生成数据。
  2. 一种在服务器可用时连接到数据源的方法,以获取最新数据并覆盖静态数据。
  3. 一种组织数据的方式,以便客户端内容中的最终渲染函数能够以相同的方式在 WebHelp 和已编译帮助中访问它。

与所有这些紧密相关的是,RoboHelp 的条件生成标签将在适用的地方贯穿始终。

本文的其余部分将详细解释如何用最少的代码编写,并具有高可重用性和可扩展性来实现这一点。

数据库连接

在 ISC 场景中,我们将研究如何连接到 Microsoft Access 数据库,使用 ADODB 创建记录集对象,然后将结果渲染为 JavaScript 对象字面量,通过 HTML script 标签传递回客户端。在类似的实际情况中,我连接到使用 SQL Server 作为底层数据存储的现有系统的业务层。

在您的案例中,您可能正在使用 PHP 和 MySQL,或 PERL 和 Oracle,Java 和 Cloudscape,或完全不同的东西。您必须保持不变的部分是,返回到客户端的 JavaScript 对象字面量应该看起来相同。我在这里使用 Access 是因为 MDB 文件格式可以被大多数用户轻松下载并在本地机器上使用。

数据库架构

首先,让我们定义 MDB 文件的架构。不幸的是,我没有先这样做。我是通过 Access 程序的界面创建的,但我找到了一个很棒的小 python 工具来反向工程 MDB 文件以生成其底层 DDL。

MDB 文件的 DDL

列表 1
CREATE TABLE "lookup" 
( 
    "lookup_id" Counter NOT NULL , 
    "category" LongInteger DEFAULT 0 , 
    "lookup_desc" char(50) , 
    PRIMARY KEY "lookup_id","category" 
); 
CREATE INDEX "lookup_IX0" ON "lookup" ("category" ASC ); 
CREATE INDEX "lookup_IX1" ON "lookup" ("lookup_id" ASC ); 
CREATE UNIQUE INDEX "lookup_PK" ON "lookup" ("lookup_id" ASC,"category" ASC ); 
  
CREATE TABLE "params" 
( 
    "ParamID" Counter NOT NULL , 
    "Name" char(50) , 
    "Value" char(50) , 
    "Label" char(100) , 
    PRIMARY KEY "ParamID","Name" 
); 
CREATE UNIQUE INDEX "params_PK" ON "params" ("ParamID" ASC,"Name" ASC );

JavaScript 对象字面量输出数据包

此时的目标是创建一个简单的 JavaScript 对象字面量,使用底层数据库数据。格式如下

列表 2
myData={'1':[{'lookup_id':'5','lookup_desc':'Director'}
,{'lookup_id':'2','lookup_desc':'Employee'}
,{'lookup_id':'1','lookup_desc':'Manager'}
,{'lookup_id':'4','lookup_desc':'President'}
,{'lookup_id':'3','lookup_desc':'Supervisor'}
...
] myContact=[{'Name':'ContactNumber','Value':'404-555-5566',
    'Label':'Contact Number'}
,
{'Name':'ContactPerson','Value':'Mr. Manager','Label':'Contact Person'}
,
{'Name':'ContactHours','Value':'Mon - Fri 8 AM to 5 PM',
     'Label':'Contact Hours'}
];

熟悉 PERL 的人会认为这是一种关联数组的关联数组。在 VBScript 中,它可能使用 Scripting.Dictionary 对象实现。Java 和 .NET 程序员以及其他所有人可能将其视为 HashTable。在 JavaScript 中,它被称为字面量表示法的对象。JavaScript 提供了所有这些语言中最简洁的语法。

eval 函数

在 PERL 和 JavaScript 中,通过调用 eval 函数,可以简单地写出这样的字符串(在 PERL 中,用 : 替换 =>)并在运行时立即在执行的当前上下文中激活,而程序员无需进行任何解析。这通过调用 eval 函数来完成。基本上,eval 尝试将字符串作为代码执行,并在解释器正在执行的代码块的范围内执行。许多脚本滥用 eval 函数,例如处理图像轮播的脚本,但它在脚本中的主要用途应该是激活引擎中的数据结构,或者允许交互式调试,就像在 Mozilla 扩展 Venkman 中那样。

更多关于 JavaScript 字面量表示法

有关 JavaScript 对字面量表示法的支持的更多信息,请参阅 ECMAScript 部分下的此参考资料

连接到数据库并生成 JavaScript 的 ASP 代码

这是 ASP 页面的 JScript 代码,它将连接到 MDB 文件,然后将查找值和联系信息转换为 JavaScript 对象字面量。请注意,在此 ASP 脚本中,我们还依赖字面量表示法来实现服务器端代码中的灵活命令分派。我们在通过查询字符串传递的值中使用它。在第 9 行,我们使用 eval 函数将数据激活到解释器的执行上下文中。

在其他语言中可以实现类似的命令分派系统,在 PERL 中几乎完全相同。即使在编译语言中也是可能的,但需要更复杂的数据在运行时解析。在这种情况下,脚本的强大之处在于它可以为我们完成解析工作,只要我们足够小心地考虑任何陷阱并正确使用诸如 try / catch 这样的语言结构。

列表 3
// Load the javascript in string form from the request

var cmdSetAsString = Request.Item("cmdSet"); 
var cmdSet = []; 
var jsrv = ""; 
var isValid = false; 
try { 
    eval("cmdSet = [" + cmdSetAsString + "]"); 
} 
catch(e) { } 
if (cmdSet.length > 0) 
    isValid = true; 
if (isValid != true) { 
    jsrv = "JS_Evaluator_Error = 'Could not instantiate object from string.\n'"; 
    Response.Write(jsrv); 
    Response.End(); 
} 
// Execute each command 
for (var i = 0; i < cmdSet.length; i++) { 
    try { 
        // Assign return value to the specified variable 
        jsrv += cmdSet[i].vnam + 
            "=" + this[cmdSet[i].func](cmdSet[i].arg) + ";\n"; 
        jsrv += cmdSet[i].vnam + "_error=false;\n"; 
    } 
    catch(e) { 
        jsrv += cmdSet[i].vnam + "_error=true;\n"; 
        Response.Write(e.description); 
    } 
} 
Response.Write(jsrv); 
// Page Level functions 
function GetConnection() { 
    var path, conn, connStr; 
    path = Server.MapPath("LookupDB.mdb"); 
    conn = Server.CreateObject("adodb.connection"); 
    conn.Provider = "Microsoft.Jet.OLEDB.4.0"; 
    conn.Open(path); 
    return conn; 
} 
function GetListValues(listIds) { 
    // Create a DB Connection 
    var conn = GetConnection(); 
    var rv, i; 
    rv = ""; 
    for (var i = 0; i < listIds.length; i++) 
        rv += "\n,'" + listIds[i] + "':" + PackageListAsJS(listIds[i], 
                 ['lookup_id', 'lookup_desc'], conn); 
    conn.Close(); 
    delete conn; 
    return "{" + rv.substring(2) + "}"; 
} 
function PackageListAsJS(listId, arFields, conn) { 
    var rsList, rv; 
    var rsList = GetLookups(listId, conn); 
    rv = PackageRecordSetAsJS(rsList, arFields); 
    rsList.Close(); 
    delete rsList; 
    return rv; 
} 
function PackageRecordSetAsJS(rs, arFields) { 
    var rv = ""; 
    var numFields = arFields.length; 
    while(!rs.EOF) { 
        var row = ""; 
        for (var i = 0; i < numFields; i++) { 
            var name, value; 
            if (row != "") row = row + ","; 
            name = arFields[i]; 
            value = String(rs(name).value); 
            value = value.replace("\n", "\\n"); 
            value = value.replace("\r", "\\r"); 
            value = value.replace("'", "\\'"); 
            row += "'" + name + "':'" + value + "'"; 
        } 
        rv += ",{" + row + "}"; 
        rs.MoveNext(); 
    } 
    // Complete the javascript object 
    return "[" + rv.substring(1) + "]"; 
} 
function GetLookups(id, conn) { 
    var sql = "SELECT * FROM lookup WHERE category = " + id + 
            " ORDER BY lookup_desc"; 
    return conn.Execute(sql); 
} 
function GetContactInfo() { 
    var conn = GetConnection(); 
    var sql = "SELECT * FROM params WHERE Name LIKE 'Contact%'"; 
    var rsContact = conn.Execute(sql); 
    var rv = PackageRecordSetAsJS(rsContact, ["Name", "Value", "Label"]); 
    rsContact.Close(); 
    conn.Close(); 
    delete rsContact; 
    delete conn; 
    return rv; 
}

最佳实践的安全注意事项

请注意,我在这里没有检查引荐的 URI,但我本可以这样做以确保最大的安全性。这将允许您阻止人们浏览到 URL 并输入自己的参数。您可能还想检查可能的 SQL 注入攻击。即使我们只将 SELECT 语句传递到底层数据库,攻击者也可以尝试终止您的语句并执行恶意代码。这就是脚本的灵活性可能变成噩梦,而编译和强类型的严谨性变得有益的地方。但是,即使在 JSP 或 ASP.NET 等编译的服务器端解决方案中,您也可以编写一个相对简单的解析器来将 { , : , 和 [ 转换为 HashTable 和 ArrayList 风格的对象实例的组合,并检查每个数据类型的有效性,从而仍然提供一个与底层命令处理架构松散耦合的非常灵活的命令分派系统。但是,为了在本演示中说明基本概念,我们将继续在客户端和服务器端都使用 JavaScript。

动态页面,用于包含在 WebHelp 和已编译帮助中

这是 HTML 文件的代码,它将包含静态数据版本和对 generatedata.asp 的动态调用。请注意以下几点

  1. 静态数据是调用 generatedata.asp 的输出的本地保存副本。
  2. generatedata.asp 的调用带有 RoboHelp 的 x-condition 样式标签,以确保它仅在构建 WebHelp 时渲染。
列表 4
<html>
<head>
<title>International Staffing Company</title>
<script type="text/javascript" src='DynamicPage_data.js'></script>
<script type="text/javascript"
style="x-condition: ONLINE_ALL"
src="https:///robohelp/generatedata.asp?cmdSet=
  {vnam:'myData',func:'GetListValues',arg:[1,2,3]},
  {vnam:'myContact',func:'GetContactInfo',arg:null}"></script>
<script type="text/javascript" src='applicationcontroller.js'></script>
<script type="text/javascript">
<!--
var MyApp = 
   new MyHelpApplicationController(
   MyHelpApplicationController.DEPLOYMENT_ENUM.PRODUCTION);
// -->
</script>

<style type="text/css">
<!--
BODY {
    font-family: arial;
    font-size: 80%;
}
H3 {
    color: navy;
}
LI {
    list-style: disc;
}

/* works in FireFox, but not IE:
LI:before {
    content: '> ';
    font-weight: bold;
    color: navy;
    font-size: 85%;
}
*/
// -->
</style>
<script type="text/javascript">
<!--
    function RenderList(id) {
        var rv = "<ul>\n";

        var obj = myData[id];

        for (var i in obj) {
            rv += "\t<li>" + obj[i].lookup_desc + "</li>\n";
        }

        return rv + "</ul>\n";
    }

    function RenderContactInfo() {
        var rv = "<div>\n";

        for (var i = 0; i < myContact.length; i++) {
            var rec = myContact[i];
            rv += "<b>" + rec.Label + "</b> : " + rec.Value + "<br />\n";
        }
        return rv + "</div>\n";
    }
// -->
</script>

<body>

<h2>Welcome to International Staffing Company Web Help</h2>

<p>This site provides information about navigating our 
 web site and using our online services.</p>

<h3>ICS fills positions for the following job types:</h3>
    <script type="text/javascript">
    <!--
    document.write(RenderList(1));
    // -->
    </script>
<h3>ICS has placed people in the following industries world wide:</h3>
    <script type="text/javascript">
    <!--
    document.write(RenderList(2));
    // -->
    </script>
<h3>ICS has worked with companies in the following countries:</h3>
    <script type="text/javascript">
    <!--
    document.write(RenderList(3));
    // -->
    </script>
<h3>Contact ICS</h3>
Feel free to contact us!<br /><br />
    <script type="text/javascript">
    <!--
    document.write(RenderContactInfo());
    // -->
    </script>
<br />
<a href="javascript:void(alert(MyApp.baseUrl))">Show Base Url</a>
</body>
</html>

实现说明和选项

请注意,为了确保页面始终能正常显示一些数据,即使数据不是最新的,静态数据也不会从 WebHelp 中排除。当由于网络问题、无法访问数据库或其他原因导致对 generatedata.asp 的调用失败时,这将有助于防止用户沮丧。实际上,对于可能不会经常更改的数据,更好的解决方案甚至是缓存 generatedata.asp 调用到服务器文件系统的输出。这可以允许一键更新所有数据部分,或者允许计划任务定期生成此输出,而无需手动干预。在这种替代方案中,各级的灵活性都得到了保持,但故障点得到了最小化。

在客户端 JavaScript 中使用外观模式进行资源位置抽象

最后,作为思考的食物,并再次强调 JavaScript 的灵活性,我提出了在生成的帮助系统中实现应用程序控制器对象,以提供隐藏资源分散位置底层路径的外观。

JavaScript 对象构造函数和原型

JavaScript 中经常被忽视的一个特性是其基于原型的对象系统。这与类式语言不同,但提供了类似的功能和更多的运行时灵活性。许多脚本不是使用这个非常灵活的系统,而是以过程式风格编写,在顶层对象中声明了大量的变量。

通过构造函数的更好方法

通过使用对象构造函数,有一种更好的方法。这样,所有变量和对象都可以包含在一个对象中。这里有一个示例,可用于抽象化资源物理位置的细节。这使得应用程序程序员可以专注于适当地命名资源,并将查找这些资源的详细信息留给控制器实例。

隐藏不同部署细节的“外观”

我在一个实际情况下使用了这一点,在该情况下,我们必须在多个环境中测试我们的帮助系统,包括本地、开发、暂存、生产和 Microsoft 已编译帮助。复杂因素是

  1. 这些环境中的每个环境都有略微不同的资源位置,由于位置分散和网络配置(包括安全限制),无法将它们制作成完全相对的链接。
  2. 在 RoboHelp 项目的 *内容* 中硬编码位置路径是不明智的。
  3. 同样,调用数据库来获取这些位置路径也是不明智的,因为这不适用于已编译帮助。

  4. 最后,对于可能需要在帮助系统外部访问共享数据的不同 Web 服务器上的多个安装,找到一种方法让这些安装指向共享资源是明智的。

通过 RoboHelp 的条件生成标签和客户端 JavaScript 的结合,通过简单实现外观设计模式,解决方案变得可行。

列表 5
// Application Controller employing a Facade design pattern
function MyHelpApplicationController(deploymentType) {
    this.baseUrl = "";
    this.init(deploymentType);
}
/* Constructor Level Enumeration for Deployment Configuration Options */
MyHelpApplicationController.DEPLOYMENT_ENUM = {
    LOCAL : 1,
    DEVELOPMENT : 2,
    STAGING : 3,
    PRODUCTION: 4,
    HOTSITE: 5,
    COMPILED_HELP: 6
}
MyHelpApplicationController.prototype.init = function(deploymentType) {
    switch(deploymentType) {
        case MyHelpApplicationController.DEPLOYMENT_ENUM.LOCAL:
            this.baseUrl = "c:\\projects\\helpsystem\\helpoutdirectory\\";
        break;
        case MyHelpApplicationController.DEPLOYMENT_ENUM.DEVELOPMENT:
            this.baseUrl = "http://machine-on-intranet/applicationdir/help/";
        break;
        case MyHelpApplicationController.DEPLOYMENT_ENUM.PRODUCTION:
            this.baseUrl = 
               "http://www.internationalstaffingcompanysiteurl.com/help/";
        break;
        case MyHelpApplicationController.DEPLOYMENT_ENUM.COMPILED_HELP:
            this.baseUrl = "./";
        break;
    }
}
MyHelpApplicationController.prototype.NavigateUrl = function(url) {
    location.href = this.baseUrl + url;
}
MyHelpApplicationController.prototype.GetScriptReference = function(url) {
    return "<" + "script type='text/javascript' src='" + this.baseUrl + url +
    "'>" + "</" + "script>";
}

后记:关于范围和改进想法的说明

上述解决方案假设帮助创作是通过标准的 HTML 创作或从 Word 文档导入文件来完成的。这种方法在许多帮助项目中很常见,并且可以重用现有内容。在我看来,一种更好、甚至更灵活的方法是,将现有内容转换为标准的 XML 模式,但这可能会产生更多的前期内容重写。

RoboHelp 中的 XML 支持为创作语义丰富的帮助内容提供了支持

HTML 不是一种语义语言,尤其是在创作帮助内容方面!XML 的设计目的是允许开发标签集,以便作者能够语义地而不是图形地传达他们的想法。基于作者提供的语义,应用程序作者然后编写转换代码来生成适当的图形表示。这允许在原始语义意图和最终输出格式之间存在一对多关系。不幸的是,HTML 有时感觉更像一对零。

RoboHelp 支持复杂的 XML 导入选项,允许内容作者设计具有语义丰富结构化内容的帮助系统,而不是试图将帮助和以用户为中心的习语强行塞入不适合的 HTML 模式。RoboHelp 通过 XML Handlers 对 XML 的支持允许应用程序开发人员编写 XSLT 以将语义帮助模式转换为适当的 HTML 或任何其他输出。

在这种情况下,帮助作者可以编写语义丰富的 XML,应用程序开发人员然后应用 XSLT 转换来构建 HTML 内容。通过允许帮助作者创建自己的语义,应用程序开发人员处理它来生成输出,XML 使作者和开发人员都能更高效,并最终提供更好的用户体验。

有关 RoboHelp X5 中 XML 支持的更多信息,请参阅相关资源部分。

下载和相关资源

下载次数

请参阅页面右侧的下载部分,其中包含一个 ZIP 文件,其中包含所有代码列表和静态及动态页面的工作示例。它还包含一个完整的 RoboHelp X5 项目,以及生成的 WebHelp 和已编译帮助输出。有一个 Readme.txt 文件用于解释如何在 IIS 中使用它。

链接

在撰写本文时,我遇到了一些非常棒且有用的链接。

© . All rights reserved.