跳转到主要内容

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

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

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

  • 关闭 [x]

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

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

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

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

  • 关闭 [x]

面向 C++ 的服务数据对象简介

用于 SDO 的 C++ API 简介

Ed Slattery (slattery@uk.ibm.com), 软件工程师, IBM UK
Ed Slattery 的照片
Ed Slattery 于 1999 年以软件工程师的身份加入 Java Technology Centre。他最初从事 Shiraz 可重用 VM 技术方面的工作,然后转而研究图形技术 (AWT/Swing),目前在孵化器项目团队,他曾为该团队编写过 SDO 的 C++ 实现核心。此核心现已提交给 Apache Software Foundation 的 Tuscany 孵化器项目。您可以通过 slattery@uk.ibm.com 与 Ed 联系。
Pete Robbins (slattery@uk.ibm.com), 软件工程师, IBM UK
Pete Robbins 的照片
Pete Robbins 是英国的 IBM Hursley 的软件工程师。他于 1981 年加入 IBM,曾担任过各种开发和技术规划职务。最近他在进行 Tuscany 开源 SOA 项目方面的工作,进行过使用 C++ 开发 SDO 的 XML 序列化的工作。然后他继续开发属于 Apache 孵化器项目的 C++ 实现的初始 SCA。他还参与了 SCA 规范的协调工作。您可以通过 robbins@uk.ibm.com 与 Pete 联系。

简介: 本文将向您介绍从 C++ 使用服务数据对象 (Service Data Object) 所需的 API,您可以从中方便地了解该 API 的主要元素,以便快速入门。

发布日期: 2006 年 7 月 31 日
级别: 高级
访问情况 : 1014 次浏览
评论: 


引言

本文将帮助您迅速了解 C++ 中服务数据对象的基本应用程序编程接口(Application Programming Interface,API)。首先向您介绍服务数据对象(Service Data Object,SDO)背后的概念,然后讨论 API 的每个主要区域,以便提供足够的背景知识,从而开始您自己的第一个应用程序。

SDO 概述

服务数据对象提供了一种用于描述数据元素图结构的方法,也提供了一种基于图描述从任何数据源加载特定数据实例的方法。SDO 提供的功能还包括跟踪对应用程序使用的数据图的更改,并记录这些更改,使其在数据从计算机移动到其他计算机时跟随数据移动。因此,SDO 提供了从数据库加载数据并将数据传递给临时连接的客户机的功能。该数据返回时,SDO 可以随即识别在客户机断开连接时所发生的任何更改。

SDO 的主要组成部分有:

  • 元数据(或数据的描述)。这是类型和属性的框架,提供了一组数据必须满足的规则,并可通过从其他数据元素描述其路径来访问数据元素。元数据可以动态构建或从 XSD 描述加载。
  • 用于填充和操作数据图的 API。数据可以从数据源加载(使用数据访问服务)或动态创建。
  • 用于记录对数据图的更改的更改摘要 API。
  • 序列化及传输所有三个元素——元数据、数据和更改摘要——的功能。

数据访问服务遵循相应的 API 描述,因此第三方可以为任何数据源编写自己的数据访问服务。基本 SDO 实现提供了允许从 XML 进行序列化和反序列化的服务。

元数据是通过类型和属性进行描述的,数据工厂可提供完整的描述。此工厂用于创建数据对象,因此在允许进行创建前,此工厂将对元数据执行验证。

类型 是一种描述数据对象的方式,与 Java 中的类相似。Type 存在两个不同的变体数据类型数据对象类型。数据类型与 Java 原语类似,用于表示元素,如整数、字节 Boolean 值及其他。数据工厂会在缺省情况下提供一个数据类型基本集,可表示大部分编程语言的标准原语。其他的可由用户通过对基本类型进行扩展或限制进行定义。

类型是由其统一资源标识符(Uniform Resource Identifier,URI)及其名称定义的。例如,对于预定义的数据类型,都具有一个 commonj/sdo 形式的 URI,且名称为 Byte、Boolean、Short、Integer、Long 等。

数据类型并不具有属性。

而另一方面,数据对象类型可以具有属性,可以将这些属性视为“内嵌”属性或“引用”属性。内嵌属性允许数据对象包含实际数据值。引用属性允许数据对象引用其他位置保存的值。

数据对象类型表示原语的分组和其他数据对象类型,是数据图的构建块。数据对象类型可以具有命名属性,而这些属性本身可以为数据类型或数据对象类型。为了便于图方便地表示表格式数据,每个属性还可以定义为多值或单值。

类型可以为其他类型的子类型,可以集成这个类型的所有属性。类型可以为抽象的,数据工厂将不允许创建该类型的实例。抽象的类型与 C++ 中的纯虚类或 Java 中的接口类似。


公司示例

下面的示例描述了一个典型公司的基本情况,我们将通过这个示例对前面的各个要点进行说明。

公司具有一个名称、很多部门和一名负责人。任何部门都具有一个名称和很多雇员。每个雇员都有自己的姓名、序列号和相应的办公席位。负责人可能有私人帐户号。公司有一名工会代表,他也是雇员之一。

为了演示子类型,让我们将 DirectorType 和 EmployeeType 定义为 PersonType 的子类型。PersonType 具有名为 name 的属性。DirectorType 具有名为 account 的属性,而 EmployeeType 具有名为 serial numberdesk location 的属性。companyType 将需要一个名为 UnionRep 的引用属性,以指向某个雇员。

我们可以定义实例化一个公司所必需的类型和属性。

首先,让我们定义 CompanyType。CompanyType 是一个数据对象类型,因为它具有属性(如名称和部门)。

图 1 显示了需要描述的元数据:
图 1. 类型
类型

可以从 XSD 模式加载此元数据,或对其进行动态创建。在尝试使用 XSD 前,让我们在 C++ API 中使用 DataFactory 动态定义此元数据,如清单 1 中所示。


清单 1. 在 C++ API 中使用 DataFactory

DataFactoryPtr df = DataFactory::getDataFactory();

// df is an empty data factory, containing only definitions of the primitives. We will 
// now define the types.
// Descriptions of 'open' , and 'sequenced' appear later in the document - dont worry 
//about them for now.

bool isSequenced = false;
bool isOpen = false;
bool isAbstract = false;
bool isDataType = false;

df->addType("mynamespace","CompanyType", isSequenced, isOpen, isAbstract, isDataType);
df->addType("mynamespace","DepartmentType", isSequenced, isOpen, isAbstract, isDataType);
df->addType("mynamespace","DirectorType", isSequenced, isOpen, isAbstract, isDataType);
df->addType("mynamespace","EmployeeType", isSequenced, isOpen, isAbstract, isDataType);

isAbstract = true; // we will not let a person be created, only employees or directors
df->addType("mynamespace","PersonType", isSequenced, isOpen, isAbstract, isDataType);

// now we need to tell the data factory that employees and directors "are" persons.

df->setBaseType("mynamespace","DirectorType","mynamespace","PersonType");
df->setBaseType("mynamespace","EmployeeType","mynamespace","PersonType");

// now we need to add properties

bool isMany = false;
bool isReadOnly = false;
bool isContainment = false;

// add all the single valued strings...

df->addPropertyToType("mynamespace","CompanyType","Name","commonj/sdo","String", 
    isMany, isReadOnly, isContainment);
df->addPropertyToType("mynamespace","PersonType","Name","commonj/sdo","String", 
    isMany, isReadOnly, isContainment);
df->addPropertyToType("mynamespace","DepartmentType","Name","commonj/sdo","String", 
    isMany, isReadOnly, isContainment);
df->addPropertyToType("mynamespace","DirectorType","Account","commonj/sdo","String", 
    isMany, isReadOnly, isContainment);
df->addPropertyToType("mynamespace","EmployeeType","Serial Number","commonj/sdo","String",
    isMany,isReadOnly,isContainment);
df->addPropertyToType("mynamespace","EmployeeType","Location","commonj/sdo","String", 
    isMany, isReadOnly, isContainment);

// since unionrep is a reference, isContainment" remains false...
df->addPropertyToType("mynamespace","CompanyType","UnionRep","mynamespace",
    "EmployeeType",isMany,isReadOnly,isContainment);

// the director is contained, unlike the union rep ...
isContainment=true; 
df->addPropertyToType("mynamespace","CompanyType","Director","mynamespace",
    "DirectorType",isMany,isReadOnly,isContainment);

// departments and employees are many valued, and contained...
isMany=true;         
df->addPropertyToType("mynamespace","CompanyType","Departments","mynamespace",
    "DepartmentType", isMany, isReadOnly, isContainment);
df->addPropertyToType("mynamespace","DepartmentType","Employees","mynamespace",
    "EmployeeType", isMany, isReadOnly, isContainment);

对象创建

现在已经定义了元数据,接下来我们将开始创建或加载实际数据实例,如此例中名为 ACME 的实际公司。

数据工厂允许创建数据对象,但所创建的每个对象都具有用于创建相关数据对象的 API。从理论上说,可以仅使用此数据工厂创建公司对应的对象,然后使用公司数据对象创建部门和雇员对象。清单 2 所示的代码对我们的公司 ACME 进行填充。


清单 2. 填充公司对象

// create an object of type CompanyType
DataObjectPtr acme = df->create("mynamespace","CompanyType");

// set its Name property
acme->setCString("Name","ACME");

//Use the company to create departments. The property "Departments" tells the 
// factory which type of object to create.

DataObjectPtr sales = acme->createDataObject("Departments")
sales->setCString("Name","Sales");

DataObjectPtr marketting = acme->createDataObject("Departments")
marketting->setCString("Name","Marketting");

// Now we can use the departments to create employees...

DataObjectPtr sales_emp1 = sales->createDataObject("Employees")
sales_emp1->setCString("Name","Helena B Carter");

DataObjectPtr sales_emp2 = sales->createDataObject("Employees")
sales_emp2->setCString("Name","Anthony W Thompson");

DataObjectPtr marketting_emp1 = marketting->createDataObject("Employees")
marketting_emp1->setCString("Name","Justin Marples");

DataObjectPtr marketting_emp2 = marketting->createDataObject("Employees")
marketting_emp2->setCString("Name","Stephen McTavish");


您可能应该考虑以下问题:

  • 为什么 createDataObject 允许创建两个雇员对象,现在可以采用何种方式对其进行引用?
  • 如何从一个数据对象中访问另一个数据对象或与其进行通信?
  • DataObjectPtr 是什么,哪部分负责删除已使用的数据对象?

createDataObject 使用 name 属性来区分如何动作。对于 Employees,该属性定义为多值属性,因此每次调用 createDataObject 都会在列表中创建另一个相应对象。如果在名为 Director 的属性上调用两次 createDataObject,所创建的第二个对象将替换第一个对象。

如前面代码中所示,您实际上是在按名称访问属性,首先调用 company 对象,告知它处理 Departments 属性,然后该属性调用 department 对象,并告知它处理其 Employees 属性。此访问方法进一步扩展为了 XML 路径语言(XML Path Language,Xpath)的一个子集。即,还可以通过直接与某个对象相关的对象的属性来访问这些属性,从而允许您按照清单 3 中所示访问公司的第一个部门并获取其名称。


清单 3. 访问对象的属性

cout << "Department 1=" << acme->getCString("Departments[1]/Name") << endl;

或者,如清单 4 中所示,访问第二个部门的第二个雇员。


清单 4. 访问第二个雇员

cout << "Employee =" << acme->getCString("Departments[2]/Employees[2]/Name") << endl;

清单 5 中所示的语法使用斜线 (/) 分隔数据对象和属性,使用1 或 0 语法说明引用元素,最终将找到同一个雇员。


清单 5. 用于将数据对象与属性分隔的语法

cout << "Employee =" << acme->getCString("Departments.1/Employees.1/Name") << endl;

注意:在点语法中,第一个元素是编号为 0 的元素,而在括号语法中,第一元素是编号为 1 的元素。

可以将列表作为整体访问,以通过首先获得列表本身来对其进行遍历,如清单 6 中所示。


清单 6. 访问列表

DataObjectList& emps = acme->getList("Departments[1]/Employees");
// Now we can walk the list or add or remove items.


内存管理

到目前为止,几乎全部使用的都是 DataObjectPtrs。而看到的仅是一个数据对象列表(引用)。要正确使用列表和 DataObjectPtrs,现在必须在 SDO 中处理内存管理问题。

SDO 采用内部方式处理其所有内存分配和释放工作,并不要求使用用户代码。DataObjectPtr 实际上是包含指向数据对象的指针的包装类。此包装类会在超出范围或设置为空时丢弃其到数据对象的连接。一定不能删除 DataObjectPtrs。

在该库内部,图中的所有数据对象都由其父项引用,并将保持到从数据图断开为止,因此并不需要删除数据对象。当丢弃对其的客户机引用且未连接到数据图时,会将其自动删除。

数据对象列表是作为引用返回的。这些引用指示您看到的是真正的值列表,而不是副本,并会在更改属性值时进行更新。

到目前为止,您已经了解了如何创建元数据,然后填充和访问与元数据对应的数据图。现在需要说明一下,所有这些操作也可以通过使用 XSDHelper 和 XMLHelper 类完成。XSDHelper 将从 XSD 文档中加载元数据,而 XMLHelper 允许从 XML 文件加载数据图。

清单 7 演示了如何通过使用 XSD 模式完成这些任务。


清单 7. 使用 XSD 模式

<xsd:schema     
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:sdo="commonj.sdo"
    xmlns:sdoxml="commonj.sdo/xml"
    xmlns:company="mynamespace"
    targetNamespace="mynamespace">
    <xsd:element name="company" type="company:CompanyType"/>
     <xsd:complexType name="CompanyType">
         <xsd:sequence>
             <xsd:element name="Departments" type="company:DepartmentType" maxOccurs="unbounded"/>
            </xsd:sequence>
            <xsd:attribute name="Name" type="xsd:string"/>
            <xsd:attribute name="Director" type="company:DirectorType"/>
            <xsd:attribute name="UnionRep"     type="xsd:IDREF"    doxml:propertyType="company:EmployeeType"/>
        </xsd:complexType>
        <xsd:complexType name="PersonType">
         <xsd:attribute name="Name" type="xsd:string"/>
     </xsd:complexType>
     <xsd:complexType name="DepartmentType">
         <xsd:restriction base="company:PersonType" />
         <xsd:sequence>
             <xsd:element name="Employees" type="company:EmployeeType"     maxOccurs="unbounded"/>
         </xsd:sequence>
     </xsd:complexType>
     <xsd:complexType name="EmployeeType">
         <xsd:restriction base="company:PersonType" />
         <xsd:attribute name="Serial Number" type="xsd:ID"/>
         <xsd:attribute name="Desk Location" type="xsd:string"/>
     </xsd:complexType>
    </xsd:schema>


作为 XML 输入的数据如清单 8 中所示。


清单 8. 作为 XML 输入的数据

<?xml version="1.0" encoding="UTF-8" ?>  
<company xmlns="mynamespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
name="ACME"    >
     <Departments Name="Sales"    >
         <Employees>
          <Name>Helena B Carter</Name> 
    <\Employees>
    <Employees> 
          <Name>Anthony W Thompson</Name> 
    </Employees>
</Departments>
<Departments Name="Marketting"    > 
         <Employees>
          <Name>Justin Marples</Name> 
    </Employees>
    <Employees> 
          <Name>Stephen McTavish</Name> 
    </Employees>
</Departments>
</company>

下面清单 9 中所示的代码可替换清单 8 中的所有代码。


清单 9. 替换代码

DataFactoryPtr df = DataFactory::getDataFactory();

XSDHelper xsdh = HelperProvider::getXSDHelper(df);
xsdh->defineFile("company.xsd");

XMLHelper xmlh = HelperProvider::getXMLHelper(df);
XMLDocumentPtr doc = xmlh->createDocument(comp,"companyNS","company");
DataObjectPtr acme = doc->getRootDataObject();

XSDHelper 和 XMLHelper 的方法允许加载和保存 XSD/XML 信息,因此可以使用他们来将元数据和数据从图中保存为序列化格式。

清单 10 显示了用于将元数据保存到新 XSD 文件的 XSDHelper。


清单 10. 用于将元数据保存到新 XSD 文件的 XSDHelper

    xsdh->generateFile(df->getTypes(),
                "output.xsd","companyNS"); 

清单 11 显示了用于将文档保存到新文件的 XMLHelper。


清单 11. 用于将文档保存到新文件的 XMLHelper

xmlh->save(doc,"output.xml");


异常处理

SDO API 会引发大量异常。例如,使用无效的 Xpath 表达式访问数据对象将引发 SDOInvalidPathException。试图使用不存在的属性将引发 SDOPropertyNotFoundException。所有这些异常都从 SDORuntimeException 继承,因此所需的最小错误处理如清单 12 中所示。


清单 12. 最小错误处理

try {
DataFactoryPtr df = DataFactory::getDataFactory();

XSDHelper xsdh = HelperProvider::getXSDHelper(df);
xsdh->defineFile("company.xsd");

XMLHelper xmlh = HelperProvider::getXMLHelper(df);
XMLDocumentPtr doc = xmh->createDocument(comp,"companyNS","company");
DataObjectPtr acme = doc->getRootDataObject();
}
catch (SDORuntimeException e)
{
cout << "Exception caught: "     << e << endl;
}

清单 12 显示了基本的 SDO API。接下来让我们了解一下序列、开放类型、自检 (Introspection) API 和更改摘要。


序列

数据对象类型可以定义为已序列化,即除了用于设置属性的 API 外,这些数据对象上还有另一个 API,可使用其设置相同的属性。还需要记住设置值的顺序。这就为您提供了一种强大的功能,让您知道设置的顺序(即使涉及多值属性),例如,可以知道首先设置 listA 的第一个元素,接着设置 listB 的第一个元素,然后设置 listA 的第二个元素。

而且,序列 API 还提供了在属性设置间添加自由文本设置的的功能。可以设置 listA 的第一个元素,然后包含“Hello”文本项,然后 listA 的第二个元素。序列对于记录一系列事件非常有用(此时非常重要)。


开放类型

开放类型是数据对象类型的一种特殊形式。它具有属性,但如果尝试设置其不包含的属性,它不会引发异常,这一点与普通数据对象不同。相反,它将直接为您创建该属性——在这个特定的数据对象实例上。也就是所,假定您有一个名为 OpenEmployee 的开发类型,该类型具有一个 Name 属性。清单 13 中所示的所有内容都是有效的。


清单 13. 开放类型属性

DataObjectPtr emp = df->create("myspace","OpenEmployee");
emp->setCString("Name","Alphonse Dodet");
emp->setInteger("AlfsNumber", 256);

DataObjectPtr emp2 = df->create("myspace","OpenEmployee");
emp2->setCString("Name","Bill McCawber");
emp2->setBoolean("BillsBool", true);

查询类型 OpenEmployee 的属性时,将会告知其具有一个名为 Name 的属性。查询 emp 的属性时,将会告知其具有 Name 和 AlfsNumber 属性。而 Emp2 会告知其具有 Name 和 BillsBool 属性。请注意,选择用于设置开放属性的 API 将决定所要求的属性类型。(BillsBool 为 Boolean 型,而 AlfsNumber 为 Integer 型。)


自检

用于查找可用的类型并检查其属性的功能称为自检 API。可以查询属于类型的属性和属于数据对象的属性。例如,可以如清单 14 中所示,显示 companyType 的全部元数据。


清单 14. 显示元数据


const Type&  t = df->getType("mynamespace","Company");

cout << "==============================================================" << endl;
cout << "Type: " << t.getURI() << "#" << t.getName() << endl;
if (t.isSequenced())cout << "is Sequenced" << endl;
if (t.isOpenType())cout     << " is Open" << endl;

PropertyList&  pl = t.getProperties();

for (int i=0; i < pl.size() ;i++)
{
             cout << "     Property: " << pl[i].getName() << " ";
             if (pl[i].isMany()) cout << "Many Valued ";
             else cout << "Single Valued ";
             if (pl[i].isDataType) cout << " DataType "; 
             else
             { 
                          if (pl[i].isContainment()) cout " Containment ";
                          else cout << " Reference ";
             }
                 cout << pl[i].getType().getURI() << "#" << pl[i].getType().getName() << endl;
}

cout << "===============================================================" << endl;


更改摘要

更改摘要可以附加到任何数据对象类型。创建数据对象实例的唯一规则是,任何带更改摘要的数据对象都不能包含其他带更改摘要的数据对象。更改摘要采用与属性相似的方式附加到类型,但并不会出现在可设置的属性列表中。更改摘要最初处于非活动状态,因此用户代码需要访问并将其设置开始记录。只要开始记录了,就会记录对其数据对象(及其下的每个数据对象)属性的每次更改。它将记录创建、更改和删除操作。将记录每个项更新前的旧值(创建操作除外)。对相同数据对象的多次更改将仅记录一次,因此相应的旧值保持为最后一次更改前的值。对于删除操作,将记录删除前数据对象的全部状态。

用户代码可以随时关闭记录功能,将保存关闭记录功能前的所有更改。当再次打开记录功能时,将丢失以前日志中的所有更改。

当带更改摘要的数据对象序列化时,也将保存其相应的更改摘要,并能够使用该数据对象进行恢复。更改摘要 API 允许查询图中的所有对象的设置,并确定是否已经对其进行了更改。


总结

您已通过本文简单了解了面向 C++ API 的 SDO。请立即阅读规范文档


参考资料

作者简介

Ed Slattery 的照片

Ed Slattery 于 1999 年以软件工程师的身份加入 Java Technology Centre。他最初从事 Shiraz 可重用 VM 技术方面的工作,然后转而研究图形技术 (AWT/Swing),目前在孵化器项目团队,他曾为该团队编写过 SDO 的 C++ 实现核心。此核心现已提交给 Apache Software Foundation 的 Tuscany 孵化器项目。您可以通过 slattery@uk.ibm.com 与 Ed 联系。

Pete Robbins 的照片

Pete Robbins 是英国的 IBM Hursley 的软件工程师。他于 1981 年加入 IBM,曾担任过各种开发和技术规划职务。最近他在进行 Tuscany 开源 SOA 项目方面的工作,进行过使用 C++ 开发 SDO 的 XML 序列化的工作。然后他继续开发属于 Apache 孵化器项目的 C++ 实现的初始 SCA。他还参与了 SCA 规范的协调工作。您可以通过 robbins@uk.ibm.com 与 Pete 联系。

关于报告滥用的帮助

报告滥用

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


关于报告滥用的帮助

报告滥用

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


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=SOA and Web services
ArticleID=151837
ArticleTitle=面向 C++ 的服务数据对象简介
publish-date=07312006
author1-email=slattery@uk.ibm.com
author1-email-cc=
author2-email=slattery@uk.ibm.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)。