W3CHINA Blog首页    管理页面    写新日志    退出


«September 2025»
123456
78910111213
14151617181920
21222324252627
282930


公告
暂无公告...

我的分类(专题)

日志更新

最新评论

留言板

链接


Blog信息
blog名称:VeryTag
日志总数:15
评论数量:8
留言数量:0
访问次数:84223
建立时间:2005年1月22日




XHTML的模块化
电脑与网络

清风细雨 发表于 2005/2/6 16:39:02

简介1. 本教程适合我吗?2. 本教程的内容3. 工具4. 本教程中使用的约定5. 关于作者 模块化概述1. 为什么要模块化?2. 目标设备3. 模块化体系结构 一致性1. 一致性及其原因2. XHTML 主机语言3. XHTML 集成集合4. 做选择 摘要模块1. 该模块的用途2. 设计目的3. 源数据4. 约定5. 组和最小内容模型6. 摘要模块 Qname 模块1. 该模块的用途2. 创建文件3. DTD 条件节4. 名称空间处理5. 元素和属性6. Qname 模块(代码)7. Qnames 集合 声明模块1. 该模块的用途2. 声明元素和属性3. 添加名称空间属性4. 声明模块(代码) 内容模型模块1. 该模块的用途2. 定义结构3. 内容模型模块(代码) DTD 驱动程序1. 该模块的用途2. 链接到 XHTML3. XHTML 框架4. 包括新模块5. DTD 驱动程序(代码) 构建 MemoryML 文档1. 基本文档2. 为新元素添加前缀3. 为所有元素添加前缀 XHTML 模块化结束语1. 结束语2. 参考资料 ------------------------------------------------------------------------ 简介 本教程适合我吗? 本教程是为需要了解 XHTML 的模块化的用户设计的,帮助他们使用 XHTML 的子集或添加他们自己的标记来创建他们自己的标记语言变体。 您应该已经十分了解 XML,并且至少对 XHTML 及其使用有基本了解。您还应该了解 XML 验证并熟悉“文档类型定义(Document Type Definition (DTD))”和名称空间。参考资料页提供了至一些教程的链接,这些教程可帮助您迅速掌握所有这些方面的知识。 您不需要有任何编程技巧就可理解本教程。 本教程的内容 本教程演示了“内存标记语言(Memory Markup Language)”(或 MemoryML)的创建,它被设计成通过嵌入在一个设备(如摄像机、录像机或 DVD 播放器)中虚构的浏览器来查看。 XHTML 的模块化允许开发人员选择要在一个应用程序中支持哪些 XHTML 模块。开发人员可以对那些模块进行补充,使创建与 XHTML 无缝结合的新标记语言成为可能。 工具 本教程演示了 XHTML 模块的构建。要实际构建这些模块,只需要一个文本编辑器。 要更进一步测试新模块,需要一个验证解析器,如 XML 处理的 Java API(Java API for XML Processing(JAXP))或 Xerces。参考资料页列出了几种验证解析器。 本教程中使用的约定 本教程使用几个约定,使手边的资料更便于阅读: monospace 字体用于文件和路径名。 用 bold monospace 字体显示需要输入的文本。在一些代码示例中,使用粗体来提醒您注意在附带的文本中正在引用的标记或元素。 着重/斜体提醒您注意窗口、对话框和特性名。 本教程中,省略与讨论无关的代码段并用省略号(...)替代。 关于作者 Nicholas Chase 一直参与多家公司的网站开发工作,包括 Lucent Technologies、Sun Microsystems、Oracle Corporation 和 Tampa Bay Buccaneers。Nick 曾是一名高中物理教师、低水平放射性废物设施经理、在线科幻小说杂志编辑、多媒体工程师和 Oracle 讲师。最近,他是佛罗里达州 Clearwater 的 Site Dynamics Interactive Communications 的首席技术官。他还是包括 Java and XML From Scratch(Que)在内的有关 Web 开发的三本书的作者。他乐于倾听读者的意见,可以通过 nicholas@nicholaschase.com 与他联系。 模块化概述 为什么要模块化? HTML 的第一个正式版本,HTML 2.0,只有不到 50 个标记在其中。经过几年的发展,标记数已翻了几倍,以至于甚至在最流行且最受支持的浏览器中完全支持所有这些标记也是十分困难的。何况小型移动电话或 PDA 呢? 当独立设备开始连接到 Web 时,开发人员面临进退两难的局面。如果他们不能支持所有这些标记,那么他们应该如何决定要支持哪些标记呢?内容供应商将如何知道哪些标记是受支持的呢? 本教程通过将该语言分割成可以以标准方式混合并匹配的标准模块来解决这一问题。例如,XHTML Basic 是为如移动电话、寻呼机和 PDA 等设备设计的特定子集。想要创建 XHTML Basic 内容的开发人员应该清楚地知道哪些标记是受支持的。同样,如果一个设备支持特定的 XHTML 模块,则开发人员可以将内容针对它们。 然而,模块化的用途还远远不止这些。它还允许以标准化方式添加特定标记,这样便有可能创建新的派生标记语言,以为特定目的提供服务。 目标设备 本教程记录了新标记语言的创建,它跟踪记录在录像带、DVD 和其它介质上的数据。该语言可以由制作、存储并重放这些记录的设备使用。 这些设备,其内存和处理能力可能非常小,可能有一个内置浏览器用于显示信息,如已经出现在类似设备上的菜单(象 VCR 上的设置菜单)。这些菜单可以方便地用 XHTML Basic 显示出来。然而,如果信息作为更具描述性的 XML 的一部分显示,则它还可以用来控制该设备。 考虑一下作为摄像机、VCR 和 DVD 之间的控制器的设备。控制器可能会遇到如下所示的一小段 XML 代码: <video tapeid="A323"> <media mediaid="A323" type="VHS"/> <start>0:00:00</start> <end>32:12:45</end> <subdate>2001-05-23</subdate> <donor>John Baker</donor> <subject>Pitching a tent</subject> <location><description>Outside in the woods</description></location> </video> 控制器可能会将该主题作为菜单的一部分显示。另外,如果用户选择了这一片段,那么控制器还将完全知道向 VHS 机器发信号以插入编号为 A323 的录像带,从起始处开始并播放 32 分钟 12 秒。 将这些标记合并到与 XHTML 集成的新标记语言可允许内容供应者根据一个标准编辑内容。 模块化体系结构 创建一个新的标记语言实际上涉及到几个以一种特定方式组合起来的相关模块。 摘要模块:实际上任何应用程序都不读取这个可选文件,而是提供一种半形式化的、可供人们阅读的描述,包括任何元素分组的文字描述。 Qname 模块:Qname 模块,或限定名模块,定义一系列表示实际元素名的参数实体。可在其它模块中引用这些实体。 声明模块:该模块为元素及其属性提供实际声明。 内容模型模块:该模块为整个模块和现在将要有“新”元素作为子元素的XHTML 元素定义内容模型,而不是为新元素定义。 Qnames 集合:该文件将 Qname 模块链接在一起。 DTD 驱动程序:这是在验证 XML 文件时实际引用的文件。它包含对其它模块的引用,以便它们都可用于验证。 一致性 一致性及其原因 如果没有标准方式支持功能的标准集合,那么它们对于要支持的应用程序没有任何好处。例如,假设浏览器通过将标记显示为其余内容中的小文本而不是它自己的一大块文本来“支持”它。即使假设它们是受支持的,Web 作者也不会知道如何使用这些功能。 一致性同时为应用程序和语言的类型定义了特定需求的集合。例如,声称是 XHTML 用户代理(如浏览器)的应用程序必须,除其它事情之外,以某种方式处理文档中的空白并且忽略未知标记同时继续处理其内容。 在定义 XHTML 语言中,有两组不同的一致性需求:XHTML 主机语言和 XHTML 集成集合。 XHTML 主机语言 XHTML 主机语言是基于 XHTML 的新标记语言,它遵循与传统 XHTML 页面相同的结构规则。例如,它必须将 <html> 作为其根元素。XHTML 主机语言一致性要求: W3C 认可的实现中的定义:目前,这意味着必须通过 DTD 定义模块,但模块化的 W3C XML Schema 版本目前正在完成中,其它实现也是有可能的。 在 DTD 的 PUBLIC 标识符的公共文本描述的开始处使用“XHTML”:例如,-//COMPANY NAME//ELEMENTS XHTML Memory Language 1.0//EN。 包含 XHTML 结构、超文本、文本和列表模块:还可以包括其它模块,但任何使用的模块都必须包括在其整体中。一个新的 DTD 可以通过添加新属性或内容来扩展元素。然而,XHTML 中所需的任何属性或最小的内容模型都是新语言所需的,不能除去它们。 使用单独的 XML 名称空间:这是添加到语言的任何附加元素或属性所需的。 语言不必始终符合所有这些需求。 XHTML 集成集合 并非所有标记语言必须是 XHTML 主机语言。在某些情况下,语言只需要描述内容,但决不是一定要独立使用 — 否则它最终可能会使用不同于 XHTML 页面的结构。这些语言只需要符合 XHTML 集成集合。 XHTML 集成集合一致性与 XHTML 主机语言一致性是基本相同的,除了以下两个例外: 当 XHTML 必须出现在 DTD 的 PUBLIC 标识符的公共文本节中时,它必须不是第一个。例如:-//COMPANY NAME//ELEMENTS Memory Information XHTML 1.0//EN。 XHTML 结构模块不是必需的。然而,超文本、文本和列表模块仍是必需的。 做选择 在决定是构建 XHTML 主机语言还是构建 XHTML 集成集合语言时,主要因素应该是将如何使用新的标记语言。例如,XHTML 主机语言可以独立使用,而 XHTML 集成集合语言通常与主机语言结合使用。 将主机语言用作扩展的基础可能也很方便,因为集成集合语言可能容易缺少在任何环境中独立使用所需的结构,更不用说基于 XHTML 的了。 在本教程中为内存标记语言选择路径时,请考虑将如何使用它。将读取它的设备(如控制器)没有 XHTML 的其它知识,所以它们需要构建在语言中的某种结构。 当然,并没有规定它的结构必须与 XHTML 的结构相同。该语言可以方便地使用 或 作为其根元素,所以可以将它作为 XHTML 集成集合语言构建。 另一方面,假设控制器是可用于 Web 的,并允许在 Web 上从浏览器访问它,那怎么办呢?在这种情况下,当然是使用 XHTML 主机语言更好,因为在浏览器中“页面”至少是可理解的。(并且通过添加样式表来控制新元素的显示,它看上去可能会更好。) 本教程演示了将内存标记语言构建成为 XHTML 主机语言。 摘要模块 该模块的用途 标记语言的定义涉及了几个模块(也称为子模块)的创建,大多数模块由解析器处理以验证文档。摘要模块是这一规则的例外。 摘要模块为读者理解语言结构提供必需的信息,而不必通过多个文档提供。它列出了可能的元素、它们可能携带的属性以及可能存在的任何逻辑分组。 摘要模块使读者清晰地了解语言的总体结构。 设计目的 在创建内存标记语言中,请考虑下列目的: MemoryML 应该: 对记录内容的描述进行编码 支持同时通过专用和非专用的浏览器应用程序来浏览 是人类可阅读的 支持通过非浏览器应用程序(如软件)的处理来控制设备 开始确定结构的一个方法是创建样本数据。 源数据 语言的实际设计是可能包括十分专门化技巧的研究领域,而一点常识和深谋远虑对确定语言基础大有帮助。 MemoryML 实际上基于“千年内存项目(Millennium Memory Project)”的数据,它收集从新千年开始的每天生活的记录。每个清单都包括有关记录所包含的内容以及可在何处找到它的信息。例如: <?xml version="1.0"?> <memories> <video tapeid="A323"> <media mediaid="A323" type="VHS"/> <start>0:00:00</start> <end>32:12:45</end> <subdate>2001-05-23</subdate> <donor>John Baker</donor> <subject>Pitching a tent</subject> <location><description>Outside in the woods</description></location> </audio> <memory tapeid="C531"> <media mediaid="C531" type="DVD"/> <start>12:09:23</start> <end>58:34:51</end> <subdate>2001-05-18</subdate> <donor>Elizabeth Davison</donor> <subject>Baseball Game</subject> </memory> </memories> (在生产环境中,实际需要多得多的信息。为了简单起见,本教程使用这种结构。) 该样本数据只显示将添加到新语言的扩展。请记住,还包括了结构、超文本、文本和列表模块。 描述这些关系不需要特定格式,但存在某些约定。 约定 虽然摘要模块的格式化没有正式要求,但有时使用了某些约定,那些阅读文档的人也期望使用一些约定。许多都与 DTD 本身使用的约定和修饰语相似或相同。 例如,?、+ 和 * 在 DTD 中有特殊含义— 分别特别地表示 0 个或 1 个实例、1 个或多个实例以及 0 个或多个实例。在摘要模块中也遵循这些约定。类似地,要求用逗号列出的元素名以特定次序排列,用| 符号隔开的那些元素名是另一个选项。使用圆括号的分组也以它在 DTD 中相同的方式起作用。 然而,在摘要模块中使用的一些约定未包括在 DTD 中。例如,要表示正在扩展一个元素以包括新属性(与从头开始创建的相反),名称的后面跟一个 &,如 title& 中。 属性可能也有特殊需求。必需的属性应该后跟一个星号,如 tapeid* 中。也可以指定可允许的值,并用一个星号指定缺省值,如下所示:type("VHS" | "DAT" | "DTD" | "DVD" | "8mm"*) 与特定值对比,属性可能需要特殊数据类型,如 tapeid(CDATA) 中,或固定值,如 license(="free") 中。 除了这些约定外,还可以添加文字节来描述最小内容模型。 组和最小内容模型 在许多情况下,将元素或属性分组在一起,以便更容易地表示许多不同的属性或元素在特殊位置中是适当的。例如,即使列出每个 XHTML 元素可用的核心属性也是极其不便的;而只查看对 Common 的引用是很常见的。 同样,为了方便起见,可以将元素分组到表示特殊最小内容模型的表达式中。例如:Heading h1 | h2 | h3 | h4 | h5 | h6 通过这种方式,只引用 Heading 表达式要比单独列出元素方便。同样的事情可适用于定制标记。考虑一下 MemoryML 示例。为记录创建一组描述符可能很方便:VideoInfo media | start | end | subdate | donor | subject | location 这创造了第二个优势。现在可以说 video 元素将 VideoInfo 内容模型作为其子元素,还可以方便地描述 audio 元素的子元素,它们由所有的video 子元素(除了 location)组成。摘要模块可以使用以下命令来表示这种关系:VideoInfo - location 将这些约定与上一页中的那些约定组合起来可提供用于创建摘要模块的工具。 摘要模块 将这些技术合并到 MemoryML 的单一摘要模块中可以为内存扩展模块创建一个可理解的描述。元素 属性 最小内容模型 memories (audio | video)* video tapeid(IDREF) VideoInfo audio tapeid(IDREF) VideoInfo - location start PCDATA end PCDATA subdate PCDATA donor PCDATA subject PCDATA location place | description description PCDATA place PCDATA media mediaid(ID), EMPTY type("VHS" | "DAT" | "DTD" | "DVD" | "8mm"*) 该模块还定义了最小内容模型 VideoInfo: media、media、start、end、subdate、donor、subject、location 现在,设置好了结构,该开始创建实际的 DTD 模块了。 Qname模块 该模块的用途 Qname 或限定名,是还包括任何可应用的名称空间别名的元素或属性的名称。例如,对于元素<mem:subject>Baseball game</mem:subject> 该元素的限定名是 mem:subject,其中 mem 是名称空间别名。 然而,不是总显示别名或前缀。在某些情况下,可能完全禁用添加前缀,或可能仅对 XHTML 的扩展启用。 通过用参数表示定义,XHTML 的模块化使这成为可能。换言之,不是将元素的名称定义为 subject 或 mem:subject,而是模块将参数实体定义为:<!ENTITY % Memory.subject.qname "%Memory.pfx;subject" > 因此,如果索引是打开的,则 %Memory.pfx; 的值将是 mem:,并使 %Memory.pfx;subject 的值等于 mem:subject。如果索引是关闭的,则 %Memory.pfx; 的值将是空的,并使 %Memory.pfx;subject 的值只保留为 subject。 Qname 模块为所有元素名称提供了可修改的定义。 创建文件 与创建新标记语言有关的每个模块(和因此包含它的文件),除了有实际定义外,还应该有使之易于使用的文档。该信息可能包括有关该文件的“正式”版本所在位置的信息,或应该用来引用它的 PUBLIC 标识符。 既然开发人员熟悉这个布局,就让我们把 W3C 中的一个样本文件作为起点。下面的示例显示了 Qname 模块文件的开始部分:<!-- ...................................................................... --> <!-- MemoryML Qname module ................................................ --> <!-- file: memory-qname-1.mod PUBLIC "-//MY COMPANY//ELEMENTS XHTML MemoryML Qnames 1.0//EN" SYSTEM "http://www.my.org/DTDs/memory-qname-1.mod" xmlns:memory="http://www.my.org/namespaces/MemoryML" ...................................................................... --> 请注意所有信息都包括在注释中。它仅供那些可能要查找它以获得实现帮助的开发人员使用。 实际名称不重要,但开发人员期望某些约定。例如,Qname 模块通常命名为 MODULENAME-qname-1.mod,而定义模块本身将是 MODULENAME-1.mod。 PUBLIC 标识符必须遵循XHTML 主机语言中提到的一致性规则,但 SYSTEM 信息则由您自己决定。要知道,Qname 文件应该始终可用于 URI,这些 URI 是作为不识别PUBLIC 标识符的那些应用程序的 SYSTEM 标识符列出的。 为了符合 XHTML 主机语言需求,所有附加元素都必须包含在它们自己的名称空间中。这是在上面的示例中提到的名称空间,所以它在所有文件中必须是一致的。 是否将名称空间信息视作每个元素的前缀由 DTD 的条件节(conditional sections)确定。 DTD 条件节 虽然 DTD 不是实际编程的平台,但可以包括或忽略节,以有效地更改文档类型的定义。例如:<![IGNORE[ <!ELEMENT memory (video)*> ]]> <![INCLUDE[ <!ELEMENT memory (video | audio)*> ]]> 在这个示例中,memory 元素可以包括 video 或audio,因为包括了该节,而忽略了前一节。交换下列值<![INCLUDE[ <!ELEMENT memory (video)*> ]]> <![IGNORE[ <!ELEMENT memory (video | audio)*> ]]> 产生只可包含 video 的 memory 元素。 还可包括或排除实体定义,但有一个附加复杂因素:实体的第一个定义是在任何给定情况中使用的那个定义。因此,示例<![INCLUDE[ <!ENTITY % prefixed "TRUE" > ]]> <!ENTITY % prefixed "FALSE" > 导致 %prefixed 的值为 TRUE,因为该定义先包括在文档中。 另一方面,如果处理的另一个 DTD 首先为 %prefixed 提供了一个值,那么不管在这里指定了什么,都将使用该值。也可能在 DTD 的内部子集中提供该值,以作为实际文档的一部分。 当值的这种传播打开和关闭添加前缀,并涉及到其它名称空间处理问题时,理解它是至关紧要的。 名称空间处理 使用 MemoryML 创建文档的开发人员应该能够打开和关闭添加前缀,但不应该被要求那么做。所以,Qname 模块需要定义一个参数实体,如果需要这个参数实体的话,它可以被设置,但如果不需要的话,则已经有一个值。<!ENTITY % NS.prefixed "IGNORE" > <!ENTITY % Memory.prefixed "%NS.prefixed;" > 这种方式参数是可用的,但如果没有显式地设置它,那么它采用值 %NS.prefixed,它是在 XHTML 框架内实际定义的。开发人员可以选择将 %NS.prefixed 设置为INCLUDE,以有效地打开所有添加前缀,或者可以将%Memory.prefixed 设置为 INCLUDE,仅为内存模块打开添加前缀。如果两个都没有设置,则都保持 IGNORE。 下一步,定义实际名称空间和前缀:<!ENTITY % Memory.xmlns "http://www.my.org/namespaces/MemoryML" > <!ENTITY % Memory.prefix "memory" > 一旦确定了这些值,就为实际文档创建名称空间声明:<![%Memory.prefixed;[ <!ENTITY % Memory.pfx "%Memory.prefix;:" > <!ENTITY % Memory.xmlns.extra.attrib "xmlns:%Memory.prefix; %URI.datatype; #FIXED '%Memory.xmlns;'" > ]]> <!ENTITY % Memory.pfx "" > <!ENTITY % Memory.xmlns.extra.attrib "" > 这种方式,如果打开 %Memory.prefixed;,则%Memory.xmlns.extra.attrib 的值变成:xmlns:memory %URI.datatype; #FIXED 'http://www.my.org/namespaces/MemoryML' (%URL.datatype 是在 XHTML 框架中定义的。) 当然,如果无法将其返回到实际文档,则创建这个值无任何意义。幸运的是,XHTML 框架定义了将信息传播回文档的参数实体:<!ENTITY % XHTML.xmlns.extra.attrib "%Memory.xmlns.extra.attrib;" > 一旦完成了名称空间处理,就准备好可以添加实际元素了。 元素和属性 前几页的所有技巧旨在允许方便地创建(或排除)元素的名称空间前缀。象添加前缀信息一样,这些元素在 Qname 模块中用参数表示。例如:<!ENTITY % Memory.subject.qname "%Memory.pfx;subject" > 其余的模块构建过程将该元素称为 %Memory.subject.qname。因此,无论添加前缀是开(使它成为 memory:subject)还是关(使它成为 subject),它都将是正确的。 实际模块名,本例中为 Memory,用在该模块的所有参数实体的开始,这样不仅将它们与 XHTML 实体区分,还将它们与稍后可能添加的附加扩展区分开来。 集中在一起完成 Qname 模块。 Qname 模块(代码)<!-- ...................................................................... --> <!-- MemoryML Qname module ................................................ --> <!-- file: memory-qname-1.mod PUBLIC "-//MY COMPANY//ELEMENTS XHTML MemoryML Qnames 1.0//EN" SYSTEM "http://www.my.org/DTDs/memory-qname-1.mod" xmlns:memory="http://www.my.org/namespaces/MemoryML" ...................................................................... --> <!-- Declare the default value for prefixing of this module's elements --> <!-- Note that the NS.prefixed will get overridden by the XHTML Framework or by a document instance. --> <!ENTITY % NS.prefixed "IGNORE" > <!ENTITY % Memory.prefixed "%NS.prefixed;" > <!-- Declare the actual namespace of this module --> <!ENTITY % Memory.xmlns "http://www.my.org/namespaces/MemoryML" > <!-- Declare the default prefix for this module --> <!ENTITY % Memory.prefix "memory" > <!-- Declare the prefix and any prefixed namespaces that are required by this module --> <![%Memory.prefixed;[ <!ENTITY % Memory.pfx "%Memory.prefix;:" > <!ENTITY % Memory.xmlns.extra.attrib "xmlns:%Memory.prefix; %URI.datatype; #FIXED '%Memory.xmlns;'" > ]]> <!ENTITY % Memory.pfx "" > <!ENTITY % Memory.xmlns.extra.attrib "" > <!ENTITY % XHTML.xmlns.extra.attrib "%Memory.xmlns.extra.attrib;" > <!ENTITY % Memory.memories.qname "%Memory.pfx;memories" > <!ENTITY % Memory.video.qname "%Memory.pfx;video" > <!ENTITY % Memory.audio.qname "%Memory.pfx;audio" > <!ENTITY % Memory.start.qname "%Memory.pfx;start" > <!ENTITY % Memory.end.qname "%Memory.pfx;end" > <!ENTITY % Memory.subdate.qname "%Memory.pfx;subdate" > <!ENTITY % Memory.donor.qname "%Memory.pfx;donor" > <!ENTITY % Memory.subject.qname "%Memory.pfx;subject" > <!ENTITY % Memory.location.qname "%Memory.pfx;location" > <!ENTITY % Memory.description.qname "%Memory.pfx;description" > <!ENTITY % Memory.place.qname "%Memory.pfx;place" > <!ENTITY % Memory.media.qname "%Memory.pfx;media" > 当仅有一个模块时,该文件会照管所有限定名。但如果有多个模块呢? Qnames 集合 可以绑在一起的文件的数目没有限制,但添加多个模块会引入一种另外的复杂情况。Qnames 模块包含定义:<!ENTITY % XHTML.xmlns.extra.attrib "%Memory.xmlns.extra.attrib;" > 最终文档使用 %XHTML.xmlns.extra.attrib 来为外部模块添加任何额外的名称空间。困难在于,如果定义了多个模块,则每个模块重新定义 %XHTML.xmlns.extra.attrib,以便只包括它的信息。 要解决该问题,可以创建一个 Qnames 集合模块。该文件只是将所有名称空间信息合并到一个单一实体中。例如,如果有一个称为 MemoryExtensions 的附加模块,则 Qnames 集合模块将包含:<!-- ...................................................................... --> <!-- MemoryML/MemoryExtensions Qname Collection Module .................... --> <!-- file: memory-qnames.mod ............................................. --> <!-- Bring in both sets of Qnames in order to access their entities --> <!ENTITY % Memory-qname.mod PUBLIC "-//MY COMPANY//ELEMENTS XHTML MemoryML Qname Collection 1.0//EN" SYSTEM "http://www.my.org/DTDs/memory-qnames.mod" > %Memory-qname.mod; <!ENTITY % MemoryExtension-qname.mod SYSTEM "memoryextension-qname-1.mod" > %MemoryExtension-qname.mod; <!-- Add both as an extension to XHTML --> <!ENTITY % XHTML.xmlns.extra.attrib "%Memory.xmlns.extra.attrib; %MemoryExtension.xmlns.extra.attrib;" > 可以将任何数目的名称空间添加到整个语言中,只要它们以这种方式绑在一起。 本教程只处理内存模块,因此 Qname 集合包含:<!-- ...................................................................... --> <!-- MemoryML Qname Collection Module ..................................... --> <!-- file: xhtml-memory-qname-1.mod ...................................... --> <!-- Bring in the MemoryML qualified names --> <!ENTITY % Memory-qname.mod PUBLIC "-//MY COMPANY//ENTITIES XHTML MemoryML Qnames 1.0//EN" "memory-qname-1.mod" > %Memory-qname.mod; <!-- Define the xmlns extension attributes --> <!ENTITY % XHTML.xmlns.extra.attrib "%Memory.xmlns.extra.attrib;" > 现在您已经得到了它们的名称,该定义实际元素了。 声明模块 该模块的用途 既然已经声明了所有元素名,该声明元素本身了。 声明元素就象创建 DTD 一样,除了不使用元素名称的直接引用外,结构引用了参数化名称。以这种方式,声明模块定义了元素及其内容模型。 声明模块还通过添加名称空间属性包括每个元素的名称空间信息。 首先,需要声明实际元素。 声明元素和属性 声明元素和属性的最容易的方法是先构建传统的 DTD ,然后将声明更改为参数。因此<!ELEMENT memories ( audio | video )* > 变成<!ELEMENT %Memory.memories.qname; ( %Memory.audio.qname; | %Memory.video.qname; )* > <!ATTLIST %Memory.memories.qname; %Memory.xmlns.attrib; > 额外属性定义了添加到元素的名称空间信息。确定名称空间信息的方法与 名称空间处理 中的非常象。 添加名称空间属性 实际包含在 %Memory.xmlns.attrib; 中的信息取决于先前所做的名称空间定义和添加前缀决定:<![%Memory.prefixed;[ <!ENTITY % Memory.xmlns.attrib "%NS.decl.attrib;" > ]]> <!ENTITY % Memory.xmlns.attrib "%NS.decl.attrib; xmlns %URI.datatype; #FIXED '%Memory.xmlns;'" > %NS.decl.attrib; 的值表示全局名称空间属性信息,它是由 XHTML 框架 DTD 中的条件确定的。如果添加前缀是打开的,则只有该信息需要出现在每个元素上,因为该前缀引用该元素的细节。然而,如果添加前缀是关闭的,则元素还需要模块的特定名称空间信息。 所有元素都必须将 %Memory.xmlns.attrib; 作为属性引用。如果元素已经有一个属性,则另外加上名称空间信息,如下所示:<!ATTLIST %Memory.media.qname; mediaid ID #REQUIRED type CDATA #IMPLIED %Memory.xmlns.attrib; > 声明模块(代码)<!-- ...................................................................... --> <!-- Memory Elements Module ............................................... --> <!-- file: memory-1.mod PUBLIC "-//MY COMPANY//ELEMENTS XHTML MemoryML Declaration 1.0//EN" SYSTEM "http://www.my.org/DTDs/memory-1.mod" xmlns:memory="http://www.my.org/namespaces/MemoryML" ...................................................................... --> <!-- Memory Module memories audio media start end subdate donor subject video media start end subdate donor subject location description | place --> <!-- Define the global namespace attributes --> <![%Memory.prefixed;[ <!ENTITY % Memory.xmlns.attrib "%NS.decl.attrib;" > ]]> <!ENTITY % Memory.xmlns.attrib "%NS.decl.attrib; xmlns %URI.datatype; #FIXED '%Memory.xmlns;'" > <!ELEMENT %Memory.memories.qname; ( %Memory.audio.qname; | %Memory.video.qname; )* > <!ATTLIST %Memory.memories.qname; %Memory.xmlns.attrib; > <!ELEMENT %Memory.video.qname; ( %Memory.media.qname;, %Memory.start.qname;, %Memory.end.qname;, %Memory.subdate.qname;, %Memory.donor.qname;, %Memory.subject.qname;, %Memory.location.qname;) > <!ATTLIST %Memory.video.qname; tapeid IDREF #REQUIRED %Memory.xmlns.attrib; > <!ELEMENT %Memory.audio.qname; ( %Memory.media.qname;, %Memory.start.qname;, %Memory.end.qname;, %Memory.subdate.qname;, %Memory.donor.qname;, %Memory.subject.qname;) > <!ATTLIST %Memory.audio.qname; tapeid IDREF #REQUIRED %Memory.xmlns.attrib; > <!ELEMENT %Memory.media.qname; EMPTY > <!ATTLIST %Memory.media.qname; mediaid ID #REQUIRED type CDATA #IMPLIED %Memory.xmlns.attrib; > <!ELEMENT %Memory.start.qname; (#PCDATA) > <!ATTLIST %Memory.start.qname; %Memory.xmlns.attrib; > <!ELEMENT %Memory.end.qname; (#PCDATA) > <!ATTLIST %Memory.end.qname; %Memory.xmlns.attrib; > <!ELEMENT %Memory.subdate.qname; (#PCDATA) > <!ATTLIST %Memory.subdate.qname; %Memory.xmlns.attrib; > <!ELEMENT %Memory.donor.qname; (#PCDATA) > <!ATTLIST %Memory.donor.qname; %Memory.xmlns.attrib; > <!ELEMENT %Memory.subject.qname; (#PCDATA) > <!ATTLIST %Memory.subject.qname; %Memory.xmlns.attrib; > <!ELEMENT %Memory.description.qname; (#PCDATA) > <!ATTLIST %Memory.description.qname; %Memory.xmlns.attrib; > <!ELEMENT %Memory.place.qname; (#PCDATA) > <!ATTLIST %Memory.place.qname; %Memory.xmlns.attrib; > <!ELEMENT %Memory.location.qname; ( %Memory.place.qname; | %Memory.description.qname;) > <!ATTLIST %Memory.location.qname; %Memory.xmlns.attrib; > 内容模型模块 该模块的用途 就象 DTD 为新模块定义结构一样,整个标记语言有一个结构。例如,memory 元素可以包含 video 和 audio 元素,但此刻没有可以包含 memory 元素的 XHTML 元素,所以无法将它添加到页面! 内容模型模块定义这些结构化元素。因为 XHTML 已参数化,所以可以改变其每个元素的定义。只要记住:一致性要求所有必要的元素都保持必要的,并且可选元素保持可用的。 例如,将 subject 添加为 li 元素的潜在子元素涉及重新定义li 的内容模型,如 XHTML 核心模块中定义的那样:<!ENTITY % li.content "( #PCDATA | %Flow.mix; | %Memory.subject.qname; )*" > 乍一看,似乎只有正在扩展的元素才需要重新定义 — 毕竟,原始定义仍存在。不幸的是,它并不那样简单。 在最终的 DTD 驱动程序文件中,将首先列出内容模型模块,所以其定义将取得优先。因而,当处理该文件时,还未定义如%Flow.mix; 这样的参数。 这意味着,为了将 subject 添加到 li,需要定义 %Flow.mix; 参数实体和标记 %Flow.mix; 的所有实体。 定义结构 必须做的第一个决定确定了(相对与旧元素)新元素将出现的位置。这很大程度取决于将如何使用数据。subject 应该作为超文本链接(<a>)的一部分出现吗,或者它应该只作为列表项(<li>)的一部分出现并且当选中它时表现为超文本链接吗?正常情况下,数据将如何出现在页面上? 在某些情况下,同时考虑这两种使用方法是有意义的。例如,构建在视频控制器中的浏览器可能知道 subject 应该作为超文本链接,但用于访问 Web 上控制器的浏览器可能不知道,所以有必要将它添加到一个正常的链接标记中。 为了本教程,假设下列情况: subject 可能作为列表项(li)或链接(a)的一部分出现。 memory 可能出现在页面本身的主体上。 生产环境很可能需要将元素添加到所有块元素的集合中。为了方便起见,本示例将它们直接添加到这些元素。 这些决定有助于形成内容模型模块。 内容模型模块(代码)<!-- ............................................................. --> <!-- XHTML Memory Model Module .................................. --> <!-- file: xhtml-memory-model-1.mod SYSTEM "xhtml-memory-model-1.mod" ................................................................ --> <!-- Define the content model for Misc.extra --> <!ENTITY % Misc.class "| %script.qname; | %noscript.qname; "> <!-- .................... Inline Elements ...................... --> <!ENTITY % HeadOpts.mix "( %meta.qname; )*" > <!ENTITY % I18n.class "" > <!ENTITY % InlStruct.class "%br.qname; | %span.qname;" > <!ENTITY % InlPhras.class "| %em.qname; | %strong.qname; | %dfn.qname; | %code.qname; | %samp.qname; | %kbd.qname; | %var.qname; | %cite.qname; | %abbr.qname; | %acronym.qname; | %q.qname;" > <!ENTITY % InlPres.class "| %tt.qname; | %i.qname; | %b.qname; | %big.qname; | %small.qname; | %sub.qname; | %sup.qname;" > <!ENTITY % Anchor.class "| %a.qname;" > <!ENTITY % InlSpecial.class "| %img.qname; " > <!ENTITY % Inline.extra "" > <!-- %Inline.class; includes all inline elements, used as a component in mixes --> <!ENTITY % Inline.class "%InlStruct.class; %InlPhras.class; %InlPres.class; %Anchor.class; %InlSpecial.class;" > <!-- %InlNoAnchor.class; includes all non-anchor inlines, used as a component in mixes --> <!ENTITY % InlNoAnchor.class "%InlStruct.class; %InlPhras.class; %InlPres.class; %InlSpecial.class; | %Memory.subject.qname; " > <!-- %InlNoAnchor.mix; includes all non-anchor inlines --> <!ENTITY % InlNoAnchor.mix "%InlNoAnchor.class; %Misc.class;" > <!-- %Inline.mix; includes all inline elements, including %Misc.class; --> <!ENTITY % Inline.mix "%Inline.class; %Misc.class;" > <!-- ..................... Block Elements ...................... --> <!ENTITY % Heading.class "%h1.qname; | %h2.qname; | %h3.qname; | %h4.qname; | %h5.qname; | %h6.qname;" > <!ENTITY % List.class "%ul.qname; | %ol.qname; | %dl.qname;" > <!ENTITY % Blkstruct.class "%p.qname; | %div.qname;" > <!ENTITY % Blkphras.class "| %pre.qname; | %blockquote.qname; | %address.qname;" > <!ENTITY % Blkpres.class "| %hr.qname;" > <!ENTITY % Block.extra " | %Memory.video.qname; | %Memory.audio.qname; " > <!-- %Block.class; includes all block elements, used as an component in mixes --> <!ENTITY % Block.class "%Blkstruct.class; %Blkphras.class; %Blkpres.class; %Block.extra;" > <!-- %Block.mix; includes all block elements plus %Misc.class; --> <!ENTITY % Block.mix "%Heading.class; | %List.class; | %Block.class; %Misc.class;" > <!-- ................ All Content Elements .................. --> <!-- %Flow.mix; includes all text content, block and inline --> <!ENTITY % Flow.mix "%Heading.class; | %List.class; | %Block.class; | %Inline.class; %Misc.class; | %Memory.subject.qname; " > DTD驱动程序 该模块的用途 现在,所有代码段都有了,该将它们全都放入可由 XML 文档调用的单一 DTD 中了。 该文件不仅合并在前面示例中创建的文件,而且还合并支持文件(如 XHTML 框架本身)和一致性所需的个别模块(如结构、超文本、文本和列表模块)。驱动程序还可以包括任何其它模块。 链接到 XHTML 要开始构建 DTD 驱动程序,需要添加版本参数以标识标记语言:<!ENTITY % XHTML.version "-//MY COMPANY//DTD XHTML MemoryML 1.0//EN" > 下一步,开始将文件链接在一起,产生把这两个名称空间的信息合并在一起的文件。以 Qnames 集合文件开始,它链接两个名称空间:<!ENTITY % xhtml-qname-extra.mod SYSTEM "xhtml-memory-qname-1.mod" > 还产生实际将两个结构绑在一起的内容模型:<!ENTITY % xhtml-model.mod SYSTEM "xhtml-memory-model-1.mod" > 下一步,将添加 XHTML 框架本身。 XHTML 框架 单一文件包含 XHTML 框架,但在为它创建设置时涉及到几个参数。 首先,添加 %XHTML.profile 实体,它是在 XHTML 概要可用时为与它们一起使用而保留的。虽然它实际上还没有用于任何事情,但在其它文件内部引用它并且可以想象出在内容模型中引用它,所以必须在内容模型之前定义它。<!ENTITY % XHTML.profile "" > 下一步,禁用双向文本支持,因为将不使用它。(该参数实际上包括除去双向支持的节,因此是奇怪的语法。)<!ENTITY % XHTML.bidi "INCLUDE" > 最后,产生 XHTML 框架本身:<!ENTITY % xhtml-framework.mod PUBLIC "-//W3C//ENTITIES XHTML Modular Framework 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-framework-1.mod" > %xhtml-framework.mod; 下一步,将包括所有模块。 包括新模块 有了适当的框架,该开始添加模块了。首先,添加包括在 MemoryML 中的 XHTML 模块:<!-- Text Module (Required) ............................... --> <!ENTITY % xhtml-text.mod PUBLIC "-//W3C//ELEMENTS XHTML Text 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-text-1.mod" > %xhtml-text.mod; <!-- Hypertext Module (required) ................................. --> <!ENTITY % xhtml-hypertext.mod PUBLIC "-//W3C//ELEMENTS XHTML Hypertext 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-hypertext-1.mod" > %xhtml-hypertext.mod; <!-- Lists Module (required) .................................... --> <!ENTITY % xhtml-list.mod PUBLIC "-//W3C//ELEMENTS XHTML Lists 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-list-1.mod" > %xhtml-list.mod; <!-- Document Structure Module (required) ....................... --> <!ENTITY % xhtml-struct.mod PUBLIC "-//W3C//ELEMENTS XHTML Document Structure 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-struct-1.mod" > %xhtml-struct.mod; 最后,但的确相当重要,不要忘记添加 MemoryML 模块!<!-- Memory Module ........................................ --> <!ENTITY % Memory-elements.mod SYSTEM "memory-1.mod" > %Memory-elements.mod; 添加了这些代码之后,驱动程序文件是完整的并且准备使用。 DTD 驱动程序(代码)<!-- .................................................................... --> <!-- Memory Extension DTD .............................................. --> <!-- file: xhtml-memory-1.dtd --> <!-- This is the DTD driver for Memory extension 1.0. Please use this formal public identifier to identify it: "-//MY COMPANY//DTD XHTML MemoryML 1.0//EN" And this namespace for extension-unique elements: xmlns:Memory="http://www.my.org/namespaces/MemoryML" --> <!ENTITY % XHTML.version "-//MY COMPANY//DTD XHTML MemoryML 1.0//EN" > <!-- Define the xhtml qualified names module to be ours --> <!ENTITY % xhtml-qname-extra.mod SYSTEM "xhtml-memory-qname-1.mod" > <!-- reserved for use with document profiles --> <!ENTITY % XHTML.profile "" > <!-- Define the Content Model for the framework to use --> <!ENTITY % xhtml-model.mod SYSTEM "xhtml-memory-model-1.mod" > <!-- Disable bidirectional text support --> <!ENTITY % XHTML.bidi "INCLUDE" > <!-- Bring in the XHTML Framework --> <!ENTITY % xhtml-framework.mod PUBLIC "-//W3C//ENTITIES XHTML Modular Framework 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-framework-1.mod" > %xhtml-framework.mod; <!-- Text Module (Required) ............................... --> <!ENTITY % xhtml-text.mod PUBLIC "-//W3C//ELEMENTS XHTML Text 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-text-1.mod" > %xhtml-text.mod; <!-- Hypertext Module (required) ................................. --> <!ENTITY % xhtml-hypertext.mod PUBLIC "-//W3C//ELEMENTS XHTML Hypertext 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-hypertext-1.mod" > %xhtml-hypertext.mod; <!-- Lists Module (required) .................................... --> <!ENTITY % xhtml-list.mod PUBLIC "-//W3C//ELEMENTS XHTML Lists 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-list-1.mod" > %xhtml-list.mod; <!-- Document Structure Module (required) ....................... --> <!ENTITY % xhtml-struct.mod PUBLIC "-//W3C//ELEMENTS XHTML Document Structure 1.0//EN" "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-struct-1.mod" > %xhtml-struct.mod; <!-- Memory Module ........................................ --> <!ENTITY % Memory-elements.mod SYSTEM "memory-1.mod" > %Memory-elements.mod; 构建 MemoryML 文档 基本文档 根据我们已经定义的结构,使用新元素并将它们合并到一个 XHTML 页面的简单文件看起来如下:<?xml version="1.0"?> <!DOCTYPE html SYSTEM "xhtml-memory-1.dtd"> <html> <head><title>Sample Page</title></head> <body> <p><a href="newpage.mml"><subject>Pitching a tent</subject></a></p> <ul> <li><subject>Pitching a tent</subject></li> <li><subject>Baseball game</subject></li> </ul> <video tapeid="A323"> <media mediaid="A323" type="VHS"/> <start>0:00:00</start> <end>32:12:45</end> <subdate>2001-05-23</subdate> <donor>John Baker</donor> <subject>Pitching a tent</subject> <location><description>Outside in the woods</description></location> </video> <audio tapeid="C531"> <media mediaid="C531" type="DAT"/> <start>12:09:23</start> <end>58:34:51</end> <subdate>2001-05-18</subdate> <donor>Elizabeth Davison</donor> <subject>Baseball Game</subject> </audio> </body> </html> 注意,该页面使用新的 DTD。在这种情况下,不提供名称空间信息,因为这不是必需的。 为新元素添加前缀 某些情况可能需要提供名称空间信息。因为内部 DTD 子集始终优先,所以很容易使用它来打开添加前缀。记得 %Memory.prefixed; 吗?在这里打开它,而它会覆盖任何其它设置。<?xml version="1.0"?> <!DOCTYPE html SYSTEM "xhtml-memory-1.dtd"[ <!ENTITY % Memory.prefixed "INCLUDE"> <!ENTITY % Memory.prefix "mem"> ]> <html xmlns:mem="http://www.my.org/namespaces/MemoryML> <head><title>Sample Page</title></head> <body> <p><a href="newpage.mml"><mem:subject>Pitching a tent</mem:subject></a></p> <ul> <li><mem:subject>Pitching a tent</mem:subject></li> <li><mem:subject>Baseball game</mem:subject></li> </ul> <mem:video tapeid="A323"> <mem:media mediaid="A323" type="VHS"/> <mem:start>0:00:00</mem:start> <mem:end>32:12:45</mem:end> <mem:subdate>2001-05-23</mem:subdate> <mem:donor>John Baker</mem:donor> <mem:subject>Pitching a tent</mem:subject> <mem:location><mem:description>Outside in the woods</mem:description></mem:location> </mem:video> <mem:audio tapeid="C531"> <mem:media mediaid="C531" type="DAT"/> <mem:start>12:09:23</mem:start> <mem:end>58:34:51</mem:end> <mem:subdate>2001-05-18</mem:subdate> <mem:donor>Elizabeth Davison</mem:donor> <mem:subject>Baseball Game</mem:subject> </mem:audio> </body> </html> 还必须注意,该文件中的前缀不同于在原始 Qnames 模块中指定的前缀。这不是问题。象前缀开关一样,该值优先于任何其它值。 一种类似的方法打开所有添加前缀。 为所有元素添加前缀 打开所有添加前缀与更改缺省添加前缀设置一样简单:<?xml version="1.0"?> <!DOCTYPE xhtml:html SYSTEM "xhtml-memory-1.dtd"[ <!ENTITY % NS.prefixed "INCLUDE"> <!ENTITY % XHTML.prefix "xhtml" > <!ENTITY % Memory.prefix "mem"> ]> <xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mem="http://www.my.org/namespaces/MemoryML"> <xhtml:head><xhtml:title>Sample Page</xhtml:title></xhtml:head> <xhtml:body> <xhtml:p><xhtml:a href="newpage.mml"><mem:subject>Pitching a tent</mem:subject></xhtml:a></xhtml:p> <xhtml:ul> <xhtml:li><mem:subject>Pitching a tent</mem:subject></xhtml:li> <xhtml:li><mem:subject>Baseball game</mem:subject></xhtml:li> </xhtml:ul> <mem:video tapeid="A323"> <mem:media mediaid="A323" type="VHS"/> <mem:start>0:00:00</mem:start> <mem:end>32:12:45</mem:end> <mem:subdate>2001-05-23</mem:subdate> <mem:donor>John Baker</mem:donor> <mem:subject>Pitching a tent</mem:subject> <mem:location><mem:description>Outside in the woods</mem:description></mem:location> </mem:video> <mem:audio tapeid="C531"> <mem:media mediaid="C531" type="DAT"/> <mem:start>12:09:23</mem:start> <mem:end>58:34:51</mem:end> <mem:subdate>2001-05-18</mem:subdate> <mem:donor>Elizabeth Davison</mem:donor> <mem:subject>Baseball Game</mem:subject> </mem:audio> </xhtml:body> </xhtml:html> 还应该注意,因为 %Memory.prefixed; 继承 %NS.prefixed; 的值,所以不需要单独设置它。 XHTML模块化结束语 结束语 本教程演示了通过使用 XHTML 的模块化构建一个新的基于 XHTML 的标记语言所需的方法和过程。 该过程涉及了创建参数化的定义文件,甚至还允许定制实例文档本身。然后,充当实例文档的 DTD 的单一 DTD 驱动程序文件将这些文件结合在一起。 必需的和可选的 XHTML 模块通过几个创建新内容模型和名称空间设置的文件加入到扩展中。 更多信息 有关 XML 的基本背景知识,请阅读 Introduction to XML 教程。 有关“文档对象模型(Document Object Model)”的信息和 XML 名称空间的基本信息,请阅读 Understanding DOM 教程。 有关创建“文档类型定义(DTD)”的信息,请阅读 XML Validation教程。 请阅读 W3C 的 Modularization of XHTML 建议书(Recommendation)。 要查看用多个扩展模块创建语言,请阅读 Shane McCarron 著的 XHTML Modules and Markup Languages -- How to create XHTML Family modules and markup languages for fun and profit。 有关 XML 编程的介绍,请尝试 Doug Tidwell 的 XML programming in Java 教程。 订购 Nicholas Chase 著的 XML and Java from Scratch。它涵盖了 XML 和 Java 的一般性使用。它还涵盖了 XML 的其它以数据为中心的观点,例如 XML Query,以及 XML 的其他使用,例如 SOAP。另外,它就是由这个极佳教程的作者编写的。 下载 IBM Centre for Java Technology Development 提供了用于在一系列平台上创建和测试 Java applet 和应用程序的 developer kits。 下载 JAXP 1.1,XML 处理的 Java API。 从 Apache XML 项目下载 Xerces parser for Java。 从 Apache XML 项目下载 Xerces parser for C++。 从 Apache XML 项目下载 Xerces parser for Perl。 下载 IBM 的 XMI Toolkit,以通过使用 XML 来共享您的 Java 对象、生成 DTD 并转换 Java、UML 和 Rational Rose 之间的设计和代码。


阅读全文(2788) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.191 second(s), page refreshed 144763102 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号