SEO教程,前端,C++,JAVA个人工作经验分享博客 - 「IT程序猿博客」

DOM Xerces类库使用方法

弘先生

  DOM Xerces类库使用方法

  Tuxedo中XML的历史

  如 今随着XML逐渐成为主流的数据格式之一,自然而然地 Tuxedo将之作为一种基本缓冲类型予以支持。Tuxedo 7.1 引入了XML缓冲类型,但迄今为止对于Tuxedo中的XML并无较多的论述。Tuxedo 7.1中并未携带真正的XML API,因为通常认为将开发人员自己最喜欢的DOM或SAX实现合并到其应用程序中是其自身的责任。

  现在,由于在Tuxedo内嵌了Xerces 1.7 版本(来自Apache XML项目)库,所以伴随Tuxedo 8.1提供了一套真正的XML API。8.1版本还包含了一个称为xmlstockapp(xml股票程序)的XML示例。

  这一点为开发人员增加了许多XML功能,例如XML解析,XML树遍历或构建,以及XML格式化,从而不需要使用外部的产品。

  何为XML?

  XML经常作为一种“语言”被提及,然而它实际上是一种用于描述文本缓冲区中的层次结构数据集的标准格式。这种数据格式可以通过一种加强数据结构和层次关系的本地语法(称为DTD)来进行控制。

  我如何在XML中进行编码?

  XML并非一种语言,而是一种数据格式。编码意味着使用一种API,从一个纯文本缓冲区到数据树来回进行数据转换,或者对数据树进行遍历或操纵。想要了解如何使用XML进行编码,请参看下文“……一般任务”一节。

  有哪些可用的API对XML进行操纵作?

  目前存在数种标准API对XML进行操纵,最著名的是DOM,SAX和XPATH。所有的API都针对不同语言具有不同的实现,但是本文仅仅关注Tuxedo 8.1产品中包含的Xerces的C/C 实现。

  我应在何时使用XML?

  由于XML是一种标准的有组织的格式,如今它已经成为一种广为使用的便利格式来在不同系统间进行数据交换。即使结构上(DTD)略作改动来添加一些子节点或新属性,XML的自描述性和结构化的方式也有助于数据的理解。XML也是易于阅读的,而二进制数据则不然。

  然而XML仍具有一些缺点:

  它使您的数据大幅膨胀(每个域将增加一个20字节左右的标题,并且所有的二进制域将扩大为相应的字符串表达)。

  在进行解析和格式化时它增加了CPU的开销,尤其是在解析和检验文档是否是“格式良好”时。

  其API均比较复杂。

  因此XML是一种理想的集成语言,但是在系统内部您可能并非处处都需要使用它。在Tuxedo中它通常用于同外部系统发送和接收数据。

  对于使用DOM API处理XML数据的程序的一般任务:

  这些任务并非只针对Tuxedo,而是适用于所有使用DOM处理XML数据的程序。

  初始化Xerces

  一旦您希望使用Xerces API进行工作就必须强制进行初始化:

  /* initialise xerces */

  try

  {

  XMLPlatformUtils::Initialize ();

  }

  catch (const XMLException & toCatch)

  {

  char *pMsg = XMLString::transcode (toCatch.getMessage ());

  userlog ("Error during Xerces-c Initialization.\n"

  " Exception message: %s", pMsg);

  delete[]pMsg;

  return -1;

  }

  解析XML文本

  当XML 数据被接收时,它通常是一个文本缓冲区或一个文件。DOM API是一种用于处理数据节点树的API,这种节点树通常由包含了属性和其他元素的元素构成。一个程序可以通过递归扫描元素节点来遍历DOM树。

  如果一个程序希 望通过层次结构,元素名称或者属性来访问缓冲区内的数据,该缓冲区首先需要被读入并转化为一棵数据树。这一过程被称为解析。要执行文本解析您需要实现一个 来源类(LocalFileInputSource或MemBufInputSource)来容纳将要解析的文本,并使用DOMParser的实现来进行 解析。

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  /* parse a XML file */

  char *xmlFileName = "./myfile.xml";

  DOMParser *parser = 0;

  DOM_Document document;

  DOM_Element topLevel;

  LocalFileInputSource source (XMLString::transcode (xmlFileName));

  //

  // Create our parser, then set the parsing options.

  // discovers errors during the course of parsing the XML document.

  //

  parser = new DOMParser ();

  parser->setValidationScheme (DOMParser::Val_Never);

  parser->setDoNamespaces (false);

  parser->setDoSchema (false);

  parser->setValidationSchemaFullChecking (false);

  parser->setCreateEntityReferenceNodes (false);

  parser->setToCreateXMLDeclTypeNode (true);

  //

  // Parse the XML file, catching any XML exceptions that might propagate

  // out of it.

  //

  try {

  parser->parse (source);

  int errorCount = parser->getErrorCount ();

  if (errorCount > 0) {

  printf("%d error(s) occured during parsing config\n", errorCount);

  goto clean;

  }

  }

  catch (const XMLException & e) {

  printf("An error occured during parsing \n Message: %s\n"

  "", e.getMessage ());

  goto clean;

  }

  catch (const DOM_DOMException & e) {

  printf("A DOM error occured during parsing config\n"

  "Exception code: %d\n", e.code);

  goto clean;

  }

  catch (...) {

  printf ("An error occured during parsing config\n");

  goto clean;

  }

  …

  处理解析错误

  一旦遇到解析错误,获取错误发生的行号和列号来代替仅仅进行错误计数(或获取一个致命异常)是更好的方式。这种做法能够通过安装错误处理来轻松实现:

  #include

  class ExampleErrorHandler: public ErrorHandler {

  virtual void anyError(char* type, const SAXParseException& exception) ;

  public:

  /** Default constructor */

  ExampleErrorHandler(){};

  /** Destructor */

  ~ExampleErrorHandler() {};

  void warning(const SAXParseException& exception){anyError("warning", exception); };

  void error(const SAXParseException& exception) {anyError("error", exception); };

  void fatalError(const SAXParseException& exception){anyError("fatal error", exception); };

  void resetErrors() {};

  };

  void ExampleErrorHandler::anyError(char* type, const SAXParseException& exception){

  printf("Parser %s line %d column %d: %ls %ls : %ls", type,

  exception.getLineNumber () ,

  exception.getColumnNumber () ,

  exception.getPublicId () ,

  exception.getSystemId () ,

  exception.getMessage ());

  }

  在解析代码中:

  ExampleErrorHandler handler;

  parser = new DOMParser ();

  parser->setErrorHandler(&handler);

  //

  // Parse the XML file, catching any XML exceptions that might propagate

  // out of it.

  //

  try {

  parser->parse (source);

  }

  …

  创建一棵DOM树

  您可以按这种方式创建一棵DOM树。它创建了根元素。

  /* creates an empty dom tree */

  DOM_DOMImplementation impl;

  DOM_Document doc = impl.createDocument (0, // root element namespace URI.

  rootname, // root element name

  DOM_DocumentType ());// document type object (DTD).

  /* fetch the root element */

  DOM_Element rootElem = doc.getDocumentElement ();

  对一个元素添加子元素

  //Add new (empty) Element to the root element

  DOM_Element parentNode = …;// parent is known

  DOM_Element prodElem = doc->createElement (tagName);

  parentNode->appendChild (prodElem);

  删除一个子元素

  parentNode->removeChild (prodElem);

  修改DOM树元素的标签名称

  一旦元素被创建您就不可以修改其标签名称。

  遍历一个元素的子元素

  既然您已经创建了一个XML元素节点,您(可能)希望访问其子元素:

  DOM_Element parent = …; // parent is known

  DOM_Node child;

  child = parent.getFirstChild ();

  while (child != 0) {

  //work with child

  …

  //pickup next child

  child = child.getNextSibling ();

  }

  按类型过滤子节点

  您可能希望忽略某些节点,在这种情况下,检查节点类型:

  switch (child.getNodeType ())

  {

  case DOM_Node::ELEMENT_NODE:

  …

  break;

  case DOM_Node::ATTRIBUTE_NODE:

  …

  break;

  case DOM_Node::TEXT_NODE:

  …

  break;

  case DOM_Node::CDATA_SECTION_NODE:

  …

  break;

  case DOM_Node::ENTITY_REFERENCE_NODE:

  …

  break;

  case DOM_Node::ENTITY_NODE:

  …

  break;

  case DOM_Node::PROCESSING_INSTRUCTION_NODE:

  …

  break;

  case DOM_Node::COMMENT_NODE:

  …

  break;

  case DOM_Node::DOCUMENT_NODE:

  …

  break;

  case DOM_Node::DOCUMENT_TYPE_NODE:

  …

  break;

  case DOM_Node::DOCUMENT_FRAGMENT_NODE:

  …

  break;

  case DOM_Node::NOTATION_NODE:

  …

  break;

  case DOM_Node::XML_DECL_NODE:

  …

  break;

  default:

  …

  }

  获得一个元素的值

  一个元素内的值存储在一个文本子节点中:

  DOM_Element parent = …; // parent is known

  DOM_Node child;

  DOM_Text value;

  child = parent.getFirstChild ();

  while (child != 0) {

  //work with child

  if (child.getNodeType () == DOM_Node::TEXT_NODE) {

  value = (DOM_Text &) child;

  break;

  }

  //pickup next child

  child = child.getNextSibling ();

  }

  DOMString unicodeValue = value.getData ();

  //if you need the ascii value

  char* asciiValue = unicodeValue.transcode ();

  //work with your value

  …

  //free the value

  delete []asciiValue ;

  更改DOM树元素的值

  另外,如果存在的话,不要忘记删除之前的值:

  DOM_Element parent = …; // parent is known

  DOM_Node child;

  DOM_Text value;

  bool childFound = false;

  child = parent.getFirstChild ();

  while (child != 0) {

  //work with child

  if (child.getNodeType () == DOM_Node::TEXT_NODE) {

  value = (DOM_Text &) child;

  childFound = true;

  break;

  }

  //pickup next child

  child = child.getNextSibling ();

  }

  //now , maybe create a text node

  if (!childFound) {

  value = doc->createTextNode ();

  parent.appendChild (value);

  }

  DOMString unicodeValue(asciiValue);

  value.setData(unicodeValue);

  添加或修改一个元素的属性

  要添加(或设置)一个元素属性的值,使用以下方法:

  DOMString unicodename(asciiname);

  DOMString unicodevalue(asciivalue);

  DOM_Element element = …;// element is known

  //Add new attribute to the element

  element->setAttribute(unicodename, unicodevalue);

  删除一个元素的属性

  要删除一个元素的属性,使用以下方法: [I.L.H1]

  DOMString unicodename(asciiname);

  DOM_Element element = …;// element is known

  //Add new attribute to the element

  element->removeAttribute(unicodename);

  遍历一个元素的属性

  要浏览一个元素的所有属性,您可以按以下方法加以实现:

  //loop through this element attributes and fill the config structure

  DOMString unicodename;

  DOMString unicodevalue;

  DOM_NamedNodeMap attributes;

  DOM_Element element = …;// element is known

  attributes = element.getAttributes ();

  int attrCount;

  attrCount = attributes.getLength ();

  for (i = 0; i < attrCount; i ) {

  DOM_Node attribute = attributes.item (i);

  //work with the attribute

  unicodename = attribute.getNodeName ();

  unicodevalue= attribute. getNodeValue ();

  //if need ascii values, get them

  char* asciiname= unicodename.transcode ();

  char* asciivalue = unicodevalue.transcode ();

  …

  //but don't forget to release them

  delete []asciiname;

  delete []asciivalue;

  }

  将DOM树作为文本缓冲区打印输出

  并没有直接的方法来将DOM树格式化为XML文本缓冲区。最简单的方法是参考Xerces 1.7中DOMPrint的示例,或者查看一下本文附带的XFML库中的XMLimplementation.hxx文件。

  具体的想法是实现一个函数,该函数将遍历所有节点并将节点及其属性打印输出。

  Tuxedo中的XML示例:

  所有附带的代码示例均经过编译,并在Microsoft Windows NT下使用。由于示例中依赖的库均已在Unix中经过编译,移植到Unix的工作量应该很小。

发表评论 (已有 条评论)

说点什么吧
  • 全部评论(0
    还没有评论,快来抢沙发吧!

快来评论,快来抢沙发吧~