日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

vba xml 怎么设置父节点_熊二做了一个xml报文处理的开源库easyxml

發布時間:2023/12/10 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vba xml 怎么设置父节点_熊二做了一个xml报文处理的开源库easyxml 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?

自信、冷靜、專注。—— TM 熊的自我勉勵

?

1. 前言

熊二從去年開始,因項目需求接觸到xml報文的處理,也是我第一次學習用C/C++的方式處理基于DOM模型的xml報文。因為本人比較懶hhh,所以第一反應就是去看看網上有沒有什么大家都在用的比較好的xml處理開源庫,站在前輩的肩膀上才能看的更遠嘛。

2. 我找到了哪些庫

庫名稱實現語言源碼地址基于模型
Tinyxml2C++https://github.com/leethomason/tinyxml2DOM
libxml2Chttp://xmlsoft.org/sources/win32/libxml2-2.7.8.win32.zipDOM
CMarkupC++http://www.firstobject.com/Markup115.zipDOM
Mini-XMLChttp://www.msweet.org/files/project3/mxml-2.9.tar.gzDOM/SAX
Expat-XMLChttps://github.com/libexpat/libexpat/SAX
XercesC++/Java/Perlhttp://xerces.apache.org/mirrors.cgiDOM/SAX
  • SAX(Simple API for XML)是基于事件的,其基本工作流程是分析XML文檔,當發現了一個新的元素時,產生一個對應事件,并調用相應的用戶處理函數。這種方式占用內存少,速度快,但用戶程序相應地會比較復雜。
  • DOM(Document Object Model)是在分析時,一次性地將整個XML文檔進行分析,并在內存中形成對應的樹結構,同時,向用戶提供一系列的接口來訪問和編輯該樹結構。這種方式占用內存大,速度往往慢于SAX,但可以給用戶提供一個面向對象的訪問接口,對用戶更為友好。
?

最后我選擇了tinyxml2這個庫作為項目使用,但關于這個庫,網上的資料看了很多總覺得不算太理想。于是我嘗試僅從使用者地角度去看看這個庫有沒有可能再封裝一次,使其處理xml報文變得更簡單?

?

3. 我用到了tinyxml庫的哪些功能

  • 3.1. 根據 DOM模型,XML 文檔中的每個成分都是一個節點。整個文檔是一個文檔節點,每一個xml元素是一個元素節點,而包含在xml元素中的文本是一個文本節點,每一個xml屬性是一個屬性節點,總之,基于DOM模型,xml文檔皆為節點。tinyxml2正好利用了這一特性,以節點的概念來設計處理函數。
  • 3.2. ?xml報文的處理在廣義上來說,無非“增”、“刪”、“改”、“查”四部分,我在處理xml報文時,用的最多的就是“增”、“查”,即協議交互中報文的組裝和解析。通過將近半年的使用體驗,不得不說,真的很感謝tinyxml2的作者Lee Thomason先生,能創作出這個好用的庫并開源。接下來我會展示tinyxml組裝和解析的步驟,并嘗試優化我覺得不合理的地方。

4. xml報文的組裝

比如我們要組裝這樣一段xml報文

<?xml version="1.0" encoding="UTF-8"?>
"south-bear">
0.0.0.0
8888
bear-2

這是用tinyxml2的基本接口組裝報文的方法

XMLDocument xmlDoc;
XMLNode* parent = NULL;
XMLElement *child[16] = { NULL };

parent->InsertEndChild( xmlDoc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\""));
child[1]=xmlDoc.NewElement("param"); //創建一個名為param的節點
child[1]->SetAttribute("name","south-bear"); //設置該節點屬性
parent->InsertEndChild(child[1]); //將該節點加入到parent節點下

child[2]=xmlDoc.NewElement("ipAddress"); //創建一個名為ipAddress的節點
child[2]->SetText("0.0.0.0"); //設置該節點內容
child[1]->InsertEndChild(child[2]); //將該節點加入到param節點下

child[2]=xmlDoc.NewElement("portNo"); //創建一個名為portNo的節點
child[2]->SetText(8888); //設置該節點內容
child[1]->InsertEndChild(child[2]); //將該節點加入到param節點下

child[2]=xmlDoc.NewElement("channel"); //創建一個名為channel的節點
child[1]->InsertEndChild(child[2]); //將該節點加入到param節點下

child[3]=xmlDoc.NewElement("Name"); //創建一個名為Name的節點
child[3]->SetText("bear-2"); //設置該節點內容
child[2]->InsertEndChild(child[3]); //將該節點加入到channel節點下

怎么樣?第一眼看上去是不是有點懵?感覺很不好記?如果是就對了,我當時第一反應也是這樣。tinyxml2庫在插入元素節點時都會用到NewElement和InsertEndChild等接口,但是每插入一個節點后,想在該節點下插入下一級節點就很容易將節點搞混淆,就是說,你在使用tinyxml2庫這個接口時,必須將每一個插入的節點記下,否者可能導致組裝的xml報文就是混亂的,另外從篇幅上來看重復的代碼還是占太多了。

于是我開始設想,有沒有這樣一種庫,我只需要傳入每一級節點的相關參數,就能自動組裝xml報文,下面是我設想的組裝xml的代碼。

XMLDocument xmlDoc;
XMLNode* parent = NULL;
XMLElement *child[16] = { NULL };

child[1]=xmlAddNode(xmlDoc, parent, "param");//創建一個名為param的節點,將該節點加入到parent節點下
xmlSetNodeAttr(child[1], "name", "south-bear");//設置該節點屬性

xmlAddNode(xmlDoc,child[1], "ipAddress", "0.0.0.0");//在param節點下添加ipAddress節點
xmlAddNode(xmlDoc,child[1], "portNo", 8888);//在param節點下添加portNo節點

child[2]=xmlAddNode(xmlDoc, child[1], "channel");//在param節點下添加channel節點
xmlAddNode(xmlDoc, child[2], "Name", "bear-2");//在channel節點下添加Name節點

xmlAddNode和xmlSetNodeAttr接口是我在tinyxml2庫的基礎上封裝的庫。

?

對于xmlAddNode接口,你需要傳入

?
  • xml文檔對象
  • 想要創建的節點的父節點
  • 節點名稱
  • 該節點的文本內容(可選)
?

對于xmlSetNodeAttr接口,你需要傳入

?
  • 需要設置屬性的節點
  • 屬性名稱
  • 屬性內容 是不是容易理解多了,而且光看child數組元素的下標就能知道當前處在哪一級。操作起來也更方便

5. xml報文的解析

這是用tinyxml2的基本接口解析上述報文的方法

XMLDocument xmlDoc;
XMLElement *pXmlRoot = NULL;
XMLElement *pXmlTra = NULL;
char name[32] = {0};
char ipAddress[32] = {0};
int port = 0;

if(0 == xmlDoc.Parse((const char *)xmlBuf))
{
pXmlRoot = xmlDoc.RootElement();
pXmlTra = pXmlRoot->FirstChildElement("ipAddress");
if (pXmlTra != NULL)
{
strncpy(ipAddress, (pXmlTra->GetText()), (sizeof(ipAddress)-1));
}

pXmlTra = pXmlRoot->FirstChildElement("portNo");
if (pXmlTra != NULL)
{
sscanf(pXmlTra->GetText(), "%d", &port);
}

pXmlTra = pXmlRoot->FirstChildElement("channel");
pXmlTra = pXmlTra->FirstChildElement("Name");
if (pXmlTra != NULL)
{
strncpy(name, (pXmlTra->GetText()), (sizeof(name)-1));
}
}

emmmm....看上去還是很繁瑣,能不能變得簡潔點?下面是我設想的解析xml報文的代碼,

XMLDocument xmlDoc;
XMLElement *pXmlRoot = NULL;
XMLElement *pXmlTra = NULL;
char name[32] = {0};
char ipAddress[32] = {0};
int port = 0;

if(0 == xmlDoc.Parse((const char *)xmlBuf))
{
pXmlRoot = xmlDoc.RootElement();

xmlGetNodeAttr(pXmlRoot, "name", name, sizeof(name));
xmlGetChildNode(pXmlRoot, "ipAddress", ipAddress, sizeof(ipAddress));
xmlGetChildNode(pXmlRoot, "portNo", &port);
xmlGetChildNode(pXmlRoot->FirstChildElement("channel"),"Name", channelName, sizeof(channelName));
}

xmlGetNodeAttr和xmlGetChildNode接口是我在tinyxml2庫的基礎上封裝的庫。

?

對于xmlGetNodeAttr接口,你需要傳入

?
  • 節點指針
  • 屬性名稱
  • 存放屬性內容的緩沖區
?

對于xmlGetChildNode接口,你需要傳入

?
  • 父節點
  • 想要獲取的節點名稱
  • 存放該節點內容的緩沖區

6.easyxml庫

根據上面的設想,我基于tinyxml2庫開發了easyxml庫,這是源碼目錄樹

├── demo
│?? ├── create.cpp
│?? ├── parser.cpp
│?? └── test.xml
├── src
│?? ├── easyxml.cpp
│?? ├── easyxml.hpp
│?? └── xml_cofig.h
└── third
├── tinyxml2.cpp
└── tinyxml2.h

目錄樹包含了依賴的tinyxml2源碼和使用demo, 在src目錄下的即為easyxml庫的源碼,easyxml庫的接口有兩個實現版本,用C++函數和宏來實現,兩種版本各有優缺點,在使用中我們按照需求場景來選擇。「C++函數接口」

  • 優點:利用c++函數的可重載性,解析各種類型的字段時,接口名稱可以不變。
  • 缺點:因為是函數接口,存在實參轉形參的過程。比如當獲取字符串類型的字段時,為防止溢出,我們需要傳入緩沖區的長度,這樣一來函數的入參就要增加一個,觀感上就會不整潔。

「宏接口」

  • 優點:因不存在存在實參轉形參的過程,完美解決了C++函數接口的缺點,觀感整潔。
  • 缺點:因宏不具備可重載性,所以解析各種類型的字段時,就要設計該種類型對應的宏接口
?

如上面目錄所示,easyxml.hpp存放的是C++函數接口,xml_cofig.h存放的是宏接口 總結:如果是對于少量代碼的工程,上面兩種版本的選擇沒有太大的差別,但對于大量代碼的工程,推薦選擇宏接口。

?

「easyxml庫的開源地址」https://github.com/southbear-club/easyxml

?

其中包含的接口當然不止上面示例代碼中的這些庫啦,當然一些更原子的操作還是要用tinyxnl2的基本接口的,不過easyxml庫已經能幫你解決大部分的xml報文處理的需求了,這個庫后續我會持續維護更新,以使得其能應用于更多的場景。歡迎star喲~

?

7. 關于tinyxml2

「傳送門」如果在這之前,你還不太了解xml報文的基礎知識,可以訪問下面的鏈接惡補惡補。

?

https://www.runoob.com/dom/dom-intro.html

?

tinyxml2庫的接口使用說明

?

http://leethomason.github.io/tinyxml2/annotated.html

?

「我遇到了哪些坑」

  • XMLDocument類中的Parse函數,可以選擇傳入"len"參數,即要解析的字節數。如果未指定,TinyXML-2將假定'xml'指向以NULL終止的字符串。
  • XMLPrinter類中的CStrSize()函數用以獲取xml報文的總長度,但返回值長度包含終止符null,所以用CStrSize()函數獲取xml的長度比實際值多1。
  • 如果你希望生成的xml報文是不帶格式對齊的,那只需要在定義XMLPrinter類的對象時指定compact值為true即可,例如:?

    XMLPrinter printer(0,true,0);

    ?

暫時就想到了這些坑,真是一把心酸淚,希望你們不要再去踩這些坑了。

8.嘮嘮叨叨

最近杭州突然變得好冷啊,大家記得添衣服別感冒呀,感冒了干啥都不開心。好啦,以上就是本期的全部內容,學習不是為了變得全知全能,而是為了不再害怕未知,我是熊二,我們下期再見。

推薦閱讀:

從cmockery入門C語言單元測試

你的github開源項目還沒做持續集成么?趕緊看看這個

還在為查內存泄漏問題痛苦不堪?試試這個神器

?????????????????????????? ? ? ??

????????????????????????????????????

總結

以上是生活随笔為你收集整理的vba xml 怎么设置父节点_熊二做了一个xml报文处理的开源库easyxml的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。