加载中…
正文 字体大小:

用Xerces操作XML文档

(2006-04-08 16:16:15)
分类: VC编程开发

对于使用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 <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/XMLFormatter.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>

#include <xercesc/parsers/DOMParser.hpp>
#include <xercesc/dom/DOM_Node.hpp>

  /* 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 <xercesc/sax/ErrorHandler.hpp>
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

阅读 评论 收藏 转载 喜欢 打印举报
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4006900000 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有