DOM Xerces类库使用方法(转)

    如今随着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 <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);

删除一个元素的属性

  要删除一个元素的属性,使用以下方法:

      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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值