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 <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的工作量應該很小。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章