c++语言 xml数据绑定技术简介

The C++ Source
An Introduction to XML Data Binding in C++
by Boris Kolpackov
May 4, 2007

原文:http://www.artima.com/cppsource/xml_data_binding.html

一个c++应用程序需要处理 xml 格式的数据,一般的不外乎有两种存取 xml 的API:文档对象模型(Document Object Model,dom)或者 xml 简单 API。(SAX)。DOM 将xml描述为一个树状的数据结构,以供程序遍历和存取。SAX 是一个事件驱动的 解析的XML API。应用程序注册它感兴趣的事件--诸如元素结点、属性、文本之类的东东。当解析 xml时,会触发应用程序注册的这些事件。

DOM 是先将整个 xml文档读入内存,然后再解析数据,而 SAX 是在解析过程中传递这些数据。


无论使用 DOM还是 SAX,要处理大量的 xml 数据都非易事。毕竟,DOM 和 sax 都是 xml 结构,和对元素、属性、文本的操作,在内存中的表达。程序员不得不写大量的代码,将xml编码翻译为程序可使用的逻辑。例如,下面是一个简单的xml文档,它描述了一个人。


<person>

  <name>John Doe</name>

  <gender>male</gender>

  <age>32</age>

</person>


如果我们想确保这个人的年龄大于某个阀值,那么,无论是使用 DOM 还是 SAX,我们都必须先找到“年龄”这个元素,然后将文本 “32” 转换为 int 类型。这时才能做比较。通用API的另一个显著缺点是基于字串流的控制。在上面的例子中,要查找“年龄”元素,我们需要先顺序地解析 name 元素,如果元素拼写错误,那我们只有在运行时才能发现这个 bug。字串流的代码也影响了代码的可读性和可维护性。此外,通用 api 缺乏类型安全机制,因为所有的类型都表现为文本类型。例如,我们可以堂而皇之地将表示“性别”的元素和其它的任意东西做比较,而编译器不会给出任何警告。

DOMElement* gender = ...


if (gender->getTextContent () == "man")

{

  ...

}


近年来,出现了一种处理 xml的新手段。叫做 xml 数据绑定。xml数据绑定技术的出现,得益于 xml 语意描述语言 ( xml shemas )的发展。 xml 数据绑定技术的核心思想是:将数据解析到一个对象(而不再是内存中)。这样,程序员就不需要再处理那些 xml底层操作,因为这些对象可以被程序逻辑直接识别和执行。还是拿上面的例子来说,我们不再搜索表示年龄的文本串,把它手工转成 int,而是简单地调用 person对象的 age()方法,age 方法返回的结果是一个 int 。所谓“绑定”,就是说,“对象”必须是,而是只能是用于表达xml数据块。

对象,以及用于操作对象的相关代码--比如解析和序列化函数--是由 数据绑定工具 生成的。数据绑定工具 是一种 来自于 xml schema。 schema 是一种语法规范--规定了元素的名称、属性、内容,以及元素之间的结构关系。大多数的 数据绑定工具都使用了 W3c 的W3C XML Schema 规范。一来因为它用的比较普遍。二来因为它的良好的面向对象特性。下面一段 代码描述了我们前面的 person 文件。使用的是 w3c xml schema 规范。

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">


  <xs:simpleType name="gender_t">

    <xs:restriction base="xs:string">

      <xs:enumeration value="male"/>

      <xs:enumeration value="female"/>

    </xs:restriction>

  </xs:simpleType>


  <xs:complexType name="person_t">

    <xs:sequence>

      <xs:element name="name" type="xs:string"/>

      <xs:element name="gender" type="gender_t"/>

      <xs:element name="age" type="xs:short"/>

    </xs:sequence>

  </xs:complexType>


  <xs:element name="person" type="person_t"/>


</xs:schema>


即使你不熟悉 xml schema,你也能看明白上面这些代码干了些什么。gender_t 是一种枚举类型。其值有两种可能: male 或 female。 person_t 被定义为一个序列,其中嵌套了 name, gender, age 元素。注意:术语“序列”,在xml schema 的意思是:in 元素按指定的顺序出现。a particular order as opposed to appearing multiple times. 最后,全局定义  person 指明了 结构体的根元素。关于 xml schema的更多资料,请参考 w3c规范:xml schema part0: primer。

   像其它的直接解析 xml的 api一样, xml 数据绑定也支持 内存模式和 事件驱动模式。下一节中,我们将对比  xml 数据绑定技术和 dom 及  sax 的性能表现。本例中使用的 DOM 和 SAX 例子是基于 Apache 的一款C++ 开源 XML 解析器 Xerces。为了简单起见,不对数据做类型识别。


内存式的 xml 绑定。

In-Memory XML Data Binding

Based on an XML schema, a data binding compiler generates C++ classes that represent the given vocabulary as a tree-like in-memory data structure as well as parsing and serialization functions. The parsing functions are responsible for creating the in-memory representation from an XML instance while the serialization functions save the in-memory representation back to XML. For the schema presented in the introduction, a data binding compiler could generate the following code:

利用 xml schema,数据绑定工具生成了 c++ 类。这些类把 xml数据表现内存中的树状结构的数据。和一些解析、序列化的函数。解析函数负责从xml实例中抽取数据并表达为内存对象,而序列化函数则把内存对象还原为 xml。根据前面所给的 schema,数据绑定工具会生成下面的代码:

class gender_t

{

public:

  enum value {male, female};


  gender_t (value);

  operator value () const;


private:

  ...

};


class person_t

{

public:

  person_t (const string& name,

            gender_t gender,

            short age);


  // name

  //

  string& name ();

  const string& name () const;

  void name (const string&);


  // gender

  //

  gender_t& gender ();

  gender_t gender () const;

  void gender (gender_t);


  // age

  //

  short& age ();

  short age () const;

  void age (short);


private:

    ...

};


std::auto_ptr<person_t> person (std::istream&);

void person (std::ostream&, const person_t&);

对比代码和 xml schema声明,可以看出 schema 编译工具将 schema 类型映射为c++ 中的类,将本地元素映射为一组操作,将全局元素映射为一组解析和序列化的函数。

下面,我们将深入观察三个普通的 xml 处理任务。使用 dom和  xml 数据绑定。这三个任务是:访问xml数据,修改现有的数据,创建新数据。通过这些试验,我们将证实 xml数据绑定比较于  dom 的优越性。

下面的代码使用数据绑定技术来读取 xml 文件中保存的某人的信息,如果此人的姓名大于30,则打印其姓名。简单起见,没有考虑错误处理。

ifstream ifs ("person.xml");

auto_ptr<person_t> p = person (ifs);


if (p->age () > 30)

  cerr << p->name () << endl;

上面的例子简单明了。一旦xml文件读到内存中,代码便不再依赖 xml,代码和程序中的其它的对象模型配合得天衣无缝。 同时要注意 c++ class表现的数据是静态的。

下面的代码使用 dom 来完成相同的任务。


ifstream ifs ("person.xml");

DOMDocument* doc = read_dom (ifs);

DOMElement* p = doc->getDocumentElement ();


string name;

short age;


for (DOMNode* n = p->getFirstChild ();

     n != 0;

     n = n->getNextSibling ())

{

  if (n->getNodeType () != DOMNode::ELEMENT_NODE)

    continue;


  string el_name = n->getNodeName ();

  DOMNode* text = n->getFirstChild ();


  if (el_name == "name")

  {

    name = text->getNodeValue ();

  }

  else if (el_name == "age")

  {

    istringstream iss (text->getNodeValue ());

    iss >> age;

  }

}


if (age > 30)

  cerr << name  << endl;


doc->release ();






    







原文地址:https://www.cnblogs.com/diylab/p/1338034.html