尽管网页使用的术语和书本不同,但多个网页同样可以被组织成树状。
本节要构建的是这样一个程序,它生成多个网页,这些网页带有以下结构: 第一页是一个目录,目录中的链接指向各个节点(section)页面。 每个节点包含一些指向项(item)的链接。 而一个项就是一个包含纯文本的页面。
除了页面本身的链接以外,根据页面在树状结构中的位置,每个页面都会带有前进、后退和向上的链接。 其中,前进和后退链接用于在同级(sibling)页面中进行导航。 举个例子,点击一个项页面中的前进链接时,如果这个项的同一个节点下还有下一个项,那么就跳到这个新项的页面里。 另一方面,向上链接将页面跳转到树形结构的上一层 —— 如果当前页面是项页面,那么返回到节点页面;如果当前页面是节点页面,那么返回到目录页面。 最后,还会有索引页面:这个页面包含一系列链接,按字母顺序排列所有项。
图 16.7 网站的结构
图 16.7 展示了生成程序创建的页面所形成的链接结构。
图 16.8 包含定义页面所需的数据结构。程序需要处理两类对象:项和节点。这两类对象的结构很相似,不过节点包含的是项的列表,而项包含的是文本块。
节点和项两类对象都带有 域。 标识符(id)被用作符号(symbol),并达到以下两个目的:在 defitem
和 defsection
的定义中, 标识符会被设置到被创建的项或者节点当中,作为我们引用它们的一种手段;另一方面,标识符还会作为相应文件的前缀名(base name),比如说,如果项的标识符为 foo
,那么项就会被写到 foo.html
文件当中。
节点和项也同时带有 title
域。这个域的值应该为字符串,并且被用作相应页面的标题。
在节点里,项的排列顺序由传给 defsection
的参数决定。 与此类似,在目录里,节点的排列顺序由传给 defsite
的参数决定。
图 16.9 生成索引和目录
图 16.9 包含的函数用于生成索引和目录。 常量 contents
和 都是字符串,它们分别用作 contents
页面的标题和 index
页面的标题;另一方面,如果有其他页面包含了目录和索引这两个页面,那么这两个常量也会作为这些页面文件的前缀名。
实际程序中的对比操作通常更复杂一些。举个例子,它们需要忽略无意义的句首词汇,比如 和 "the"
。
图 16.10 生成网站、节点和项
图 16.10 包含其余的代码: gen-site
生成整个页面集合,并调用相应的函数,生成节点和项。
所有页面的集合包括目录、索引、各个节点以及各个项的页面。 目录和索引的生成由图 16.9 中的代码完成。 节点和项由分别由生成节点页面的 gen-section
和生成项页面的 gen-item
完成。
这两个函数的开头和结尾非常相似。 它们都接受一个对象、对象的左兄弟、对象的右兄弟作为参数;它们都从对象的 title
域中提取标题内容;它们都以调用 gen-move-buttons
作为结束,其中 gen-move-buttons
创建指向左兄弟的后退按钮、指向右兄弟的前进按钮和指向双亲(parent)对象的向上按钮。 它们的不同在于函数体的中间部分: gen-section
创建有序列表,列表中的链接指向节点包含的项,而 创建的项则链接到相应的文本页面。
项所包含的内容完全由用户决定。 比如说,将 HTML 标签作为内容也是完全没问题的。 项的文本当然也可以由其他程序来生成。
图 16.11 一个微型网站