-- 作者:小鞋子
-- 发布时间:2/18/2004 10:00:00 AM
-- Xml:运用数据链路来显示XML 文件和DSO方法
可见解运用数据链路来显示XML 文件和DSO方法[书TXT] --------------------------------------------------------------- 资料来源: 轻松搞定XML 作者:Michael.J.Young 翻译者:林嘉胜 此资料仅供自己学习参考,未经作者及翻译者授权,不得用于商业目的。 ---------------------------------------------------------------- 将HTML元素连结到XML元素的两种方法: 表格式数据链路 ----代表将HTML 的TABLE 元素连结至XML 数据,好让表格能自动地显示属于XML 文件纪录的整个集合。 单一纪录数据链路 ----代表将非表格式的HTML 元素(例如,SPAN 元素)联结到XML 元素,如此一次只有一笔记录被显示。 使用表格式数据链路 要显示由一连串的记录(如列表8-1 中显示的Inventory.xml)所组成的XML 文件,最简单的方法就是将HTML 的TABLE 元素连结至XML 数据,以便让表格能自动一次显示全部的数据记录(或者是一次显示一页的资料,如果你启动分页的功能的话)。利用这种方法,Internet Explorer5 会帮你处理所有的程序;你不需撰写程序或呼叫方法。(但假使你选择了分页功能,就必须自己动手含括一些方法呼叫,本章稍后将介绍这种情况的处理方式。) 你可以使用单一HTML 表格来显示以简单记录集型式建构的XML 文件 或者是你可以使用巢状套迭的HTML 表格来显示包含阶层式纪录集的XML 文件。接下来的章节会详细地解释这两种显示纪录集的方法。 使用个别的HTML 表格来显示简单的纪录集 巢状的记录 ----以下列方式建构的XML 文件: . 根元素包括了一连串的record 元素,全部都是相同的型式。(本章有时将记录元素简称为record。) . 每一个记录元素包含了同一组的field 元素。(本章有时将字段元素简称field。) . 每一个字段元素只包含字符数据。(如果记录元素的子元素包含了一个或多个自己专有的子元素,DSO 将之视为巢状的记录,而不是字段。 Inventory.xml 就是这种型式的HTML 文件的范例,在这份文件中,根元素(INVENTORY) 包含了一组八个元素(BOOK 元素),而且每一笔记录元素拥有相同一组字段元素,这些字段 元素只包含字符数据。(TITLE、AUTHOR、BINDING、PAGES 与PRICE) Inventory.xml ---------------- <?xml version="1.0"?> <!--File Name:Inventory.xml --> <INVENTORY> <BOOK> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> <BOOK> <TITLE>Leaves of Grass</TITLE> <AUTHOR>Walt Whitman</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>462</PAGES> <PRICE>$7.75</PRICE> </BOOK> <BOOK> <TITLE>The Legend of Sleepy Hollow</TITLE> <AUTHOR>Washington Irving</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>98</PAGES> <PRICE>$2.95</PRICE> </BOOK> <BOOK> <TITLE>The Marble Faun</TITLE> <AUTHOR>Nathaniel Hawthorne</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>473</PAGES> <PRICE>$10.95</PRICE> </BOOK> <BOOK> <TITLE>Moby-Dick</TITLE> <AUTHOR>Herman Melville</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>724</PAGES> <PRICE>$9.95</PRICE> </BOOK> <BOOK> <TITLE>The Portrait of a Lady</TITLE> <AUTHOR>Henry James</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>256</PAGES> <PRICE>$4.95</PRICE> </BOOK> <BOOK> <TITLE>The Scarlet Letter</TITLE> <AUTHOR>Nathaniel Hawthorne</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>253</PAGES> <PRICE>$4.25</PRICE> </BOOK> <BOOK> <TITLE>The Turn of the Screw</TITLE> <AUTHOR>Henry James</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>384</PAGES> <PRICE>$3.35</PRICE> </BOOK> </INVENTORY> 当你将表格连结至XML 文件,属于每一个记录元素的数据会被显示在表格不同的列中,而记录元素的每一个子字段元素则是显示于不同的栏中。如同范例,列表8-2 中的HTML 网页包含一个表格,该表格连结到列表8-1 中Inventory.xml 文件中的数据。 Inventory Table.htm -------------------- <!--File Name:Inventory Table.htm --> <HTML> <HEAD> <TITLE>Book Inventory</TITLE> </HEAD> <BODY> <XML ID="dsoInventory" SRC="Inventory.xml"></XML> <H2>Book Inventory</H2> <TABLE DATASRC="#dsoInventory" BORDER="1" CELLPADDING="5"> <THEAD> <TH>Title</TH> <TH>Author</TH> <TH>Binding</TH> <TH>Pages</TH> <TH>Price</TH> </THEAD> <TR ALIGN="center"> <TD><SPAN DATAFLD="TITLE" STYLE="font-style:italic"></SPAN></TD> <TD><SPAN DATAFLD="AUTHOR"></SPAN></TD> <TD><SPAN DATAFLD="BINDING"></SPAN></TD> <TD><SPAN DATAFLD="PAGES"></SPAN></TD> <TD><SPAN DATAFLD="PRICE"></SPAN></TD> </TR> </TABLE> </BODY> </HTML> Inventory.xml文件透过网页里面的一个ID 为dsoInventory 的data island,而链接到列表Inventory Table.htm的HTML 网页: <XML ID="dsoInventory" SRC="Inventory.xml"></XML> 借着将网页中TABLE 元素的DATASRC 属性设定成data island 的ID,以一个算数符号(#)字符作为开头,TABLE 元素会被连结到整个XML 文件中: <TABLE DATASRC="#dsoInventory" BORDER="1" CELLPADDING="5"> 表格是以一个标准的标题(THEAD 元素)与一个列(TR 元素)定义。列中的每一个栏(即每一个TD 元素)包含了一个SPAN 元素,该SPAN 元素被连结至XML 文件的字段中以便让元素能够显示字段的内容。例如,第一个栏包含了一个连结到TITLE 字段的SPAN 元素: <TD><SPAN DATAFLD="TITLE" STYLE="font-style:italic"></SPAN></TD> SPAN 元素借着将字段的名称设定到元素的DATAFLD 属性中(在这个范例中,是TITLE),而连结到XML 字段。 下面是数据链路运作的模式:虽然TABLE 元素只定义了单一列,当浏览器显示该表格时,它会为XML 文件中的每一笔记录重复显示列元素。即,紧随标题的第一列显示了属于第一笔记录(为The Adventures of Huckleberry Finn 的BOOK 元素)的字段(TITLE、AUTHOR 等等)。接下来的列则为第二笔记录(为Leaves of Grass 的BOOK 元素),第三笔记录等等显示字段。下面是在Internet Explorer 5 中文件看起来的样子: http://jyan.w148.4everdns.com/lycos/xml/images/1.gif 你可能会怀疑为什么栏(TD)元素不直接连结到XML 字段呢。原因是TD 元素并不是一个可连结的HTML 元素。(位于295 页中的表格8-1 列出了可连结的元素。)因此,你需要包含一个可连结的元素,通常是SPAN,在每一个TD 元素中。 提示 要获得更多于第五章中介绍的操作HTML 与DHTML 相关信息,请参阅MSDN 上http://msdn.microsoft.com/workshop/author/default.asp 所列举的网站。若要参考官方的 HTML 规格,请参阅WorldWide Web Consortium (W3C) 网 站http://www.w3.org/TR/REC-html40/ 所提供的信息。 使用分页(Paging)功能 如果XML 文件包含了许多记录,你可以使用分页(paging)以一次一个群组的方式显示纪录,而不是一次将全部的记录显示在冗长的表格中。要为特定被连结的表格启动分页功能,请执行下列步骤: 1. 将被连结的TABLE 元素的DATAPAGESIZE 属性设定成你希望一次显示的最多记录个数。即记录的每个分页最多会包含你所指定的记录数目。例如,下面TABLE元素的起始卷标为DATAPAGESIZE 属性指定了5 作为属性值,这样会致使表格一次只显示5 笔记录: <TABLE DATASRC="#dsoInventory" DATAPAGESIZE="5"> 2. 为TABLE 元素的ID 属性指定一个唯一的识别代号,如下面起始标签所示: 3. <TABLE ID="InventoryTable" DATASRC="#dsoInventory "DATAPAGESIZE="5"> 4. 要在记录间浏览,可以呼叫下表中TABLE 元素的方法。注意,范例在最后一行的呼叫是假设表格拥有InventoryTable 的ID 值。 TABLE 元素的方法影响呼叫范例 -----firstPage 显示记录的第一页InventoryTable.firstPage() -----previousPage 显示记录的前一页InventoryTable.previousPage() -----nextPage 显示记录的下一页InventoryTable.nextPage() -----lastPage 显示记录的最后一页InventoryTable.lastPage() 如果目前正在显示第一页,呼叫previousPage 方法会被忽略,不进行动作;若是正在显示最后一页,呼叫nextPage 方法也会被忽略。你可以使用script 呼叫这些方法的任何一个(如同本章稍后将讨论的)。然而,最简单的方式,就是将方法设定到HTML 中BUTTON 元素的ONCLICK属性中,如下所示: <BUTTON ONCLICK="InventoryTable.nextPage()">Next Page</BUTTON> 该元素显示一个按钮。当使用者按下按钮,被指定到ONCLICK 属性的方法-InventoryTable.nextPage,会被呼叫。列表8-3 与8-4 显示了分页的技术。列表8-3 是列表8-1 中显示的Inventory.xml 文件的延伸版本。而列表8-4 则是一个HTML 网页,负责将这份XML 文件显示于其DATAPAGESIZE 属性被设定成「5」的表格中。(你将可在随书光盘的Inventory Big.xml 与Inventory Big Table.htm 档案中找到。) 在网页的顶端有4 个BUTTON 元素,每一个按钮会执行表格的分页方法。当你初次开启网页,表格会显示前5 笔记录。按下Next Page 按钮会显示下5 笔记录(若是在记录的结束部分,则还是显示原本的五笔数据),而按下Previous 按钮则会显示前5 笔记录(若在记录起始部分,则还是原来的前5 笔纪录)。按下First Page 或Last Page 按钮则是显示最前面5 笔或最后面5 笔记录。下面是列表8-4 被开启于Internet Explorer 5 中看起来的样子: http://jyan.w148.4everdns.com/lycos/xml/images/2.gif Inventory Big.xml ----------------- <?xml version="1.0"?> <!--File Name:Inventory Big.xml --> <INVENTORY> <BOOK> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> <BOOK> <TITLE>The Adventures of Tom Sawyer</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>205</PAGES> <PRICE>$4.75</PRICE> </BOOK> <BOOK> <TITLE>The Ambassadors</TITLE> <AUTHOR>Henry James</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>305</PAGES> <PRICE>$5.95</PRICE> </BOOK> <BOOK> <TITLE>The Awakening</TITLE> <AUTHOR>Kate Chopin</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>195</PAGES> <PRICE>$4.95</PRICE> </BOOK> <BOOK> <TITLE>Billy Budd</TITLE> <AUTHOR>Herman Melville</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>195</PAGES> <PRICE>$4.49</PRICE> </BOOK> <BOOK> <TITLE>A Connecticut Yankee in King Arthur's Court</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>385</PAGES> <PRICE>$5.49</PRICE> </BOOK> <BOOK> <TITLE>Joan of Arc</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>465</PAGES> <PRICE>$6.95</PRICE> </BOOK> <BOOK> <TITLE>Leaves of Grass</TITLE> <AUTHOR>Walt Whitman</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>462</PAGES> <PRICE>$7.75</PRICE> </BOOK> <BOOK> <TITLE>The Legend of Sleepy Hollow</TITLE> <AUTHOR>Washington Irving</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>98</PAGES> <PRICE>$2.95</PRICE> </BOOK> <BOOK> <TITLE>The Marble Faun</TITLE> <AUTHOR>Nathaniel Hawthorne</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>473</PAGES> <PRICE>$10.95</PRICE> </BOOK> <BOOK> <TITLE>Moby-Dick</TITLE> <AUTHOR>Herman Melville</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>724</PAGES> <PRICE>$9.95</PRICE> </BOOK> <BOOK> <TITLE>Passing</TITLE> <AUTHOR>Nella Larsen</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>165</PAGES> <PRICE>$5.95</PRICE> </BOOK> <BOOK> <TITLE>The Portrait of a Lady</TITLE> <AUTHOR>Henry James</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>256</PAGES> <PRICE>$4.95</PRICE> </BOOK> <BOOK> <TITLE>Roughing It</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>324</PAGES> <PRICE>$5.25</PRICE> </BOOK> <BOOK> <TITLE>The Scarlet Letter</TITLE> <AUTHOR>Nathaniel Hawthorne</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>253</PAGES> <PRICE>$4.25</PRICE> </BOOK> <BOOK> <TITLE>The Turn of the Screw</TITLE> <AUTHOR>Henry James</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>384</PAGES> <PRICE>$3.35</PRICE> </BOOK> </INVENTORY> 列表8-3. Inventory Big Table.htm ------------------------ <!--File Name:Inventory Big Table.htm --> <HTML> <HEAD> <TITLE>Book Inventory</TITLE> </HEAD> <BODY> <XML ID="dsoInventory" SRC="Inventory Big.xml"></XML> <H2>Book Inventory</H2> <BUTTON ONCLICK="InventoryTable.firstPage()"> |<First Page </BUTTON> <BUTTON ONCLICK="InventoryTable.previousPage()"> <Previous Page </BUTTON> <BUTTON ONCLICK="InventoryTable.nextPage()"> Next Page > </BUTTON> <BUTTON ONCLICK="InventoryTable.lastPage()"> Last Page >| </BUTTON> <p> <TABLE ID="InventoryTable" DATASRC="#dsoInventory" DATAPAGESIZE="5" BORDER="1" CELLPADDING="5"> <THEAD> <TH>Title</TH> <TH>Author</TH> <TH>Binding</TH> <TH>Pages</TH> <TH>Price</TH> </THEAD> <TR ALIGN="center"> <TD><SPAN DATAFLD="TITLE " STYLE="font-style:italic"></SPAN></TD> <TD><SPAN DATAFLD="AUTHOR"></SPAN></TD> <TD><SPAN DATAFLD="BINDING"></SPAN></TD> <TD><SPAN DATAFLD="PAGES"></SPAN></TD> <TD><SPAN DATAFLD="PRICE"></SPAN></TD> </TR> </TABLE> </BODY> </HTML> 列表8-4. 使用巢状表格来显示阶层式记录集 在前面的章节中,你已学得如何使用单一表格来显示以简单记录集型式建构的XML 文件,文件中每一笔记录包含了固定的一组字段,全部都只储存字符数据。现在你将学习如何使用巢状表格来显示特定的XML 文件,这种XML 文件的元素是以阶层式的记录集型式所建构。在阶层式的记录集中,每一笔记录除了固定的一组字段之外,还可以包含一组为数众多的巢状记录(零个或多个)。列表8-5 显示了一个建构成阶层式记录集构造的XML 文件范例。(你可在随书光盘的Inventory Hierarchy.xml 档案中找到。)在这份文件中,根元素(INVENTORY)包含了一系列的CATEGORY 记录。每一笔CATEGORY 记录由一个CATNAME 字段起始,该字段只包含字符数据。后面接着零或多个巢状的BOOK 元素。每一个巢状的BOOK 元素拥有五个字段(TITLE、AUTHOR、BINDING、PAGES 与PRICE)。 Inventory Hierarchy.xml ----------------------- <?xml version="1.0"?> <!--File Name:Inventory Hierarchy.xml --> <INVENTORY> <CATEGORY> <CATNAME>Middle Ages</CATNAME> <BOOK> <TITLE>The Canterbury Tales</TITLE> <AUTHOR>Geoffrey Chaucer</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>692</PAGES> <PRICE>$18.95</PRICE> </BOOK> <BOOK> <TITLE>Piers Plowman</TITLE> <AUTHOR>William Langland</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>385</PAGES> <PRICE>$10.95</PRICE> </BOOK> </CATEGORY> <CATEGORY> <CATNAME>Renaissance</CATNAME> <BOOK> <TITLE>The Blazing World</TITLE> <AUTHOR>Margaret Cavendish</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>225</PAGES> <PRICE>$8.79</PRICE> </BOOK> <BOOK> <TITLE>Oroonoko</TITLE> <AUTHOR>Aphra Behn</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>295</PAGES> <PRICE>$4.95</PRICE> </BOOK> <BOOK> <TITLE>Doctor Faustus</TITLE> <AUTHOR>Christopher Marlowe</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>472</PAGES> <PRICE>$15.95</PRICE> </BOOK> </CATEGORY> <CATEGORY> <CATNAME>18th Century</CATNAME> <BOOK> <TITLE>Gulliver's Travels</TITLE> <AUTHOR>Jonathan Swift</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>324</PAGES> <PRICE>$11.89</PRICE> </BOOK> <BOOK> <TITLE>The History of Tom Jones:A Foundling</TITLE> <AUTHOR>Henry Fielding</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>438</PAGES> <PRICE>$16.95</PRICE> </BOOK> <BOOK> <TITLE>Love in Excess</TITLE> <AUTHOR>Eliza Haywood</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>429</PAGES> <PRICE>$12.95</PRICE> </BOOK> <BOOK> <TITLE>Tristram Shandy</TITLE> <AUTHOR>Laurence Sterne</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>322</PAGES> <PRICE>$9.49</PRICE> </BOOK> </CATEGORY> <CATEGORY> <CATNAME>19th Century</CATNAME> <BOOK> <TITLE>Dracula</TITLE> <AUTHOR>Bram Stoker</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>395</PAGES> <PRICE>$17.95</PRICE> </BOOK> <BOOK> <TITLE>Great Expectations</TITLE> <AUTHOR>Charles Dickens</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>639</PAGES> <PRICE>$6.95</PRICE> </BOOK> <BOOK> <TITLE>Percival Keene</TITLE> <AUTHOR>Frederick Marryat</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>425</PAGES> <PRICE>$12.89</PRICE> </BOOK> <BOOK> <TITLE>Treasure Island</TITLE> <AUTHOR>Robert Louis Stevenson</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>283</PAGES> <PRICE>$11.85</PRICE> </BOOK> <BOOK> <TITLE>Wuthering Heights</TITLE> <AUTHOR>Emily Bronte</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>424</PAGES> <PRICE>$12.95</PRICE> </BOOK> </CATEGORY> </INVENTORY> 列表8-5. 列表8-6 包含了一个HTML 网页,该网页使用巢状表格来显示列表8-5 中XML 文件的阶层式记录结构。(你可以在随书光盘的Inventory Hierarchy.htm 档案中找到。) Inventory Hierarchy.htm ----------------------- <!--File Name:Inventory Hierarchy.htm --> <HTML> <HEAD> <TITLE>Inventory of Classic English Literature</TITLE> </HEAD> <BODY> <XML ID="dsoInventory" SRC="Inventory Hierarchy.xml"></XML> <TABLE DATASRC="#dsoInventory" BORDER="1"> <THEAD> <TH>Classic English Literature</TH> </THEAD> <TR> <TD><SPAN DATAFLD="CATNAME"></SPAN></TD> </TR> <TR> <TD> <TABLE DATASRC="#dsoInventory" DATAFLD="BOOK" BORDER="0" CELLSPACING="10"> <THEAD> <TH>Title</TH> <TH>Author</TH> <TH>Binding</TH> <TH>Pages</TH> <TH>Price</TH> </THEAD> <TR ALIGN="CENTER"> <TD><SPAN DATAFLD="TITLE" STYLE="font-style:italic"></SPAN></TD> <TD><SPAN DATAFLD="AUTHOR"></SPAN></TD> <TD><SPAN DATAFLD="BINDING"></SPAN></TD> <TD><SPAN DATAFLD="PAGES"></SPAN></TD> <TD><SPAN DATAFLD="PRICE"></SPAN></TD> </TR> </TABLE> </TD> </TR> </TABLE> </BODY> </HTML> 列表8-6. 在列表8-6 中,外部的表格被连结到XML 文件,在它的起始标签中你可以看到如下所示; <TABLE DATASRC="#dsoInventory" BORDER="1"> 外部的表格也包含了一个标题(这是一个THEAD 元素,显示了「Classic English Literature」),加上两个表格的列(两个TR 元素)。浏览器会为每一个顶层记录(即,每一个CATEGORY 记录)重复这两个列。前两个列显示了CATNAME 字段。到目前为止,一切就像列表8-2 中显示简单记录集的范例表格那样运作。然而,第二列,包含一个巢状的表格,显示目前目录下每一个BOOK 记录的内容,而不是显示字段。下面是仅针对巢状表格的卷标: <TABLE DATASRC="#dsoInventory" DATAFLD="BOOK" BORDER=0 CELLSPACING=10> <THEAD> <TH>Title</TH> <TH>Author</TH> <TH>Binding</TH> <TH>Pages</TH> <TH>Price</TH> </THEAD> <TR ALIGN="CENTER"> <TD><SPAN DATAFLD="TITLE" STYLE="font-style:italic"></SPAN></TD> <TD><SPAN DATAFLD="AUTHOR"></SPAN></TD> <TD><SPAN DATAFLD="BINDING"></SPAN></TD> <TD><SPAN DATAFLD="PAGES"></SPAN></TD> <TD><SPAN DATAFLD="PRICE"></SPAN></TD> </TR> </TABLE> 注意,你必须将巢状表格连结到不只是XML 文件(DATASRC = #"#dsoInventory"),同时还有巢状的BOOK 记录(DATAFLD ="BOOK"),如此表格将以巢状方式显示目前CATEGORY 记录内每一个BOOK 元素的内容。换言之,表格中的列元素(TR)将会重复这些BOOK 元素的每一个。(注意,根据默认值,外部的表格被连结至顶层的元素-范例中的CATEGORY 记录-如此它将循序显示每一个记录。) 下面是当你将列表8-6 开启于Internet Explorer 5 中,该列表看起来的样子: http://jyan.w148.4everdns.com/lycos/xml/images/3.gif 你可以使用附加的巢状表格来显示包含数层巢状记录的文件。例如,参考列表8-5 的范例文件。 假设你已经将每一个AUTHOR 字段换掉了: <AUTHOR>Geoffrey Chaucer</AUTHOR> 换成零或多个巢状的AUTHOR 记录: <AUTHOR> <FIRSTNAME>Geoffrey</FIRSTNAME> <LASTNAME>Chaucer</LASTNAME> </AUTHOR> 在这种情况中,你可以使用附加的巢状表格为每一个BOOK 元素,显示所有的作者,这是利用与单一巢状表格中所使用的相同技术。 使用单一记录的数据链路 单一记录的数据链路(Single-record data binding)指的是连结一个HTML 元素,该HTML 元素不是表格,而且也不包含在被连结的表格中。HTML 元素-例如SPAN、BUTTON 或LABEL元素-被连结到个别的XML 字段。该HTML 元素接着会自动显示自己被连结到的XML 字段的内容。例如,下面HTML 的SPAN 元素被连结到XML 文件的TITLE 字段,该XML 文件会透过名为dsoBook 的data island 被存取: <SPAN DATASRC="#dsoBook" DATAFLD="TITLE"></SPAN> 然而,因为HTML 元素并不像表格一样拥有许多部分,它只能一次一笔记录来显示字段的值。 要使用单一记录的数据链路,XML 文件必须以简单的记录集的型式组成。已经在本章稍早的< 使用个别的HTML 表格来显示简单记录集>章节中介绍过的简单记录集。 单一记录的数据链路最简单的例子就是利用只包含一笔记录的XML 文件,如列表8-7 中的范例 文件。(你可在随书光盘的Book.xml 档案中找到。) Book.xml ---------- <?xml version="1.0"?> <!--File Name:Book.xml --> <BOOK> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> 列表8-7. 列表8-8 显示了一份将个别SPAN 元素连结至范例文件中的每一个字段(TITLE、AUTHOR、BINDING、PAGES 与PRICE)的HTML 网页。(你可在随书光盘的Book.htm 档案中找到。) Book.htm ----------- <!--File Name:Book.htm --> <HTML> <HEAD> <TITLE>Book Description</TITLE> </HEAD> <BODY> <XML ID="dsoBook" SRC="Book.xml"></XML> <H2>Book Description</H2> <SPAN STYLE="font-style:italic">Title:</SPAN> <SPAN STYLE="font-weight:bold" DATASRC="#dsoBook" DATAFLD="TITLE"></SPAN> <BR> <SPAN STYLE="font-style:italic">Author:</SPAN> <SPAN DATASRC="#dsoBook " DATAFLD="AUTHOR"></SPAN> <BR> <SPAN STYLE="font-style:italic">Binding type:</SPAN> <SPAN DATASRC="#dsoBook" DATAFLD="BINDING"></SPAN> <BR> <SPAN STYLE="font-style:italic">Number of pages:</SPAN> <SPAN DATASRC="#dsoBook" DATAFLD="PAGES"></SPAN> <BR> <SPAN STYLE="font-style:italic">Price:</SPAN> <SPAN DATASRC="#dsoBook" DATAFLD="PRICE"></SPAN> </BODY> </HTML> 列表8-8. 下面是Internet Explorer 5 显示列表8-8 的样子: http://jyan.w148.4everdns.com/lycos/xml/images/8-8.gif 浏览数据记录 如果XML 文件包含超过一笔的记录(最多到它们可包含的数量),单一记录数据链路变得有点复杂,因为HTML 元素一次只能显示一笔记录。被HTML 元素显示的记录称为current record(目前记录)。(因此,单一记录连结的另一种替换方法就是current-record binding,称为目前记录连结)在一开始,目前元素就是文件中的第一笔(或唯一的)记录。与XML 文件结合的DSO 提供了一组方法让你可以呼叫在记录间浏览。这些方法属于DSO 的记录集成员对象,并且被列在下面表格中。注意,在最后一行的范例呼叫是假设HTML 网页包含 一个XML 的data island,其ID 为dsoInventory。 DSO 记录集方法 (注:原来是表格) ------------------------------------------------- 将目前记录变成 呼叫范例 文件中的第一笔记录 moveFirst moveFirst() 前一笔记录 dsoInventory.recordset. movePrevious movePrevious() 下一笔记录 dsoInventory.recordset. moveNext moveNext() 文件中的最后一笔记录 dsoInventory.recordset. moveLast moveLast() 特定数目的记录 dsoInventory.recordset.move dsoInventory.recordset.move(5)移动至第6 笔记录。记录是从0 开始计数。) -------------------------------------------------- 注意 ------ DSO 的记录集成员对象符合了Microsoft 呼叫ActiveX Data Objects (ADO)的标准数据存取技术。你可以使用一般的ADO 记录集对象,以及除了本章中介绍的XML DSO 外的多种资料来源。想获得ADO 与ADO 记录集对象的更多信息,请参考下面由Microsoft 提供,位于http://www.microsoft.com/data/ado/default.htm 的网站。想获得特定记录集的方法、属性与事件的文件,请参阅http://msdn.microsoft.com/library/psdk/dasdk/mdap2y7s.htm 。你可以从你撰写的script 来呼叫这些方法的任何一个(如同本章稍后将介绍的)。然而,呼叫这些方法最简单的方式,就是借着将方法指定到BUTTON 元素的ONCLICK 属性中,如下所示: <BUTTON ONCLICK="dsoInventory.recordset.moveFirst()"> First Record </BUTTON> 这个元素会显示一个按钮。当使用者按下按钮,被指定到ONCLICK 属性的方法-dsoInventory.recordset.moveFirst,会被呼叫。 如果目前记录是第一笔,呼叫movePrevious 方法来将记录集移动到档案的起始部分,代表无法获得任何记录,且被连结的元素将消失。同样地,当目前记录是最后一笔,呼叫moveNext 方法将记录集移动到档案的结尾部分,代表被连结的元素将会消失。很幸运地,recordset 对象提供了BOF 属性与EOF 属性。如果记录集位在档案的起始部分,BOF的属性值会被设为true。而如果记录集位在档案的结尾部分,EOF 属性值会被设为true。你可 以侦测这些属性状态并设定必要的修正。例如,指定于下列按钮中的程序代码,在记录集移动到 档案的起始部分时,它会迅速地重新显示第一笔数据记录: <BUTTON ONCLICK="dsoInventory.recordset.movePrevious(); if (dsoInventory.recordset.BOF) dsoInventory.recordset.moveNext()"> Back </BUTTON> 下面的程序修正了档案结尾部分的状态: <BUTTON ONCLICK="dsoInventory.recordset.moveNext(); if (dsoInventory.recordset.EOF) dsoInventory.recordset.movePrevious()"> Forward </BUTTON> 注意,你可以将整块的script 程序代码设定到onclick 属性(或者是其它的事件属性,如ONMOUSEOVER)。在这些范例中,程序代码是以Microsoft JScript 撰写。在本章的稍后,你将学习如何撰写独立的script 程序代码区块,让包含更多指令变得更容易。 在下面的练习中,你将建立一次一笔记录显示列表8-3 中的XML 文件的HTML 网页。该网页提供了按钮来浏览第一笔、前一笔、下一笔与最后一笔。 以一次一笔记录的方式显示文件 1. 在文字编辑器中, 开启一个新的、空白的文字文件,然后输入列表8-9 中的HTML网页。(你可以在随书光盘的Inventory Single.htm 档案中找到。)注意,该网页包含了连结到Inventory Big.xml 文件的data island ,该文件包含了16 笔记录。(列表8-3 显示了Inventory Big.xml;你也可以在随书光盘上找 到该档案。) 2. 使用文字编辑器的存盘指令来将网页储存到本机硬盘上,指定其文件名为Inventory Single.htm 。 Inventory Single.htm --------------------- <!--File Name:Inventory Single.htm --> <HTML> <HEAD> <TITLE>Book Inventory</TITLE> </HEAD> <BODY> <XML ID="dsoInventory" SRC="Inventory Big.xml"></XML> <H2>Book Description</H2> <SPAN STYLE="font-style:italic">Title:</SPAN> <SPAN DATASRC="#dsoInventory" DATAFLD="TITLE" STYLE="font-weight:bold"></SPAN> <BR> <SPAN STYLE="font-style:italic">Author:</SPAN> <SPAN DATASRC="#dsoInventory" DATAFLD="AUTHOR"> </SPAN> <BR> <SPAN STYLE="font-style:italic">Binding type:</SPAN> <SPAN DATASRC="#dsoInventory" DATAFLD="BINDING"> </SPAN> <BR> <SPAN STYLE="font-style:italic">Number of pages:</SPAN> <SPAN DATASRC="#dsoInventory" DATAFLD="PAGES"> </SPAN> <BR> <SPAN STYLE="font-style:italic">Price:</SPAN> <SPAN DATASRC="#dsoInventory" DATAFLD="PRICE"> </SPAN> <HR> <BUTTON ONCLICK="dsoInventory.recordset.moveFirst()"> |& lt;First </BUTTON> <BUTTON ONCLICK="dsoInventory.recordset.movePrevious(); if (dsoInventory.recordset.BOF) dsoInventory.recordset.moveNext()"> & lt;Back </BUTTON> <BUTTON ONCLICK="dsoInventory.recordset.moveNext(); if (dsoInventory.recordset.EOF) dsoInventory.recordset.movePrevious()"> Forward & gt; </BUTTON> <BUTTON ONCLICK="dsoInventory.recordset.moveLast()"> Last & gt;| </BUTTON> </BODY> </HTML> 列表8-9. 3. 在Windows 档案总管或目录窗口中, 双击该档名- Inventory Single.htm ,这是你在前一个步骤中储存的档案:Internet Explorer 5 将会开启并显示该档案,如下图所示: http://jyan.w148.4everdns.com/lycos/xml/images/single.gif 注意,从一开始,一直到使用者开始点选按钮,Internet Explorer 5 都只显示文件的第一笔记录。 其它的数据链路技术在接下来的章节中,你将学习数种用来连结非表格式的HTML 元素的附加技术。这些技术可以是用作单一记录数据链路的个别HTML 元素,或者是包含在被连结的HTML 表格中的HTML 元素。尤其是,你将学到: . 如何将HTML 元素连结至XML 字段 . 如何使HTML 标签包含在XML 字段中 . 如何更新高速缓存中的XML 数据 表格8-1 总结了当你研读后续章节时,需要使用的重要信息。表格列出你可以用来进行单一记录数据链路的HTML 元素-即,除了TABLE 元素之外的所有可连结的HTML 元素。表格描述了每一个元素的目的,指定被连结至XML 字段元素的特定用途,代表元素是否可以实行包含在元素被连结至的XML 字段中的HTML 卷标,并显示元素是否可以更新XML 字段的内容。这项信息在你研读接下来的章节之前并没有太大意义,在此预先提供予你参考。表格8-1. 可连结的HTML 元素(不包含TABLE 元素)。 表格: http://jyan.w148.4everdns.com/lycos/xml/linkenable.htm 如你所见,当你将SPAN 元素连结至XML 字段时,该元素会简单地显示字段的内容。这是因为SPAN 元素的innerText 属性-负责设定元素要显示的元素-被连结至XML 字段。 注意 ---- 在DHTML 中,每一个HTML 元素拥有一组属性,你可以用来透过script 程序设定或读取元素不同的特性。Internet Explorer 5 有支援DHTML。同时,如同本节中所解释的,属性会自动从它所连结XML 字段的值被设定。然而,表8-1 显示了利用某些可连结的HTML 元素,其它属性会被连结至XML 字段。注意连结一个SPAN 元素实际上连结了它的innerText 与inner-HTML 属性。innerText 属性会设定或取得元素内的文字内容,但不包含HTML 标签。inner-HTML 属性则是设定或取得元素的整个内容,包含任何的HTML 标签。 例如,利用连结的A(锚)元素(anchor,用来建立超级链接),href 属性被连结至XML 字段, 如下所示: <A DATASRC="#dsoInventory" DATAFLD="REVIEWS"> Click here for reviews </A> 这个属性,就像元素的HREF 属性,负责设定超级链接的目的地URL。因此,连结的A 元素的 目的地URL,是由XML 字段衍生而来(范例中的REVIEWS XML 字段当然必须是一个完整的 URL),而不是其文字内容。 在另一个范例中,利用INPUT 元素的可连结检查方块型态,checked 属性-负责改变元素的查核状态-被连结到XML 字段,如下所示: <INPUT TYPE="CHECKBOX" DATASRC="#dsoInventory" DATAFLD="INSTOCK"> 如果INSTOCK XML 字段是空的,或者它包含文字「0」或「false」,检查方块会被清除设定。如果它包含任何其它文字,检查方块会被选定。 而在最后一个范例中,利用IMG(影像)元素,src 属性被连结至XML 字段。这个属性,就像元素的SRC 元素,指明了包含欲显示图形数据文件的URL。列表8-10 与8-11 介绍了连结IMG元素的技巧。(你可在随书光盘的Inventory Image.xml 档案与Inventory Image Table.htm 档案中找到。) Inventory Image.xml --------------------- <?xml version="1.0"?> <!--File Name:Inventory Image.xml --> <INVENTORY> <BOOK> <COVERIMAGE>Leaves.bmp</COVERIMAGE> <TITLE>Leaves of Grass</TITLE> <AUTHOR>Walt Whitman</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>462</PAGES> <PRICE>$7.75</PRICE> </BOOK> <BOOK> <COVERIMAGE>Legend.bmp</COVERIMAGE> <TITLE>The Legend of Sleepy Hollow</TITLE> <AUTHOR>Washington Irving</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>98</PAGES> <PRICE>$2.95</PRICE> </BOOK> <BOOK> <COVERIMAGE>Moby.bmp</COVERIMAGE> <TITLE>Moby-Dick</TITLE> <AUTHOR>Herman Melville</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>724</PAGES> <PRICE>$9.95</PRICE> </BOOK> </INVENTORY> 列表8-10. Inventory Image Table.htm ---------------------------- <!--File Name:Inventory Image Table.htm --> <HTML> <HEAD> <TITLE>Book Inventory</TITLE> </HEAD> <BODY> <XML ID="dsoInventory" SRC="Inventory Image.xml"></XML> <H2>Book Inventory</H2> <TABLE DATASRC="#dsoInventory" BORDER="1" CELLPADDING="5"> <THEAD> <TH>Cover</TH> <TH>Title</TH> <TH>Author</TH> <TH>Binding</TH> <TH>Pages</TH> <TH>Price</TH> </THEAD> <TR ALIGN="center"> <TD><IMG DATAFLD="COVERIMAGE"></TD> <TD><SPAN DATAFLD="TITLE " STYLE="font-style:italic"></SPAN></TD> <TD><SPAN DATAFLD="AUTHOR"></SPAN></TD> <TD><SPAN DATAFLD="BINDING"></SPAN></TD> <TD><SPAN DATAFLD="PAGES"></SPAN></TD> <TD><SPAN DATAFLD="PRICE"></SPAN></TD> </TR> </TABLE> </BODY> </HTML> 列表8-11. 列表8-10 是一份XML 文件,在每一笔BOOK 记录中包含了名为COVER-IMAGE 的字段。每一个COVER-IMAGE 字段包含了储存书籍封面图形档案的URL。列表8-11 是与列表8-2 相同的HTML 网页,除了每一列的起始部分多了一个栏(TD 元素),该栏包含了一个IMG 元素而不是SPAN 元素。该IMG 元素被连结至XML 文件中的COVERIMAGE 字段,因此它显示每一本书封面的影像,如同下图所示: http://jyan.w148.4everdns.com/lycos/xml/images/8-10.gif 你可以拿表格8-1 中其它HTML 元素的一部份来进行试验,以便学习这些元素可连结的属性,以及当你连结这些属性时,元素如何使用XML 字段中的数据。表现HTML根据预设,如果XML 字段的字符数据碰巧包含了HTML 卷标,连结至该字段的HTML 元素将这些卷标以literal 文字的型式来处理与显示。例如,仔细考虑下面的SAPN 元素,它们被连结至AUTHOR-BIO 字段: <SPAN DATASRC="#dsoInventory" DATAFLD="AUTHOR-BIO"></SPAN> 如果AUTHOR-BIO 字段包含一个斜体字(I)元素,就像这样: <AUTHOR-BIO>Henry James was an American author who lived from 1843 to 1916,and wrote <I>The Bostonians<I>and many other works of psychologically realistic fiction.</AUTHOR-BIO> 该SPAN 元素会将HTML 卷标的字符视为literal 文字并将显示字段如下: 利用某些可连结的HTML 元素,如SPAN。你可以将DATAFORMATAS 属性的值设定成「HTML」以驱使浏览器处理包含在字段文字内的HTML 卷标,而不是单纯地将之视为literal 字符。例如,假设你将之前显示的范例SPAN 元素定义成: <SPAN DATASRC="#dsoInventory" DATAFLD="AUTHOR-BIO" DATAFORMATAS="HTML"></SPAN> 它将接着把I元素内的文字以斜体型式安排,如下所示: 注意 ------ 为DATAFORMATAS 设定默认值「TEXT」,与简单地将属性省略拥有相同的效果-它让HTML卷标的字符被当作literal 文字来进行处理。要想找出哪些元素是你可以用来透过DATA-FORMATAS="HTML"的属性设定来安排HTML,请参阅表格8-1 。这些元素在倒数第二个字段中(标记为「执行包含在XML 字段中的HTML」)的值为「Yes」。 在XML 字段中加入与执行HTML 对于修改文字部分的格式时(例如,使用I 或B 元素),以及将HTML 元素如超级链接或影像含括于文字中时,特别有用。虽然借着将HTML 标签包含于XML中来安排XML 文字违反了分离数据与格式安排的基本原则,但是当你使用数据链路时,这项技巧可能是修改格式或包含HTML 元素于字段中唯一可行的方法。(相反地,如果你使用本书讨过的显示XML 的其它方法,借着含括子元素并适当地处理它们,你可以广泛地修改格式或将元素加入XML 元素。) 当你加入HTML 标签到XML 字段中时,你不能将(<)或(&)符号照字面加入到文字中。(回忆一下,这些字符在元素的字符数据中都是不合法的。)然而,你可以使用预先定义的实体参照「& lt;」与「& amp;」,将它们加到文字中。另一种选择,会让HTML 变得更具可读性,且对大区块的HTML 特别有用,方法就是将标签包含于CDATA 区段中,如第四章中所讨论的。更新快取缓冲储存区中的XML 数据 XML 的DSO 让你可以用数种方法来修改XML 数据。然而,在你为这种可能性极度兴奋之前,记得这些技术只是修改了DSO 暂时快取在内存中的XML 数据的复本,而不是服务器上的原始XML 文件。除非你利用了相当复杂的技术来更改原始的服务器上文件(这已超过本书的范围),否则修改高速缓存上XML 数据的效用有限,而且这里我只是简单地做个介绍。借着将可修改的HTML 元素连结至特定XML 字段,你可以让使用者能够修改该XML 字段,如TEXT 型态的INPUT 元素。 表格8-1 中最右行代表允许使用者修改被元素连结的XML 字段的HTML 元素。 例如,如果你将TEXT 型态的INPUT 元素连结至TITLE 字段,而不是将SPAN 元素连结至TITLE 字段,如下所示,使用者不但可以浏览TITLE 元素的内容,还可以编辑其内容: <INPUT TYPE="TEXT" DATASRC="#dsoInventory" DATAFLD="TITLE"> 同时,DSO 的recordset 成员对象提供了方法让你可以从高速缓存上的记录集新增或移除整个记录,并取消对记录集所做的修改。注意,在最后一行的呼叫范例假设HTML 网页包含一个XMLdata island,其ID 为dsoInventory。 DSO 记录集方法 影响呼叫范例 AddNew 新增一笔新的记录到快取的记录集中 dsoInventory.recordset.addNew() delete 将目前的记录从快取的记录集中移除 dsoInventory.recordset.delete() cancelUpdate 保留对目前记录所做的修改,或将新增的记录取消掉 dsoInventory.recordset.cancelUpdate() 利用DTD 与数据链路 到目前为止你在本章中所见到的每一份范例文件都拥有一个格式正确的XML 文件,里面不含文件型态宣告(DTD)。然而,如果你正要使用数据链路来显示XML 文件,包含DTD 并确保文件是有效的,当你定义文件的元素时,将可以帮助你确保符合对称式记录集组织的要求。DTD也会帮助确保DSO 属性从文件中的元素来适当地建造其快取记录集。 包含DTD 对于拥有较复杂的阶层式型态记录结构特别有用,你可以显示于巢状的表格中。列表8-5 中的文件就是这样的一个范例。在下面的练习中,你将新增一个DTD 到文件中,使文件有效并确保文件符合数据链路所需要的记录结构。 注意,如果你以数据链路显示的XML 文件包含了任何有效性的错误,资料将不会显示于被连结的元素中,但你也不会看到任何错误讯息。要观看在连结的XML 文件中任何错误的辅助性叙述,利用于第九章中<检查XML 文件的有效性>所介绍的有效性与格式正确性的检查script 来测试文件。 警告 当你为记录建立元素的宣告(如列表8-12 中的CATEGORY 或BOOK 元素),你必需包含一个内容模型,明确地列出所有记录的字段与巢状记录。你不能使用ANY 内容规则,它会导致数据链路失败。 为数据链路建立有效的XML 文件 1. 在文字编辑器中,将你在本章稍早所建立的Inventory Hierarchy.xml 文件开启。(你可以在列表8-5 与随书光盘上找到这份文件。) 2. 在文件的元素(INVENTORY)上,输入下面的文件型态宣告: 3. <!DOCTYPE INVENTORY 4. [ 5. <!ELEMENT INVENTORY (CATEGORY*)> 6. <!ELEMENT CATEGORY (CATNAME,BOOK*)> 7. <!ELEMENT CATNAME (#PCDATA)> 8. <!ELEMENT BOOK (TITLE,AUTHOR,BINDING,PAGES,PRICE)> 9. <!ELEMENT TITLE (#PCDATA)> 10. <!ELEMENT AUTHOR (#PCDATA)> 11. <!ELEMENT BINDING (#PCDATA)> 12. <!ELEMENT PAGES (#PCDATA)> 13. <!ELEMENT PRICE (#PCDATA)> 14. ] > 这些元素宣告可以被解释,使用记录集与数据链路的语言,如下所示: o <!ELEMENT INVENTORY (CATEGORY * )> 文件包含了零或多个CATEGORY 记录。 o <!ELEMENT CATEGORY (CATNAME, BOOK * )> 每一个CATEGORY 记录包含一个CATEGORY 字段,后面紧跟着零或多个巢状的BOOK 记录。 o <!ELEMENT BOOK (TITLE, AUTHOR, BINDING,PAGES,PRICE)> 每一个巢状的BOOK 记录只包含恰好一个后面字段中的任何一个,依照顺序为TITLE、AUTHOR、BINDING、PAGES与PRICE。 o <!ELEMENT TITLE (#PCDATA)> 与剩下的宣告。每一个BOOK 记录中的字段只包含字符数据。 15. 要反映出欲设定的档名,将文件起始部分的批注从 <!--File Name:Inventory Hierarchy.xml --> 改成: <!--File Name:Inventory Hierarchy Valid.xml --> 16. 利用文字编辑器的另存新文件指令来将修改过的文件储存在Inventory Hierarchy Valid.xml 中。列表8-12 中显示了完整的XML 文件。(你可在随书光盘的Inventory Hierarchy Valid.xml 档案中找到。) Inventory Hierarchy Valid.xml ---------------------------- <?xml version="1.0"?> <!--File Name:Inventory Hierarchy Valid.xml --> <!DOCTYPE INVENTORY [ <!ELEMENT INVENTORY (CATEGORY*)> <!ELEMENT CATEGORY (CATNAME,BOOK*)> <!ELEMENT CATNAME (#PCDATA)> <!ELEMENT BOOK (TITLE,AUTHOR,BINDING,PAGES,PRICE)> <!ELEMENT TITLE (#PCDATA)> <!ELEMENT AUTHOR (#PCDATA)> <!ELEMENT BINDING (#PCDATA)> <!ELEMENT PAGES (#PCDATA)> <!ELEMENT PRICE (#PCDATA)> ] > <INVENTORY> <CATEGORY> <CATNAME>Middle Ages</CATNAME> <BOOK> <TITLE>The Canterbury Tales</TITLE> <AUTHOR>Geoffrey Chaucer</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>692</PAGES> <PRICE>$18.95</PRICE> </BOOK> <BOOK> <TITLE>Piers Plowman</TITLE> <AUTHOR>William Langland</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>385</PAGES> <PRICE>$10.95</PRICE> </BOOK> </CATEGORY> <CATEGORY> <CATNAME>Renaissance</CATNAME> <BOOK> <TITLE>The Blazing World</TITLE> <AUTHOR>Margaret Cavendish</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>225</PAGES> <PRICE>$8.79</PRICE> </BOOK> <BOOK> <TITLE>Oroonoko</TITLE> <AUTHOR>Aphra Behn</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>295</PAGES> <PRICE>$4.95</PRICE> </BOOK> <BOOK> <TITLE>Doctor Faustus</TITLE> <AUTHOR>Christopher Marlowe</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>472</PAGES> <PRICE>$15.95</PRICE> </BOOK> </CATEGORY> <CATEGORY> <CATNAME>18th Century</CATNAME> <BOOK> <TITLE>Gulliver's Travels</TITLE> <AUTHOR>Jonathan Swift</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>324</PAGES> <PRICE>$11.89</PRICE> </BOOK> <BOOK> <TITLE>The History of Tom Jones:A Foundling </TITLE> <AUTHOR>Henry Fielding</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>438</PAGES> <PRICE>$16.95</PRICE> </BOOK> <BOOK> <TITLE>Love in Excess</TITLE> <AUTHOR>Eliza Haywood</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>429</PAGES> <PRICE>$12.95</PRICE> </BOOK> <BOOK> <TITLE>Tristram Shandy</TITLE> <AUTHOR>Laurence Sterne</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>322</PAGES> <PRICE>$9.49</PRICE> </BOOK> </CATEGORY> <CATEGORY> <CATNAME>19th Century</CATNAME> <BOOK> <TITLE>Dracula</TITLE> <AUTHOR>Bram Stoker</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>395</PAGES> <PRICE>$17.95</PRICE> </BOOK> <BOOK> <TITLE>Great Expectations</TITLE> <AUTHOR>Charles Dickens</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>639</PAGES> <PRICE>$6.95</PRICE> </BOOK> <BOOK> <TITLE>Percival Keene</TITLE> <AUTHOR>Frederick Marryat</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>425</PAGES> <PRICE>$12.89</PRICE> </BOOK> <BOOK> <TITLE>Treasure Island</TITLE> <AUTHOR>Robert Louis Stevenson</AUTHOR> <BINDING>trade paperback</BINDING> <PAGES>283</PAGES> <PRICE>$11.85</PRICE> </BOOK> <BOOK> <TITLE>Wuthering Heights</TITLE> <AUTHOR>Emily Bronte</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>424</PAGES> <PRICE>$12.95</PRICE> </BOOK> </CATEGORY> </INVENTORY> 列表8-12. 17. 在文字编辑器中, 开启你在本章稍早所建立的Inventory Hierarchy.htm 档案。(你可在随书光盘与列表8-6 中找到。) 18. 更改网页data island 的SRC 属性,好让它连结到你刚建立的新XML 文件。那也就是说,将它从 <XML ID="dsoInventory" SRC="Inventory Hierarchy.xml"></XML> 改成: <XML ID="dsoInventory" SRC="Inventory HierarchyValid.xml"></XML> 19. 要反映出你将设定的新档名,将位于网页起始部分的批注从 <!--File Name:Inventory Hierarchy.htm --> 改成: <!--File Name:Inventory Hierarchy Valid.htm --> 20. 使用文字编辑器的另存新文件指令,将修改过的网页储存为InventoryHierarchy Valid.htm 档案。 列表8-13 显示了完整的HTML 网页。(你可在随书光盘的Inventory HierarchyValid.htm 档案中找到。) Inventory Hierarchy Valid.htm --------------------------------- <!--File Name:Inventory Hierarchy Valid.htm --> <HTML> <HEAD> <TITLE>Inventory of Classic English Literature</TITLE> </HEAD> <BODY> <XML ID="dsoInventory" SRC="Inventory Hierarchy Valid.xml"> </XML> <TABLE DATASRC="#dsoInventory" BORDER="1"> <THEAD> <TH>Classic English Literature</TH> </THEAD> <TR> <TD><SPAN DATAFLD="CATNAME"></SPAN></TD> </TR> <TR> <TD> <TABLE DATASRC="#dsoInventory" DATAFLD="BOOK" BORDER=0 CELLSPACING=10> <THEAD> <TH>Title</TH> <TH>Author</TH> <TH>Binding</TH> <TH>Pages</TH> <TH>Price</TH> </THEAD> <TR ALIGN="CENTER"> <TD><SPAN DATAFLD="TITLE" STYLE="font-style:italic"></SPAN></TD> <TD><SPAN DATAFLD="AUTHOR"></SPAN></TD> <TD><SPAN DATAFLD="BINDING"></SPAN></TD> <TD><SPAN DATAFLD="PAGES"></SPAN></TD> <TD><SPAN DATAFLD="PRICE"></SPAN></TD> </TR> </TABLE> </TD> </TR> </TABLE> </BODY> </HTML> 列表8-13. 21. 在Internet Explorer 5 中开启这份网页。 它看起来应该像这样: http://jyan.w148.4everdns.com/lycos/xml/images/8-13.gif 22. 如果文件并未出现,该文件必定是出现了格式正确性或有效性的错误。要找出错误,请使用第九章中<检查XML 文件的有效性>所介绍的有效性检查script。将HTML 元素连结到XML 属性 截至目前为止你所看到的XML 文件范例,并没有元素包含了属性。虽然你可以连结至包含属性的元素如同连结至属性本身,但是属性却使得数据链路更为复杂。 当你使用数据链路,属性在本质上是以子元素的型式被处理。 利用record 元素,这种处理方法让存取属性变得更容易(或者仅将之忽略掉)。例如,下列的BOOK 元素包含一个名位的InStock 属性: <BOOK InStock="yes"> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> 这笔记录将会被处理,犹如InStock 属性是一个属于BOOK 的字段,而InStock 的值为该字段的内容。也就是说,BOOK 将会被看做拥有下列的结构: <BOOK> <InStock>yes</InStock> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> 因此你可以利用普通的数据链路技巧来存取属性的值。例如,下面的SPAN 元素被连结至属性,并显示了属性的值: <SPAN DATASRC="#dsoInventory" DATAFLD="InStock"></SPAN> (这个范例假设XML 文件透过一个名为dsoInventory 的data island 被连结至网页。)然而,思考一下,将属性加到XML 文件中的字段元素中-例如,将属性加入AUTHOR 字段, 如下面范例所示: <BOOK> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR Born="1835">Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> 在数据链路中,AUTHOR 元素将会被解释成这样: <AUTHOR> <Born>1835</Born> Mark Twain </AUTHOR> 结果是,DSO 将会将元素以巢状记录的型式储存,而不是以字段的型式。(回忆一下字段可以只包含字符数据,且不含子元素。)因此,记录集将会变成一个阶层式的记录集,而不是一个简单的普通记录集,而且你必须使用巢状表格来显示里面的巢状资料,如同本章稍早<使用巢状表格来显示阶层式记录集>中所介绍的。 然而,你需要更多的东西,好让你能够显示字符数据(Mark Twain)与巢状记录的属性:DSO使用特殊的名称$TEXT 来参考元素内的所有字符数据,而不是利用含括属性值的方式。因此,IE5 将会把AUTHOR 元素解释成这样: <AUTHOR> <Born>1835</Born> <$TEXT>Mark Twain</$TEXT> </AUTHOR> 你可以使用$TEXT 当作字段名称来将表格的栏连结至AUTHOR 元素字符数据的内容。 列表8-14 包含一个HTML 网页,该网页显示了本节中所介绍的所有技术。(你可以在随书光盘的Inventory Attribute.htm 档案中找到。)该网页显示了XML 文件: Inven-tory Valid.xml (你可以在随书光盘中的列表5-1 中找到该文件)。 Inventory Attribute.htm -------------------------- <!--File Name:Inventory Attribute.htm --> <HTML> <HEAD> <TITLE>Book Inventory</TITLE> </HEAD> <BODY> <XML ID="dsoInventory" SRC="Inventory Valid.xml"></XML> <H2>Book Inventory</H2> <TABLE DATASRC="#dsoInventory" BORDER="1" CELLPADDING="5"> <THEAD> <TH>Title</TH> <TH>Author</TH> <TH>Binding</TH> <TH>Pages</TH> <TH>Price</TH> <TH>In Stock?</TH> </THEAD> <TR ALIGN="center"> <TD> <TABLE DATASRC="#dsoInventory" DATAFLD="TITLE"> <TR> <TD><SPAN DATAFLD="$TEXT"></SPAN></TD> </TR> </TABLE> </TD> <TD> <TABLE DATASRC="#dsoInventory" DATAFLD="AUTHOR"> <TR> <TD><SPAN DATAFLD="$TEXT"></SPAN></TD> <TD><SPAN DATAFLD="Born"></SPAN></TD> </TR> </TABLE> </TD> <TD><SPAN DATAFLD="BINDING"></SPAN></TD> <TD><SPAN DATAFLD="PAGES"></SPAN></TD> <TD><SPAN DATAFLD="PRICE"></SPAN></TD> <TD><SPAN DATAFLD="InStock"></SPAN></TD> </TR> </TABLE> </BODY> </HTML> 列表8-14. 下面是Internet Explorer 5 显示列表8-14 看起来的样子: http://jyan.w148.4everdns.com/lycos/xml/images/8-14.gif 在这个网页中,外部表格的最后一行借着简单地将BOOK 记录的InStock 属性连结至SAPN元素素,显示了InStock 属性的内容: <TD><SPAN DATAFLD="InStock"></SPAN></TD> 因为BOOK 元素的AUTHOR 子元素包含一个属性(Born),该属性被当作巢状的元素来处理,而不是字段,因而网页是使用巢状的表格来显示属性的内容: <TD> <TABLE DATASRC="#dsoInventory" DATAFLD="AUTHOR"> <TR> <TD><SPAN DATAFLD="$TEXT"></SPAN></TD> <TD><SPAN DATAFLD="Born"></SPAN></TD> </TR> </TABLE> </TD> 特殊名称$TEXT 参考了AUTHOR 元素内的所有文字,但并不包含属性值。这份文字由作者名字(例如,Mark Twain)所组成。 注意,因为BOOK 中的TITLE 元素可以包含一个子元素(SUBTITLE),该元素也被视为一个巢状的记录,而不是字段,而且同样必须使用巢状的表格来显示: <TD> <TABLE DATASRC="#dsoInventory" DATAFLD="TITLE"> <TR> <TD><SPAN DATAFLD="$TEXT"></SPAN></TD> </TR> </TABLE> </TD> 这里,$TEXT 被用来显示记录的所有字符数据。(并没有方法能够只显示标题的文字而不包含子标题。) 使用Script 与DSO本章利用一个较复杂的script 范例作个总结。该script 利用DSO 与相关XML 文件的记录集来运作。这份范例script 使用DSO 的recordset 对象的方法与属性来搜寻Inventory Big.xml 文件中的书籍。(你可以在随书光盘与列表8-3 中找到这份文件。)用来搜寻与显示XML 文件的技术,只对以简单记录集型式组成的XML 文件合适。(有关简单记录集的信息,请参阅本章稍早的<使用个别的HTML 表格来显示简单记录集> 。) 提示 ----- 你将在第九章中看到更多的script 档案。该章中的script 使用了完全不同的程序对象(XML 文件对象模型),让你可以使用任何型式的XML 文件,不只是那些以记录集建构的XML 文件。列表8-15 代呈现了包含范例script 的HTML 网页。你可在随书光盘中的Inventory Find.htm 档案中找到。 Inventory Find.htm -------------------- <!--File Name:Inventory Find.htm --> <HTML> <HEAD> <TITLE>Book Finder</TITLE> </HEAD> <BODY> <XML ID="dsoInventory " SRC="Inventory Big.xml"></XML> <H2>Find a Book</H2> Title text:<INPUT TYPE="TEXT" ID="SearchText"> <BUTTON ONCLICK='FindBooks()'>Search</BUTTON> <HR> Results:<P> <DIV ID=ResultDiv></DIV> <SCRIPT LANGUAGE="JavaScript"> function FindBooks () { SearchString =SearchText.value.toUpperCase(); if (SearchString =="") { ResultDiv.innerHTML ="<You must enter text into" +"'Title text' box..>"; return; } dsoInventory.recordset.moveFirst(); ResultHTML =""; while (!dsoInventory.recordset.EOF) { TitleString =dsoInventory.recordset("TITLE").value; if (TitleString.toUpperCase().indexOf(SearchString) >=0) ResultHTML +="<I>" +dsoInventory.recordset("TITLE") +"</I>," +"<B>" +dsoInventory.recordset("AUTHOR") +"</B>," +dsoInventory.recordset("BINDING") +"," +dsoInventory.recordset("PAGES") +" pages,," +dsoInventory.recordset("PRICE") +"<P>"; dsoInventory.recordset.moveNext(); } if (ResultHTML =="") ResultDiv.innerHTML ="<no books found>"; else ResultDiv.innerHTML =ResultHTML; } </SCRIPT> </BODY> </HTML> 列表8-15. 这份HTML 网页显示了TEXT 类型的INPUT 元素,让使用者输入一行欲搜寻的文字: <INPUT TYPE="TEXT" ID="SearchText"> 该网页也显示一个卷标为「Search」的BUTTON 元素: <BUTTON ONCLICK='FindBooks()'>Search</BUTTON> 当使用者点选按钮,script 函式FindBooks 会被呼叫,负责将要搜寻的文字从INPUT 元素中取出,搜寻XML 文件中的所有BOOK 记录的标题是否符合该文字,然后将符合的BOOK 记录显示,如下图所示: http://jyan.w148.4everdns.com/lycos/xml/images/8-15.gif script 函式FindBooks 被包含在其专有的SCRIPT 元素中,利用JScript 来撰写: <SCRIPT LANGUAGE="JavaScript"> function FindBooks () { SearchString =SearchText.value.toUpperCase(); if (SearchString =="") { ResultDiv.innerHTML ="<You must enter text into" +"'Title text ' box..>"; return; } dsoInventory.recordset.moveFirst(); ResultHTML =""; while (!dsoInventory.recordset.EOF) { TitleString =dsoInventory.recordset("TITLE").value; if (TitleString.toUpperCase().indexOf(SearchString)>=0) ResultHTML +="<I>" +dsoInventory.recordset("TITLE") +"</I>," +"<B>" +dsoInventory.recordset("AUTHOR") +"</B>," +dsoInventory.recordset("BINDING") +"," +dsoInventory.recordset("PAGES") +" pages,," +dsoInventory.recordset("PRICE") +"<P>"; dsoInventory.recordset.moveNext(); } if (ResultHTML =="") ResultDiv.innerHTML ="<no books found>"; else ResultDiv.innerHTML =ResultHTML; } </SCRIPT> 提示 ------ JScript 是Microsoft 版本的JavaScript 程序语言。(在范例的SCRIPT 区块中,LANGUAGE 属性提供了一般程序语言的名称。)你将可以在下面的网站http://msdn.microsoft.com/workshop/c-frame.htm#/workshop/languages/jscript/handling.asp 与http://msdn.microsoft.com/ scripting/default.htm?/scripting/jscript/default.htm 中,找到JScript 完整的信息,包括为初学者所制作的导览。这两个网站都是由MSDN 所提供。 FindBooks 函式借着取得目前被输入INPUT 元素的文字(其ID 为SearchText)开始,接着使用Jscript 函式toUpperCase 来将文字转换成大写字母。(FindBooks 将所有的文字转换成大写好让搜寻的动作是没有大小写之分。) SearchString =SearchText.value.toUpperCase(); 如果使用者并未在INPUT 元素输入任何东西,函式会显示一个错误讯息并退出执行: if (SearchString =="") { ResultDiv.innerHTML ="<You must enter text into" +"'Title text ' box..>"; return; } ResultDiv 是位于网页底部的DIV 元素的ID,负责显示搜寻结果。为DIV 元素的innerHTML 属性指定文字(可以包含HTML 卷标)将会导致DIV 显示该文字(并执行它所包含的HTML 标签)。函式接着会让第一笔XML 文件成为目前的记录,使用你在之前所见过的recordset.moveFirst方法: dsoInventory.recordset.moveFirst(); 接下来它会将用来储存搜寻结果(ResultHTML) 的HTML 的字符串变量设成空白: ResultHTML =""; 现在FindBooks 会进入循环以浏览XML 文件中的所有记录。当到达档案的结尾时,它使用recordset.EOF 属性来停止循环的进行,并且使用recordset.moveNext 在每一笔新记录中移动: while (!dsoInventory.recordset.EOF) { TitleString =dsoInventory.recordset("TITLE").value; if (TitleString.toUpperCase().indexOf(SearchString)>=0) ResultHTML +="<I>" +dsoInventory.recordset("TITLE") +"</I>," +"<B>" +dsoInventory.recordset("AUTHOR") +"</B>," +dsoInventory.recordset("BINDING") +"," +dsoInventory.recordset("PAGES") +" pages,," +dsoInventory.recordset("PRICE") +"<P>"; dsoInventory.recordset.moveNext(); } 循环首先会取得目前记录的TITLE 字段的值: TitleString =dsoInventory.recordset("TITLE").value; 等号右边的表达式是呼叫recordset 对象的fields 属性的速记法。下面是完整的做法: TitleString =dsoInventory.recordset.fields("TITLE").value; fields 属性包含一个属于目前记录全部字段的集合。你可以借着将字段的名称放在参数中(例如, 范例中的「TITLE」)来存取特定的字段,而且借着附加value 属性你可以以字符串型态获得该 字段的内容。 循环接着使用JScript 函式indexOf 来决定目前记录标题是否包含了欲搜寻的文字。如果循环找 到欲搜寻的文字,if 指令中的程序会将文字放到ResultHTML 字符串与必要的HTML 卷标以显示 目前的记录: if (TitleString.toUpperCase().indexOf(SearchString) >=0) ResultHTML +="<I>" +dsoInventory.recordset("TITLE") +"</I>," +"<B>" +dsoInventory.recordset("AUTHOR") +"</B>," +dsoInventory.recordset("BINDING") +"," +dsoInventory.recordset("PAGES") +" pages,," +dsoInventory.recordset("PRICE ") +"<P>"; 一但循环结束,函式会将包含搜寻结果的HTML 卷标贴附到DIV 元素的innerHTML 属性中,这个元素是位于用来显示搜寻结果网页的BODY 元素中(该DIV 元素的识别代号为ResultDiv): if (ResultHTML =="") ResultDiv.innerHTML ="<no books found>"; else ResultDiv.innerHTML =ResultHTML; DIV 元素会立即执行HTML 卷标并显示结果。
|