原文地址:http://xerces.apache.org/xerces-c/program-dom.html
設計目標
DOM的C++實現是基於阿帕奇推薦的DOM(Apache Recommended DOM C++ binding).
設計目標是為了滿足如下需求:
1.降低記憶體佔用率.
2.提高應用程式的效能,特別是那些伺服器類型和多線程的應用程式.
3.多處理系統中優異的延展性.
4.比起Java來其風格更像C++
Xerces-C++對DOM Level 3的支援
Xerces-C++2.8.0包含了W3C DOM(文件物件模型)Level 3的部分實現,此實現是實驗性的.詳情請查看文檔DOM Level 3 Support。
使用DOM API
在您的程式碼中訪問API
#include <xercesc/dom/DOM.hpp>
在標頭檔<dom/DOM.hpp>中,包含了DOM API類所需要的全部標頭檔
類名
DOM類名都以“DOM”為首碼(如果類名本身不以“DOM”開頭),例如“DOMNode”,這樣是為了防止DOM類名與這樣一些類名混淆:一些名稱可能已經在應用程式或基於DOM的應用程式所必須連結的類中所使用了。
DOMDocument* myDocument;
DOMNode* aNode;
DOMText* someText;
對象管理
應用程式在C++ DOM中將使用標準C++指標直接存取對象所實現的節點。
思考下面的程式碼片段:
DOMNode* aNode;
DOMNode* docRootNode;
aNode = someDocument->createElement(anElementName);
docRootNode = someDocument->getDocumentElement();
docRootNode->appendChild(aNode);
記憶體管理
C++ DOM的實現提供了一個release()方法用來釋放所有的通過creatxxxFactory 方法建立的“孤兒(即現在已不再使用的)”資源,對象銷毀而釋放的記憶體資源由C++ DOM的實現進行管理。更詳細說明請查看Apache Recommended DOM C++ binding。
使用DOMImplementation::createXXX建立對象
使用者必須調用release() 函數來釋放由DOMImplementation::createXXX建立的現在已經使用完畢的對象,如DOMBuilder, DOMWriter, DOMDocument, DOMDocumentType。
試圖訪問已經被釋放的對象將導致異常行為。
1.當一個DOMDocument對象被釋放後,所有與此對象相關的子物件以及其所擁有的對象(如DOMRange, DOMTreeWalker, DOMNodeIterator或任何孤立的節點)也將被釋放。
2.當複製一個DOMDocument對象時,這個複製文檔對象不再與其父類文檔對(original master document)象有任何聯絡,並且要顯示的釋放。
3.當一個DOMDocumentType被插入一個DOMDocument後,這個DOMDocumentType也因此有了一個宿主(owner),當它的宿主(owner document)被釋放後它也會被自動釋放,此時如果釋放這個節點時會產生一個DOMException::INVALID_ACCESS_ERR 異常。
使用DOMDocument::createXXX建立對象
使用者應該調用release()函數去顯示釋放任何一個孤立的節點。當一個孤立節點被釋放後,與其相關聯的子節點也將被釋放。訪問一個被釋放的節點將導致異常行為。那些孤立的節點最終將會釋放,如果現在還沒有釋放,那麼在他們的宿主(owner document)被釋放時他們就會被釋放。
試圖釋放一個有父親的節點將會導致一個DOMException::INVALID_ACCESS_ERR異常。
使用DOMDocumentRange::createRange或者DOMDocumentTraversal::createXXX建立對象
當DOMRange, DOMNodeIterator, DOMTreeWalker使用完畢後,使用者應該調用release()函數。訪問一個被釋放的對象將導致異常行為。那些對象最終將會釋放,如果現在還沒有釋放,那麼在他們的宿主(owner document)被釋放時他們就會被釋放。
如下有一個例子:
//
// Create a small document tree
//
{
XMLCh tempStr[100];
XMLString::transcode("Range", tempStr, 99);
DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(tempStr, 0);
XMLString::transcode("root", tempStr, 99);
DOMDocument* doc = impl->createDocument(0, tempStr, 0);
DOMElement* root = doc->getDocumentElement();
XMLString::transcode("FirstElement", tempStr, 99);
DOMElement* e1 = doc->createElement(tempStr);
root->appendChild(e1);
XMLString::transcode("SecondElement", tempStr, 99);
DOMElement* e2 = doc->createElement(tempStr);
root->appendChild(e2);
XMLString::transcode("aTextNode", tempStr, 99);
DOMText* textNode = doc->createTextNode(tempStr);
e1->appendChild(textNode);
//optionally, call release() to release the resource associated with the range after done
DOMRange* range = doc->createRange();
range->release();
//removedElement is an orphaned node, optionally call release() to release associated resource
DOMElement* removedElement = root->removeChild(e2);
removedElement->release();
// no need to release this returned object which is owned by implementation
XMLString::transcode("*", tempStr, 99);
DOMNodeList* nodeList = doc->getElementsByTagName(tempStr);
// done with the document, must call release() to release the entire document resources
doc->release();
};
字串型別
C++ DOM使用普通的的無結尾標誌的(XMLCh *)UTF-16字串作為字串型別,這些(XMLCh*) utf-16 型別的字串開銷極低。
//C++ DOM
const XMLCh* nodeValue = aNode->getNodeValue();
所有的字串資料都將會儲存在記憶體中直到文檔對象被銷毀。但是像這些字串資料在執行過程中必要時有可能會被迴圈利用(RECYCLED),使用者應該使用合適的返回字串副本作為型別安全的引用.
例如當一個DOMNode被釋放後,為其分配的記憶體資源將會被迴圈在利用。
XMLCh xfoo[] = {chLatin_f, chLatin_o, chLatin_o, chNull};
// pAttr has node value = "foo"
// fNodeValue has "foo"
pAttr->setNodeValue(xfoo);
const XMLCh* fNodeValue = pAttr->getNodeValue();
// fNodeValue has "foo"
// make a copy of the string for future reference
XMLCh* oldNodeValue = XMLString::replicate(fNodeValue);
// release the node pAttr
pAttr->release()
// other operations
// implementation may have recycled the memory of the pAttr already
// so it's not safe to expect fNodeValue still have "foo"
if (XMLString::compareString(xfoo, fNodeValue))
printf("fNodeValue has some other content/n");
// should use your own safe copy
if (!XMLString::compareString(xfoo, oldNodeValue))
printf("Use your own copy of the oldNodeValue if want to reference the string later/n");
// delete your own replicated string when done
XMLString::release(&oldNodeValue);
如果調用DOMNode::setNodeValue() 去設定一個新節點值,執行時僅僅是簡單的重寫節點值所佔用的記憶體地區,因此先前的指標現在就會自動的指向新的值。使用者應該使用合適的先前所返回的字串副本作為型別安全的引用.例如:
XMLCh xfoo[] = {chLatin_f, chLatin_o, chLatin_o, chNull};
XMLCh xfee[] = {chLatin_f, chLatin_e, chLatin_e, chNull};
// pAttr has node value = "foo"
pAttr->setNodeValue(xfoo);
const XMLCh* fNodeValue = pAttr->getNodeValue();
// fNodeValue has "foo"
// make a copy of the string for future reference
XMLCh* oldNodeValue = XMLString::replicate(fNodeValue);
// now set pAttr with a new node value "fee"
pAttr->setNodeValue(xfee);
// should not rely on fNodeValue for the old node value, it may not compare
if (XMLString::compareString(xfoo, fNodeValue))
printf("Should not rely on fNodeValue for the old node value/n");
// should use your own safe copy
if (!XMLString::compareString(xfoo, oldNodeValue))
printf("Use your own copy of the oldNodeValue if want to reference the string later/n");
// delete your own replicated string when done
XMLString::release(&oldNodeValue);
這樣做是當我們成百上千次調用DOMNode::setNodeValue()時防止記憶體消耗成等比級數的增長。這一設計容許使用者主動的選擇返回的字串應該手動的讓它留在記憶體中還是將這個字串拷貝到應用程式自己的堆棧中。(這句原文是This design allows users to actively select which returned string should stay in memory by manually copying the string to application's own heap.有些疑問,疑譯文是我自己的理解)。