XML 问题: Ajax 权衡:XML 的多种风格

来源:百度文库 编辑:神马文学网 时间:2024/04/28 09:33:46
选择很多。Ajax 中的 X 代表 XML,但是 XML 并非一种语言,它是一种用来构建语言的工具。所以,您要做的第一项决定是:是使用一种现有的语言,还是构建自己的语言?这要涉及几方面的权衡。必须考虑是否有一种现有的语言能够满足自己的需要,或者您是否能够设计一种更适合需要的语言?是否有处理这种语言的工具,还是必须自己构建工具?如果您要与别人交流(如果不需要与别人交流,那为什么要构建 Web 应用程序呢?),那么别人也熟悉这种语言吗?其他应用程序能顺利访问和使用您的数据吗?
可以从以下格式中进行选择:(X)HTML(包括微格式子集)、SVG 或 X3D(用于图形数据)、Atom(用于随时间变化的数据片段)、OPML(用于简单的大纲)和 RDF(用于语义性图表)。在极端情况下,可以发送 DocBook、DITA 或 OpenOffice 格式的数据,这些格式非常复杂、具有语义性而且功能全面。(关于这些格式的更多信息参见参考资料。)
在另一个极端,可以不理会 XML,转而发送任何类型的数据。可以发送二进制数据、图像、电影或 PDF 文件;但这是一种倒退,这些数据很难在浏览器中用 JavaScript 进行操作。更易于为人接受的方法是,发送比 XML 简单的文本格式:由制表符或逗号分隔的列表、Markdown 或其他结构化程度较低的文本、YAML 或 JSON。即使不使用完整的 XML,您也有几十种选择,XML Alternatives 站点对这些技术做了全面介绍(参见参考资料)。总之,选择的范围非常广,从最丰富也最复杂的,到没那么丰富更为简单的。而且,即使对于下面列表的一种格式,也可以找到多种数据编码方法,所以这个分类是有争议的,只能算是一种粗略的分类。
OpenOffice Spreadsheet DITA(Darwin Information Typing Architecture) DocBook RDF-XML XHTML Microformat Atom OPML(Outline Processor Markup Language) Custom XML Markdown / Textile / reStructured Text YAML(YAML Ain‘t Markup Language) JSON(JavaScript Object Notation) 由逗号或制表符分隔的文本
面对如此之多的选择,如何做出合理的决定呢?出于如下几个原因,上面的列表无法严格地按照复杂性的次序排列。
首先,大多数格式都可以按照简单方式或复杂方式使用。 其次,必须区分复杂性表现在哪些方面:创建、读取、解析还是处理?XML 本身是相当复杂的,但是现有的工具比较成熟,例如浏览器中已经存在的解析器会使解析步骤简化。 第三,复杂性在很大程度上依赖于要处理的数据类型。数据是否具有非常严格的结构,比如电子表格或数据库?数据的结构是否非常松散,比如字处理文档或 blog 文章?数据是大文档(比如飞机的操作手册),还是小的数据片段(比如响应编码)?如果数据集非常大,那么是必须同时发送完整的数据集,还是可以根据需要发送它的片段?将大数据集分割为小片段是否很困难?为了在另一端将小片段正确地重新组装起来,必须添加多少额外信息?
那么,最关键的因素是什么?它们包括:
详细程度/带宽(不像您想象得那么重要,只是有时候很重要) 可读性(以及可写性和可维护性) 解析的简便性(客户端和服务器端) 解析的速度(本机还是通过脚本) 信息丢失(比如,有序对 -> 词典 -> 集) 灵活性(有时候,灵活性低反而更好,这样更容易预测会发生的情况) 语言可移植性(可以用多少种语言操作这种格式?) 正确性(是否能够轻松地检查和确保数据符合格式?) 往复转换(即 Markdown -> XHTML -> Markdown,在这个过程中会丢失多少数据?)
在大多数情况下,优化的目标并不是速度、带宽利用率或者其他效率指标,而是更模糊的目标:用户满意度。即使有轻微的网络延迟,如果能够将延迟掩盖起来,让更新显得 很及时,那么这点延迟就不是问题了。毕竟,让用户更满意就是 Ajax 比生成完整的新 Web 页面更先进的原因。




回页首
在这里,我先给出一些经验性规则,然后用一些示例证明它们。根据下面的示例和我自己构建 Web 应用程序的经验,我总结出了下面这些规则,在使用 Ajax 时可以依据这些规则选择数据格式。(编辑提示:Dethe Elza 是本文以下部分的作者。)
对于数据,使用 JSON:如果您拥有结构化或半结构化的数据,那么选择 JSON。浏览器中至少内置了三种解析器(HTML、XML 和 JavaScript),速度最快的是 JavaScript。另外,如果用 JavaScript 操作数据,而数据已经存在于 JavaScript 中,就不需要进行复杂的 DOM 操作。如果数据不直接用于显示,或者需要先做修改,或者将显示在 Web 页面的不同部分中,或者具有不同的格式,那么 JSON 可能是不错的选择。如果数据适合关系数据库,那么 JSON 也是合适的选择。大多数编程语言都有很好的 JSON 库,所以不只能够用 JavaScript 进行操作。 对于混合型内容(文档),使用 XML:如果需要使用元数据(比如 URL)或标记和文本的各种混合形式,比如字处理文档和 blog 文章,那么就使用 XML。如果数据将在一个位置直接显示,就可以在服务器上对它进行格式化,然后使用 Ajax 检索它并将它直接插入文档(这种技术有时候称为客户端包含)。正如 David 在他的 MochiKit 文章中指出的(参见参考资料),可以将 XML 提供给现代浏览器并用 CSS 对它进行格式化,也可以提供 HTML 并选择是否应用样式。关于应该使用哪种 XML,我无法提供太多建议;但是,如果某种标准格式(比如 XHTML、SVG 或 X3D)能够很好地 适应您的数据,就可以选用它。这样就可以使用这种格式的一个小子集,使数据具有更强的可互操作性,而且其他程序员也更熟悉这些标准格式,它们的文档也更完善。有时候,创建自己的 XML 格式是有好处,但是这会降低可互操作性,所以必须在某些基本方面能够获得很大的 改进,才值得这么做。如果不确定的话,就采用 HTML,这是 Web 的通用语言。 为了联合,使用 Atom:我这里所说的联合的含义非常广泛。如果您的数据将定期更新,那么可以将它放在 Atom 中。如果数据应该加上时间戳,也可以使用 Atom。基本上,对于任何随时间变化的数据流,都可以将 Atom 格式作为标准的包装。这样,就可以使用许多现有的工具,通过聚合器、新闻阅读器和脚本库跟踪和重用数据。可以以这种方式将数据插入 Web 页面,而且只需稍做努力,就可以将它转换为联合 feed。




回页首
现在,看看对于同样的示例数据使用不同格式的情况,以及如何使用这些格式。以前的两篇专栏文章(参见参考资料)使用简单的示例以便将重点放在机制上,但是这一次要使用取自真实环境的数据。我的妻子 Daniela 是一位诗人,她总是仔细地记录她向杂志、比赛和其他活动的投稿。她需要记录每篇诗稿处于什么阶段、哪些被接受了、哪些被拒绝了、每篇诗稿获得了多少稿费、她为每次活动花费了多少以及其他信息。清单 1 给出了一部分数据:
Room of One‘s Own Submitted May 10, ‘05 * Hyacinth Blue * Fabrication * Thanksgiving * Spilling the Peas Accepted Hyacinth Blue Accepted Sept 2005 Published Oct 2006 Paid Sept 2006 Paid $50 + 2 copies Postage $1.12 Submission Fee: 0 Journal submission Surrey International Writer‘s Contest Contest submission Submitted Aug. 31 2006 * 13th Child Fee: $15 Postage: 1.05 Honorable Mention Prize: $150 + copy of anthology Accepted Sept. 26 2006 Publication Date Oct. 20 2006 Word on the Street Public Reading Invited speaker Reading time: 10 minutes Paid: T-shirt and lunch Date: Sept 24 2006 Paideusis: The Journal of the Canadian Philosophy of Education Society Submitted Oct. 13th 2006 * To carry over: metaphor invents us (seven poems) Email submission Referreed Journal Accepted Oct. 16th 2006 Published (Pending) Nov. 2006
最初,她能够顺利地使用这些数据,但是随着投稿越来越多,跟踪每篇诗稿的状态越来越难了。很难统计她在一年中的收入和花费,而且她还希望能够提取其他信息,比如平均回应时间(从投稿到被接受或拒绝之间的时间)。所以,我打算为她构建一个应用程序,我将这个程序称为 “Fame Not Fortune”,而且我认为它很适合成为 Ajax 驱动的 Web 应用程序。
当然,因为我很懒,所以希望使用现有的应用程序,而不是构建一个新的应用程序。她已经使用 Open Office(字处理)(参见参考资料)来编辑诗稿,所以她可以使用 Open Office(电子表格)来跟踪信息。图 1 显示 Open Office 电子表格的外观:

现在,出现了一些问题。尤其是,电子表格并不是跟踪这些信息的最自然的界面。被跟踪的数据非常灵活,所以许多列并未在每个条目中都被用到,而且我的目标用户(Daniela)觉得填写电子表格不如访问 Web 站点那么自然和轻松。因此,我产生了构建 Web 应用程序的想法。当然,因为 Open Office 将它的文档保存为 XML 格式,所以我认为可以结合 Open Office 和 Web 应用程序两者的优势,让 Daniela 可以使用 Open Office 执行比较复杂的数据挖掘任务,并使用 Web 进行数据输入。在这种情况下,让数据存储为同一种格式可能是种好想法。
在 Open Office 中,保存的格式是 .odf 文件,这实际上只是一个 .zip 文件,其中包含数据和其他资源(嵌入的图像、脚本、样式信息等等)。通过查看这个非常简单的文档内部,我发现了以下内容:
META-INF 文件夹,其中包含 manifest.xml,这是 .odf 文档内容的清单 Configurations2 文件夹,其中包含一些与用户界面(比如状态栏、菜单等等)相关的内容。我认为目前可以不用理会这些。 Thumbnails 文件夹,其中包含文档的一个小 .png 图像 content.xml 文件,它似乎是我输入的实际数据 meta.xml 文件,其中包含关于文档的信息:创建者、修改的日期和其他细节 mimetype 文件,包含字符串 “application/vnd.oasis.opendocument.spreadsheet” settings.xml 文件,包含我在 Open Office 中设置的所有首选项 styles.xml 文件,包含电子表格的格式化信息
所以,如果我希望在 Web 应用程序和 Open Office 之间发送数据,那么我感兴趣的实际上不是整个 .odf 文件,只是其中包含的 content.xml。当我查看这个文件时,我看到了什么?它长达 17,629 个字符,包含 23 个 XML 名称空间,63 行样式信息(尽管只有一个样式文件),而且每个单元格还有样式信息。对于桌面电子表格应用程序,这些东西也许可以保留,但是我不希望浪费时间在网络上传递这些不必要的信息,然后解析它,区分它的类别,最后丢弃它。清单 2 给出一个小片段和一行实际数据以供比较:
Room of One‘s Own Journal Hyacinth Blue; Fabrication; Thanksgiving; Spilling the Peas 10 May 2005 1 Sep 2005 1 Oct 2006 1 Sep 2006 Hyacinth Blue 50.00 CAD 2 Copies of Publication Issue 1.12 CAD
这算不上可怕,但是足以促使我寻找别的替代方案。将数据嵌入在 XHTML 中怎么样?在这种情况下,不需要对它进行解析或格式化,可以像清单 3 中这样直接显示它:
  • publisher
    Room of One‘s Own
    type
    Journal
    titles
    • Hyacinth Blue
    • Fabrication
    • Thanksgiving
    • Spilling the Peas
    submitted
    2005-05-10
    accepted
    2005-09-01
    published
    2006-10-01
    payment received
    2006-09-01
    titles accepted
    • Hyacinth Blue
    expenses
    postage
    CAD 1.12
    payment
    • CAD 50.00
    • 2 Copies of Publication Issue
  • publisher
    Surrey International Writers‘ Competition
    type
    Contest
    titles
    • The Thirteenth Child
    submitted
    2006-08-31
    accepted
    2006-09-26
    published
    2006-10-20
    payment received
    2006-10-20
    titles accepted
    • The Thirteenth Child
    expenses
    postage
    CAD 1.05
    entry fee
    CAD 15.00
    payment
    • CAD 150.00
    • Honorable Mention
    • Copy of Anthology
  • publisher
    Word on the Street
    type
    Invited Reader
    event
    10 Minutes of readings
    event date
    2006-09-24
    payment
    • T-Shirt
    • Lunch
  • publisher
    Paideusis: The Journal of the Canadian Philosophy of Education Society
    type
    Refereed Journal
    titles
    • To Carry Over: Metaphor Invents Us (seven poems)
    submitted
    2006-10-13
    accepted
    2006-10-16
    published
    Pending
    titles accepted
    All

这是一个相当简单的从半结构化数据到 HTML 的映射。默认的样式不太多,但是很容易使用 CSS 以跨平台的方式重新设置样式。使用 DOM 操作数据也很容易,甚至不需要解释。添加 HTML 代码会使文档有所膨胀,但是不太过分。这个示例与 XOXO 大纲微格式非常相似(参见参考资料),而且我相信,如果在第一个
    元素中添加 class="outline",它就会成为 XOXO 大纲。可以使用定制的 XML 语言添加更多的语义内容,例如用 元素替换描述列表,但是对于这个示例,在简洁性或可读性方面帮助不大。接下来,我尝试使用 JavaScript Object Notation(JSON)进一步进行简化:
    { "publisher": "Room of One‘s Own", "type": "Journal", "titles": ["Hyacinth Blue", "Fabrication", "Thanksgiving", "Spilling the Peas"], "titles accepted": ["Hyacinth Blue"], "submitted": "2005-05-10", "accepted": "2005-09-01", "published": "2006-10-01", "payment received": "2006-09-01", "expenses": [{"postage": "CAD 1.12"}], "payment": ["CAD 50.00", "2 Copies of Publication Issue"]}, { "publisher": "Surrey International Writers‘ Competition", "type": "Contest", "titles": ["The Thirteenth Child"], "titles accepted": ["The Thirteenth Child"], "submitted": "2006-08-31", "accepted": "2006-09-26", "published": "2006-10-20", "payment received": "2006-10-20", "expenses": [{"postage": "CAD 1.05"}, {"postage": "CAD 15.00"}], "payment": ["CAD 150.00", "Honorable Mention", "Copy of Anthology"]}, { "publisher": "Word on the Street", "type": "Invited Reader", "event": "10 Minutes of readings", "event date": "2006-09-24", "payment": ["T-Shirt", "Lunch"]}, { "publisher": "Paideusis: The Journal of the Canadian Philosophy of Education Society", "type": "Refereed Journal", "titles": ["To Carry Over: Metaphor Invents Us (seven poems)"], "titles accepted": "All", "submitted": "2006-10-13", "accepted": "2006-10-16", "published": "Pending"} ]
    在清单 4 中,会看到与 HTML 编码中相同的所有内容,但是它对脚本的可访问性更强,因为它仅仅是 JavaScript 的一个子集。可以作为 JavaScript 对象、列表和字符串直接访问数据。这种格式很简洁,保留了以前格式的所有信息,还保留了结构,而且仍然足够灵活,可以处理半结构化数据。这已经很不错了,但是还可以更简单。回到第一个示例 —— 使用电子表格存储数据。在电子表格之间传输数据的一种常用方法是,使用逗号分隔的值(comma-separated value,CSV)。使用这种经过考验的格式,会获得以下文档:
    "Publisher", "Type", "Titles", "Submitted", "Accepted/Rejected", "Published", "Payment Received", "Titles Accepted", "Payment", "In Kind", "Postage", "Fees" "Room of One‘s Own", "Journal", "Hyacinth Blue; Fabrication; Thanksgiving; Spilling the Peas", 10 May 2005, 1 Sep 2005, 1 Oct 2006, 1 Sep 2006, "Hyacinth Blue", 50.00 CAD, "2 Copies of Publication Issue", 1.12 CAD, "Surrey International Writer‘s Competition", "Contest", "The Thirteenth Child", 31 Aug 2006, 26 Sep 2006, 20 Oct 2006, 20 Oct 2006, "The Thirteenth Child", 150.00 CAD, "Honorable Mention, Copy of Anthology", 1.05 CAD, 15.00 CAD "Word on the Street, Vancouver", "Invited Speaker", "10 Minutes of Readings", , , 24 Sep 2006, , , , "T-Shirt, Lunch", , "Paideusis: The Journal of the Canadian Philosophy of Education Society", "Refereed Journal", "To Carry Over: Metaphor Invents Us (seven poems)", 13 Oct 2006, 16 Oct 2006, "(Pending) Nov 2006", , "All", , , "Email",
    好了,清单 5 证明数据文档可以大大简化。我还要指出 JSON 和 CSV 之间的一个重要差异:尽管 CSV 是一种常用技术,但并没有标准化,而且一般只允许 ASCII 文本。而 JSON 经过明确正规的定义,而且指定使用 UTF-8 编码(Unicode)。所以,尽管这个示例并没有用到 ASCII 范围之外的任何文本,但是 JSON(和 XML)适合处理国际化文本。




    回页首
    Atom Syndication Format 与 Fame not Fortune 应用程序跟踪的信息有一些相同之处:作者、发布日期等等。我可以将所有数据放进一个 feed,然后在页面上对 XML 进行格式化,也可以用标准的聚合器跟踪它。这可以成为我的应用程序的一大特色,帮助我超过竞争对手 —— 帮助诗人跟踪自己的作品的所有其他工具。清单 6 给出 Atom feed 的形式(为了简短,只给出了一个条目):
    Fame not Fortune Recent submissions 2006-12-03T20:37:16Z Daniela Elza urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 Hyacinth Blue urn:uuid:68C0BAAB-C955-45F9-BDD6-21A22FC809AF 2006-12-01T20:37:16Z 2006-10-01T12:12:12Z
    publisher
    Room of One‘s Own
    titles
    • Hyacinth Blue
    • Fabrication
    • Thanksgiving
    • Spilling the Peas
    submitted
    2005-05-10
    accepted
    2005-09-01
    payment received
    2006-09-01
    expenses
    postage
    CAD 1.12
    payment
    • CAD 50.00
    • 2 Copies of Publication Issue

    如果清单 6 看起来眼熟,这是因为 Atom Entry 元素没有提供发送的数据所需的所有字段,所以这个条目的大部分是来自上面示例的 XHTML 代码,这些代码包围在 标记中。我可以改变 published 和 author 字段的用途,但是这意义不大,而且这实际上是对 published 字段的错误使用,这个字段应该是这个条目的发布日期,而不是它包含的数据的日期。我可以创建自己的名称空间,从而用额外的字段扩展 Atom Entry,但是现有的聚合器或 feed 阅读器都不能使用此信息,因此使它不可见,所以是没有意义的。可以简单地将 XHTML 代码包装在 Atom envelope 中,从而给应用程序添加联合支持,但是从纯粹的面向数据角度来看,Atom 没有给我提供任何好处。当需要将数据传入和传出我的应用程序时,用 Atom Entry 包装数据并使用 Atom Publishing Protocol(参见参考资料)可能是有好处的。注意,如果要使用 Atom,那么这对数据格式选择会有一些限制:Atom 标记只能容纳三种类型的数据:文本(可以是 JSON 格式)、HTML(其中的所有实体都要经过转义)或 XHTML。还没有在不需要扩展 Atom 的情况下在 Atom 中嵌入任意 XML 内容的方法,但是可以为不能嵌入的数据提供链接。所以,如果希望为自己的数据提供联合流,那么一定要考虑清楚,因为如果决定集成 Atom 功能,就会影响其他的数据格式决策。




    回页首
    在构建支持 Ajax 的 Web 站点或 Web 应用程序时,要做出许多决策。要采用什么数据格式就是决策之一,开发人员常常忽视这个问题,或者没有认真地全面考虑所有方面。在本文中,我尝试为这些问题提供一些思路,帮助您做出合理的决策。重申一下前面给出的经验性规则:
    对于数据,使用 JSON 对于文档,使用 XML(如果没有明确的否定理由,就选用 XHTML) 为了联合(以及支持 Atom Publishing Protocol),将数据包装在 Atom 中
    我尝试用一些示例来说明涉及到的权衡因素,并试图通过这些示例来论证我的经验性规则。但是,我没有证明任何规则,因为这些示例都是特殊情况,而且大多数现实场景都会出现例外。这些原则对我是有效的,也可能会帮您节省时间和精力。我希望能够有机会在以后的专栏文章中向您通报我利用这些原则建立实际站点的情况。我也非常希望能够了解您的成功经验、意见和建议。