跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

创建可维护、可扩展的 XML 格式

在设计可以灵活满足新需求的 XML 格式时减少修改

Adriaan de Jonge, 软件专家, WSO2 Inc
Adriaan de Jonge
Adriaan de Jonge 是一位软件专家,目前为荷兰政府工作,同时在多个项目中担任不同的角色。Adriaan 曾经为 IBM developerWorks 和 Amazon 撰写过关于 XML 的文章。
S. E Slack, 作家兼业务转换咨询师, 自由作家
Slack 是 Studio B 的作家和多部图书的作者,包括最近出版的 Windows Vista Home Entertainment with Windows Media Center and Xbox 360。她还是 IBM、State Farm 和联想国际的主管和业务转换咨询师。

简介: XML 是一种交换结构化文档和数据的通信格式。人们经常随意地在开发过程中临时决定选择 XML 格式,而没有提前计划或设计。只有提前设计好正确的 XML 格式,才能满足通信各方的要求。否则就不得不反复地修改。了解如何设计一种不经常进行修改的格式,足够敏捷,不需要彻底修改而仅需填加少许扩展就能适应新的需求。

发布日期: 2008 年 10 月 23 日
级别: 初级 其他语言版本: 英文
访问情况 : 3140 次浏览
评论: 


10 年来,XML 发展成为了一种常见的、受到广泛接受的标准,用来在组织内部和组织之间存储和交换数据。XML 本身仅仅是一种抽象,其成功完全依赖于一个或多个组织所设计的 XML 格式。与任何软件产品一样,随着业务需求的变化,这些 XML 格式也面临着维护问题。而且这些变化不是一般意义上的:迫于竞争和市场的原因,XML 格式经常需要针对多个组织同时进行更新。

常用缩写词

  • NXD:原生 XML 数据库(Native XML database)
  • XSD:XML 模式定义(XML Schema Definition)
  • XSLT:XML 样式表语言转换(XML Stylesheet Language Transformation)
  • W3C:万维网联盟(World Wide Web Consortium)
  • XML:可扩展标记语言(Extensible Markup Language)

仅仅维护一个 XML 模式还比较容易。但是如果修改影响到数百组织,问题就大了。对 XML 模式进行一次简单的修改可能要花费大量的时间和金钱,但是如果事先设计好,可能只需要再看一遍就行了。本文讨论两个问题:

  • 如何控制这种影响
  • 如何尽可能地减小这种影响

我们使用一个非常简单的例子,涉及到汽车、轮胎、挡风玻璃和有关的公司或者分销商。虽然不完全符合实际,但足以说明提高 XML 格式可维护性的必要性了。

简单但是存在问题

关于 XML 模式

XML Schema 是一种 XML 格式,可用于形式化地描述 XML 格式。XML 工具可使用 XML Schema 的实例验证 XML 文档,就是说检验一个 XML 文档是否符合 XML Schema 所规定的格式。XML Schema 的前身是文档类型定义(DTD),DTD 仍然用于描述 HTML。XML Schema 的特色之一是它本身用 XML 表示。实际上,您可以用 XML Schema 描述 XML Schema 格式。表示 XML 模式有不同的语言,比如 XML Schema (W3C) 和 RELAX NG。XML 模式通常指 XML Schema Definition

只有符合相关模式的要求,XML 文档才会被认为是有效的。

首先,我们以 Volvo C30 和米其林轮胎为例建立一个 XML 文件来共享关于轮胎的信息。如 清单 1 所示。


清单 1. 共享轮胎信息的简单 XML 文件
                
<car>
   <brand>Volvo</brand>
   <type>C30</type>
   <kind>Small family car</kind>
   <tires>
      <tire>
         <brand>Michelin</brand>
         <type>Winter</type>
         <count>4</count>
      </tire>
      <tire>
         <brand>Michelin</brand>
         <type>Spare</type>
         <count>1</count>
      </tire>
   </tires>
   <windscreen count="1">
      <brand>Car glass</brand>
   </windscreen>
</car>

这个 XML 文件看起来很简单,是不是?初看起来可能没有什么问题。但是再深入地想想。真正的问题在于 XML 模式。它非常大,而且是一个整体。现在考虑一下这种只有少量元素类型的 XML 格式。设想一下如果用于一个真实的例子会变成什么样,如 清单 2 所示。


清单 2. 描述简单 XML 格式的 XML 模式
                
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="car">
    <xs:complexType>
      <xs:complexContent>
        <xs:extension base="brand">
          <xs:sequence>
            <xs:element ref="type"/>
            <xs:element ref="kind"/>
            <xs:element ref="tires"/>
            <xs:element ref="windscreen"/>
          </xs:sequence>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>
  <xs:element name="kind" type="xs:string"/>
  <xs:element name="tires">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" ref="tire"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="tire">
    <xs:complexType>
      <xs:complexContent>
        <xs:extension base="brand">
          <xs:sequence>
            <xs:element ref="type"/>
            <xs:element ref="count"/>
          </xs:sequence>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>
  <xs:element name="count" type="xs:integer"/>
  <xs:element name="windscreen">
    <xs:complexType>
      <xs:complexContent>
        <xs:extension base="brand">
          <xs:attribute name="count" use="required" type="xs:integer"/>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="brand">
    <xs:sequence>
      <xs:element ref="brand"/>
    </xs:sequence>
  </xs:complexType>
  <xs:element name="brand" type="xs:string"/>
  <xs:element name="type" type="xs:NCName"/>
</xs:schema>

如果您要说 “这有什么?反正没有人去看 XSD 文件”,先想想业务过程中可能会发生的变化。如果需要修改轮胎 XML 以反映其尺寸怎么办,比如:

[...]
<tire>
   <brand>Michelin</brand>
   <type>Winter</type>
   <count>4</count>
   <size>20"</size>
</tire>
[...]

这样一个小小的变化就意味着只要修改轮胎格式,生产挡风玻璃的公司就将得到一份新的 XSD。而且还需要修改自己的软件以便理解这种 XSD。这可不是好消息。因为给挡风玻璃公司增加了额外的工作和成本。轮胎公司也会收到一份新的 XSD,根据使用的软件也可能需要进行修改。可能没人阅读 XSD,但确实让很多人非常恼火。


快速解决:模块

为了避免此类恐怖的 XSD 文件,办法是为轮胎和挡风玻璃提供自己的名称空间并放到单独的 XSD 文件中。清单 3 显示了这样做的结果。


清单 3. 包含名称空间的 XML 文件
                
[...]
   <tr:tires>
      <tr:tire count="4">
         <tr:brand>Michelin</tr:brand>
         <tr:type>Winter</tr:type>
      </tr:tire>
      <tr:tire count="1">
         <tr:brand>Michelin</tr:brand>
         <tr:type>Spare</tr:type>
      </tr:tire>
   </tr:tires>
   <wnd:windscreen count="1">
      <wnd:brand>Car glass</wnd:brand>
   </wnd:windscreen>
[...]

如果这样修改而不改变汽车 XML 的其他部分,XSD 文件就会变得更简短,更容易处理。大部分相关信息都转移到了在 XSD 之上导入的其他 XSD 中。现在的 XSD 文件如 清单 4 所示。


清单 4. 导入单独的轮胎和挡风玻璃 XSD 的汽车 XML 模式
                
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      elementFormDefault="qualified" 
      targetNamespace="http://car.org/car" 			
      xmlns:tr="http://car.org/tire" 
      xmlns:wnd="http://car.org/windscreen" 
      xmlns:car="http://car.org/car">
 <xs:import namespace="http://car.org/tire" schemaLocation="tr.xsd"/>
 <xs:import namespace="http://car.org/windscreen" schemaLocation="wnd.xsd"/>
 <xs:element name="car">
   <xs:complexType>
         <xs:sequence> 
               <xs:element ref="car:brand"/>
               <xs:element ref="car:type"/>
               <xs:element ref="car:kind"/> 
               <xs:element ref="tr:tires"/>
               <xs:element ref="wnd:windscreen"/>
         </xs:sequence>
   </xs:complexType>
 </xs:element>
 <xs:element name="brand" type="xs:NCName"/>
 <xs:element name="type" type="xs:NCName"/>
 <xs:element name="kind" type="xs:string"/>
</xs:schema>

它变成了 XSD 的一个模块。XSD 文件实际上没有压缩多少,但重要的是 XSD 更具模块化,更容易处理。这样就可以修改轮胎模式的某些部分然后分发给所有的轮胎公司,而不用打扰与此无关的挡风玻璃公司。


模块的优点

模块化不仅仅有助于控制分布式的可维护问题。还可以提高单个元素的可重用性。比方说,假设轮胎公司同时生产自行车和汽车轮胎。轮胎公司可能希望使用相同的 XSD 文件描述自行车轮胎。但是购买这些轮胎的自行车公司不需要描述汽车的 XML 模式,因为大多数元素和汽车公司没有关系。比如自行车一般不装挡风玻璃。自行车公司希望他们的自行车 XSD 仅仅导入轮胎 XSD。

这种情况下,XML 可能如 清单 5 所示。


清单 5. 重用轮胎 XML 格式描述自行车的 XML 示例文件
                
<bicycle>
[...]
   <tr:tire count="2">
      <tr:brand>Gazelle</tr:brand>
      <tr:type>Race</tr:type>
      <tr:size>25"</tr:size>
   </tr:tire>
[...]
</bicycle>

和汽车 XSD 非常相似,导入了轮胎,但这是针对自行车的。下一个例子我们再回到汽车。


控制模块的实体性

最终,汽车 XSD 不仅要导入挡风玻璃和轮胎的 XSD,可能还有发动机 XSD、方向盘 XSD、座椅 XSD、车漆 XSD 等等。这将变得难以管理。对这个问题可以用一个单独的 XSD parts.xsd 来导入汽车的所有零部件。这样如果需要修改导入列表,只有 parts.xsd 文件专门用于管理这些依赖性的变化。清单 6 显示了完整的例子。


清单 6. 使用单独的文件包含导入列表的汽车 XML 模式
                
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      elementFormDefault="qualified" 
      targetNamespace="http://car.org/car" 
      xmlns:tr="http://car.org/tire" 
      xmlns:wnd="http://car.org/windscreen" 
      xmlns:car="http://car.org/car">
 <xs:include schemaLocation="parts.xsd"/>
 <xs:element name="car">
   <xs:complexType>
         <xs:sequence> 
               <xs:element ref="car:brand"/>
               <xs:element ref="car:type"/>
               <xs:element ref="car:kind"/> 
               <xs:element ref="tr:tires"/>
               <xs:element ref="wnd:windscreen"/>
         </xs:sequence>
   </xs:complexType>
 </xs:element>
 <xs:element name="brand" type="xs:NCName"/>
 <xs:element name="type" type="xs:NCName"/>
 <xs:element name="kind" type="xs:string"/>
</xs:schema>

parts.xsd 文件如 清单 7 所示。


清单 7. parts.xsd:要包含的导入列表
                
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      elementFormDefault="qualified" 
      targetNamespace="http://car.org/car" 
      xmlns:tr="http://car.org/tire" 
      xmlns:wnd="http://car.org/windscreen" 
      xmlns:car="http://car.org/car">
  <xs:import namespace="http://car.org/tire" schemaLocation="tr.xsd"/>
  <xs:import namespace="http://car.org/windscreen" schemaLocation="wnd.xsd"/>
</xs:schema>

使用 parts.xsd 明显的好处是 XSD 导入列表不需要复制到需要引用这些零部件的每个 XSD 文件。只需要包含一次就可以了。


实际应用中的风险

随着实际应用中元素和零部件数量的增长,必须小心地注意类型定义。比方说,XML 格式中很常见 — 但存在风险 — 的一种做法是使用非限定的属性 — 即没有专门属于某个名称空间的属性,如 清单 8 所示。


清单 8. 带有非限定属性 count 的 XML
                
<tr:tires>
   <tr:tire count="4">
      <tr:brand>Michelin</tr:brand>
      <tr:type>Winter</tr:type>
   </tr:tire>
   <tr:tire count="1">
      <tr:brand>Michelin</tr:brand>
      <tr:type>Spare</tr:type>
   </tr:tire>
</tr:tires>
<wnd:windscreen count="1">
   <wnd:brand>Car glass</wnd:brand>
</wnd:windscreen>

如果根据非限定属性选择元素,就很难预测结果。比方说,如果用下面的 XPath 查询选择属性 count 的值为 1 的所有元素,就无法确定结果属于哪个名称空间:

//[@count = 1]

如果可以得到结果,那么当然可以 推断其名称空间,因为这个例子毕竟非常简单。但问题是这种情况可能很快失控。解决的办法是用特定名称空间限定每个属性。看一看 清单 9 所示例子中的微妙差别。


清单 9. 限定 count 属性的 XML
                
[...]
   <tr:tires>
      <tr:tire tr:count="4">
            <tr:brand>Michelin</tr:brand>
            <tr:type>Winter</tr:type>
      </tr:tire>
      <tr:tire tr:count="1">
            <tr:brand>Michelin</tr:brand>
            <tr:type>Spare</tr:type>
      </tr:tire>
   </tr:tires>
   <wnd:windscreen wnd:count="1">
      <wnd:brand>Car glass</wnd:brand>
   </wnd:windscreen>
[...]

幸运的是,这也意味着 XML 模式中的微妙区别,如 清单 10 所示。


清单 10. 限定属性 count 的轮胎 XML 模式
                
[...]
  <xs:element name="tire"> 
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="tr:brand"/>
        <xs:element ref="tr:type"/>
      </xs:sequence>
      <xs:attribute name="count" use="required" form="qualified" type="xs:integer"/>
    </xs:complexType>
  </xs:element>
[...]

效果可能不明显,但值得注意。最好在能够做到的时候避免可能出现的冲突。


设计更通用的格式

采用关系数据库作为存储后端的时候,往往会建立数据库表或字段到 XML 结构一对一的转换。这样做不仅限制了建模的自由度,而且会把数据库的局限传递给其他有关方面,即便它们不使用该数据库。清单 1 中的 XML 就是这种关系数据库中一对一转换的例子。

但是有可能需要文档的模型稍微不同。比方说,可能需要汽车从前到后的布局以便自动绘制出所有零部件。可以用 清单 11 所示的例子来说明,然后使用 XSLT 转换为可缩放向量图型(SVG)。尽管乍看起来可能很难,实际上并非如此。创建的 XML 文件如下:


清单 11. 使用不同结构的 XML
                
<car>
   <brand>Volvo</brand>
   <type>C30</type>
   <kind>Small family car</kind>
   <tr:tire tr:count="2">
      <tr:brand>Michelin</tr:brand>
      <tr:type>Winter</tr:type>
   </tr:tire>
   <wnd:windscreen wnd:count="1">
      <wnd:brand>Car glass</wnd:brand>
   </wnd:windscreen>
   <tr:tire tr:count="2">
      <tr:brand>Michelin</tr:brand>
      <tr:type>Winter</tr:type>
   </tr:tire>
   <tr:tire tr:count="1">
      <tr:brand>Michelin</tr:brand>
      <tr:type>Spare</tr:type>
   </tr:tire>
</car>

汽车 XSD 现在变成了 清单 12(特别要注意 car 元素中的 complexType)。


清单 12. 描述不同结构的汽车 XML 模式
                
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      elementFormDefault="qualified" 
      targetNamespace="http://car.org/car" 
      xmlns:tr="http://car.org/tire" 
      xmlns:wnd="http://car.org/windscreen" 
      xmlns:car="http://car.org/car">
  <xs:import namespace="http://car.org/tire" schemaLocation="tr.xsd"/>
  <xs:import namespace="http://car.org/windscreen" schemaLocation="wnd.xsd"/>
  <xs:element name="car">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="car:brand"/>
        <xs:element ref="car:type"/>
        <xs:element ref="car:kind"/>
        <xs:choice maxOccurs="unbounded">
          <xs:element ref="tr:tire"/>
          <xs:element ref="wnd:windscreen"/>
        </xs:choice>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="brand" type="xs:NCName"/>
  <xs:element name="type" type="xs:NCName"/>
  <xs:element name="kind" type="xs:string"/>
</xs:schema>

将该文件存储在关系数据库中并在以后再检索相同的 XML 文档稍微复杂一些。对此而言 NXD 非常方便。Exist DB 是支持这类 NXD 的一种简单的开放源代码数据库。IBM DB2 Express-C 是另一种免费数据库,提供了关系数据库和 XML 数据库的集成解决方案。它支持用 SQL 或 XQuery 之类纯 XML 技术访问数据库。


管理 XML 模式的版本和文档

很多情况下,多家公司同时使用同一 XML 模式的不同版本很正常。只要知道使用的是哪一个版本,该版本中哪些元素有变化,就可以了。学习利用 XSD 的标注元素描述版本和元素信息是一种好的习惯。标注可以包含两个元素:documentationappinfo

documentation 元素恰如其名 — 使用的总是文档,很少会忘掉!更有意思的是 appinfo 元素,因为它可以包含需要的任何内容。比方说,可以定义自定义元素 version 包含特定元素的版本,则 XSD 如 清单 13 所示。


清单 13. 包含自定义标注的 XML 模式
                
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      elementFormDefault="qualified" 
      targetNamespace="http://car.org/tire" 
      xmlns:tr="http://car.org/tire" 
      xmlns:custom="http://car.org/custom">
 <xs:element name="tires">
   <xs:annotation>
         <xs:appinfo>
                <custom:version>0.91</custom:version>
             </xs:appinfo>
             <xs:documentation>
                Describes a set of tires.
         </xs:documentation>
   </xs:annotation>
   <xs:complexType>

虽然 XSD 解析器不知道如何处理自定义的版本,但是它们和其他类似的自定义属性可以帮助在更大的组织中管理 XSD。毕竟,XML 文件和 XML 模式是要同时供人类和计算机读取的,最好也从这个角度对待 XSD。


关于扩展

值得注意的最后一个 XML 模式特性是 extension 元素。上一节 中,我们看到了 XSD appinfo 元素的可扩展性。默认情况下,该元素可以容纳任何内容。增加 extension 元素是一种更加严格的扩展类型的方式。清单 14 中的 XSD 文件说明了如何扩展 basicTire 类型以包含 size 元素。


清单 14. 增加 size 元素的轮胎 XML 模式
                
<xs:element name="tire" type="tr:sizedTire"/>
  <xs:complexType name="basicTire">
    <xs:sequence>
      <xs:element ref="tr:brand"/>
      <xs:element ref="tr:type"/>
    </xs:sequence>
    <xs:attribute name="count" use="required" form="qualified" type="xs:integer"/>
  </xs:complexType>
  <xs:complexType name="sizedTire">
    <xs:complexContent>
      <xs:extension base="tr:basicTire">
        <xs:sequence>
          <xs:element ref="tr:size"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

如果需要,XML 模式甚至还允许明确禁止扩展 basicType。如果希望进一步了解 XSD 规范,请参阅 参考资料。可以看到本文没有机会描述的其他很多 XML 模式的有趣特性。


结束语

如您所见,如果希望在大型企业及外围企业中保持 XML 格式的可维护性,就不能将 XML 模式看作一种自动生成的技术文档。有很多办法可以提高 XML 模式的可维护性。甚至还可用其他语言描述 XML 格式,比如 Schematron 和 RELAX NG。无论采用何种形式,提前设计好 XML 格式才能满足通信各方的需求。


参考资料

学习

获得产品和技术

  • Exist DB:下载和尝试这种开放源代码的数据库管理系统。Exist DB 完全建立在 XML 技术上,按照 XML 数据模型存储 XML 数据,特点是高效、基于索引的 XQuery 处理。

  • DB2 Express-C 9.5:尝试这种兼具灵活性、可靠性且功能强大的关系和 XML 数据服务器。

  • 用于产品评估的 IBM 试用软件:使用这些试用软件开发您的下一个项目,可直接从 developerWorks 下载,包括来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。

讨论

作者简介

Adriaan de Jonge

Adriaan de Jonge 是一位软件专家,目前为荷兰政府工作,同时在多个项目中担任不同的角色。Adriaan 曾经为 IBM developerWorks 和 Amazon 撰写过关于 XML 的文章。

Slack 是 Studio B 的作家和多部图书的作者,包括最近出版的 Windows Vista Home Entertainment with Windows Media Center and Xbox 360。她还是 IBM、State Farm 和联想国际的主管和业务转换咨询师。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Information Management
ArticleID=347568
ArticleTitle=创建可维护、可扩展的 XML 格式
publish-date=10232008
author1-email=adriaandejonge@gmail.com
author1-email-cc=
author2-email=sally@sslack.com
author2-email-cc=

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。