用XML,XSL,CSS制作电子图书
运行例程前的准备工作
你必须确认以下的软件已安装在你的操作系统中:
Microsoft XML Parser
Windows Script Host 2.0
Internet Explorer 5.0 or higher
制作电子图书的必要条件
制作电子图书所必须的条件是简单的。我们对用XML和XSL出版电子图书感兴趣。为达到这一目的,我们必须明确以下几点问题:
1. 是用有效的(valid)XML文件还是用格式良好的( well-formed )XML文件?
2. 是把整本书保存成一个XML文件,还是按内容章节把书分为若干个XML文件(i.e. chapter/section/subsection)?
3. 如果把书按内容章节分为若干个XML文件,又如何对每一个XML文件的内容进行划分?
4. 是否需要一个单独的XML文件保存内容目录?
解决方法
解决的方法就是以上问题的答案。
我用XML-Data来设计电子图书的大纲(schema)。XML-Data是一种用XML来描述大纲的标准,因为它比DTD更为直观,所以可以用它来替代DTD。相对与DTD,XML-Data的最大优势在于它的开放模式(open model)允许我们定义事先没有在大纲中定义的新子元素或子属性。你可以在http://www.w3.org/TR/1998/NOTE-XML-data/ 阅读到最新的XML-Data规范。
当我试图用XMLDOM读取XML时遇到了一些问题。因为在〈content〉〈/content〉中的使用了HTML标记符(tag)的缘故,我收到了从XML解析器返回的解析错误。我本可以为每一个要在〈content〉〈/content〉中使用的那些HTML标记符都定义一个〈ElementType〉,这样就可以避免从XML解析器返回的解析错误。但这样做的话就必须要为几乎所有必需的HTML标记符定义〈ElementType〉才能使内容合乎用户的心意。
所以我用名域(namespaces)设计了一个简单的工作区。我在〈content〉〈/content〉中指定了缺省的名域以避免解析错误。然而,如果你在〈content〉〈/content〉中使用任何XML元素的话,这个解决方法将不起作用,因为那些XML元素并非在我指定的缺省名域当中。
此外,我们可以通过象html一样使用名域前缀(namespace prefix)以区分我们自定义的标记符和HTML标记符来解决这一问题。但是,使用名域前缀使得XSL代码复杂化,因为我们必须使自定义的标记符与HTML标记符相匹配:加前缀并把它们转换为HTML标记符。既然我已经为图书设计了XML大纲,使得在〈content〉〈/content〉中没有XML元素出现,因而我们就可以设缺省名域为http://www.w3.org/TR/REC-html40,避免了解析错误的出现。
现在让我回答第二个问题。既然我已决定使用格式良好的XML,那么图书的内容就必须保存在同一个XML文件中,并可以在内容当中使用HTML标记符。对于那些希望用若干个HTML文件分别保存图书的内容,然后只用XML文件来保存实际内容在目录中的链接的人而言,大纲还是有用的。做为选择,你可以选择完全忽视大纲,继续使用格式良好的XML。
我选择以节(section)来作为划分图书内容的单元。用户不会对过细的章节划分感兴趣。同样的,把整章内容就这样显示,会使用户忙于拖动滚动条,也不好。因此,过大或过小的内容划分都不应让用户遇到。以节划分就是一个折中的标准。 当我们把图书保存在一个单独的XML文件当中时,为什么还需要另外一个XML文件来保存图书的目录呢?目录(TOC)可以很容易的用XMLDOM从XML文件当中生成。就象我先前说的,这个目录XML文件包含有内容单元(如:节)与实际HTML文件之间的链接。
既然所有的问题都有了答案,就让我解释以下电子图书的实际执行过程。在下表中,我列出了组成电子图书的各个文件名和各自的用途(这些文件都包含在文后可下载的例程当中):
| 文件名 | 用途 |
| EBookSchema.xml | 包含用XML-Data 设计的电子图书大纲(Schema) |
| EBook.xml | 保存在XML文件当中的完整的电子图书 |
| GenerateEBook.js | 从EBook.xml 中提取数据生成目录文件和图书内容的 HTML文件的JavaScript 脚本。目录文件本身就是一个可以用EbookLinks.xsl转换为HTML的XML文件。图书的内容按节保存在单独的HTML文件中,并以各节的ID号来命名HTML文件。 |
| EBook.js | 包含客户端脚本和目录、内容显示的事件句柄的JavaScript脚本 |
| EBook.asp | 连接目录文件和内容文件的ASP文件 |
| EBookContent.asp | 负责根据用户的选择显示相关内容的ASP文件 |
| EBookLinks.xsl | 用于显示目录的XSL样式文件 |
| EBookContent.xsl | 用于显示内容的XSL样式文件 |
| EBook.css | 用于显示目录的CSS样式文件 |
| EBookContent.css | 用于显示内容的CSS样式文件 |
| EBookGenerator.bat | 用Windows Script Host运行GenerateEBook.js的批处理文件 |
XML-Data开放模式下的电子图书XML大纲
以下为部分用XML-Data编写的电子图书XML大纲:
〈?xml version='1.0'?〉
〈Schema name="book" xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:datatypes" 〉
〈AttributeType name="appendix" dt:type="string" required="no"/〉
〈ElementType name="author" content="eltOnly"〉...〈/ElementType〉
〈ElementType name="authors" content="eltOnly"〉...〈/ElementType〉
〈ElementType name="publisher" content="eltOnly"〉...〈/ElementType〉
〈ElementType name="subsection" content="mixed"〉...〈/ElementType〉
〈ElementType name="section" content="eltOnly"〉...〈/ElementType〉
〈ElementType name="chapter" content="eltOnly"〉...〈/ElementType〉
〈ElementType name="part" content="eltOnly"〉...〈/ElementType〉
〈ElementType name="book" content="eltOnly" 〉...〈/ElementType〉
...
〈/Schema〉
从以上的例子可以看出,以上每一个〈ElementType〉都是其下一层子元素的集合体:
〈ElementType name="id" content="textOnly"/〉
〈ElementType name="title" content="textOnly"/〉
〈ElementType name="isbn" content="textOnly"/〉
〈ElementType name="edition" content="textOnly"/〉
〈ElementType name="copyright" content="textOnly"/〉
〈ElementType name="number" content="textOnly"/〉
〈ElementType name="name" content="textOnly"/〉
〈ElementType name="content" content="mixed"/〉
例如,被命名为“book”的〈ElementType〉在大纲中是这样描述的:
〈ElementType name="book" content="eltOnly" 〉
〈element type="id" minOccurs="1" maxOccurs="1"/〉
〈element type="title" minOccurs="1" maxOccurs="1"/〉
〈element type="isbn" minOccurs="1" maxOccurs="1"/〉
〈element type="edition" minOccurs="1" maxOccurs="1"/〉
〈element type="copyright" minOccurs="1" maxOccurs="1"/〉
〈element type="authors" minOccurs="1" maxOccurs="1"/〉
〈element type="publisher" minOccurs="1" maxOccurs="1"/〉
〈element type="part" minOccurs="1" maxOccurs="*"/〉
〈/ElementType〉

