参考:http://www.cnblogs.com/hgwang/p/5833638.html
TinyXML用法小结
1. 介绍
Tinyxml的官方网址:http://www.grinninglizard.com
官方介绍文档:http://www.grinninglizard.com/tinyxmldocs/tutorial0.html
在TinyXML中,根据XML的各种元素来定义了一些类:
TiXmlBase:整个TinyXML模型的基类。
TiXmlAttribute:对应于XML中的元素的属性。
TiXmlNode:对应于DOM结构中的节点。
TiXmlComment:对应于XML中的注释
TiXmlDeclaration:对应于XML中的申明部分,即<?versiong="1.0" ?>。
TiXmlDocument:对应于XML的整个文档。
TiXmlElement:对应于XML的元素。
TiXmlText:对应于XML的文字部分
TiXmlUnknown:对应于XML的未知部分。
TiXmlHandler:定义了针对XML的一些操作。
根据下图来说明常用的类对应的文本格式:
<?xml version="1.0" ?> //TiXmlDeclaration,声明
<MyApp> //TiXmlElement,元素
<!-- Settings for MyApp -->//TiXmlComment,注释
<Messages>//TiXmlElement,元素
<Welcome>Welcome to MyApp</Welcome>
//<Welcome>是元素TiXmlElement ,“Welcome to MyApp”是TiXmlText,文本
<Farewell>Thank you for using MyApp</Farewell>//同上
</Messages>
<Windows>//TiXmlElement,元素
<Window name="MainFrame" x="5" y="15" w="400" h="250" />
// Window是元素TiXmlElement ,name、x、y、h是TiXmlAttribute
</Windows>
<Connection ip="192.168.0.1" timeout="123.456000" />
</MyApp>
TinyXML是个解析库,主要由DOM模型类(TiXmlBase、TiXmlNode、TiXmlAttribute、TiXmlComment、TiXmlDeclaration、TiXmlElement、TiXmlText、TiXmlUnknown)和操作类(TiXmlHandler)构成。它由两个头文件(.h文件)和四个CPP文件(.cpp文件)构成,用的时候,只要将(tinyxml.h、tinystr.h、tinystr.cpp、tinyxml.cpp、tinyxmlerror.cpp、tinyxmlparser.cpp)导入工程就可以用它的东西了。如果需要,可以将它做成自己的DLL来调用。
注意,TiXmlBase 是TiXmlNode的基类,TiXmlNode是TiXmlElement、TiXmlComment、TiXmlText、TiXmlDeclaration、TiXmlUnknown、TiXmlDocument的基类。
2. TinyXML配置
在stdafx.h头文件中增加头文件引用#include "tinyxml/tinyxml.h"
在工程设置中加入lib引用库
在stdafx.h中加入动态库引用
#ifdef _DEBUG
#pragma comment(lib,"TinyXMLD.lib")
#else
#pragma comment(lib,"TinyXML.lib")
#endif
3. TinyXML读取和保存文件
3.1 读取xml文件
TiXmlDocument lconfigXML;
if( !lconfigXML.LoadFile( strXmlFile.c_str() ) )
{
break;
}
3.2 读取xml参数
TiXmlDocument lActionXML;
lActionXML.Parse(strRmcpParam.c_str());
if(lActionXML.Error())
{
strErr = "输入参数不是标准的xml格式";
return false;
}
3.3 保存xml参数到文本
TiXmlDocument tyDoc;
…
tyDoc.SaveFile(m_strFilePath);
3.4 保存xml参数到临时变量
TiXmlDocument tyDoc;
…
TiXmlPrinter printer;
tyDoc.Accept(&printer);
std::string devParam = std::string(printer.CStr());
4. TinyXML增删改查
4.1 增
创建一个如1中的xml文件代码
void write_app_settings_doc( )
{
TiXmlDocument doc;
TiXmlElement* msg;
TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" );
doc.LinkEndChild( decl );
TiXmlElement * root = new TiXmlElement( "MyApp" );
doc.LinkEndChild( root );
TiXmlComment * comment = new TiXmlComment();
comment->SetValue(" Settings for MyApp " );
root->LinkEndChild( comment );
TiXmlElement * msgs = new TiXmlElement( "Messages" );
root->LinkEndChild( msgs );
msg = new TiXmlElement( "Welcome" );
msg->LinkEndChild( new TiXmlText( "Welcome to MyApp" ));
msgs->LinkEndChild( msg );
msg = new TiXmlElement( "Farewell" );
msg->LinkEndChild( new TiXmlText( "Thank you for using MyApp" ));
msgs->LinkEndChild( msg );
TiXmlElement * windows = new TiXmlElement( "Windows" );
root->LinkEndChild( windows );
TiXmlElement * window;
window = new TiXmlElement( "Window" );
windows->LinkEndChild( window );
window->SetAttribute("name", "MainFrame");
window->SetAttribute("x", 5);
window->SetAttribute("y", 15);
window->SetAttribute("w", 400);
window->SetAttribute("h", 250);
TiXmlElement * cxn = new TiXmlElement( "Connection" );
root->LinkEndChild( cxn );
cxn->SetAttribute("ip", "192.168.0.1");
cxn->SetDoubleAttribute("timeout", 123.456); // floating point attrib
dump_to_stdout( &doc );
doc.SaveFile( "appsettings.xml" );
}
在节点最后插入新节点
TiXmlNode* LinkEndChild( TiXmlNode* addThis );
在节点后 前/后 插入新节点
TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis );
4.2 删
删除某个节点, TiXmlNode是TiXmlElement、TiXmlComment、TiXmlText、TiXmlDeclaration、TiXmlUnknown、TiXmlDocument的基类
TiXmlNode node;
node.Clear();
从A节点上移除子节点B
TiXmlNode nodeA;
nodeA. RemoveChild( TiXmlNode* removeThis );
从元素A上移除名字为B的属性
TiXmlAttribute attrA;
attrA. RemoveAttribute( const char * name );
4.3 改
查找内容为<mfid val="1234" />,现需要将1234改成其他值
TiXmlNode* lpnode = NULL;
lpnode = tixml.RootElement()->IterateChildren("mfid",lpnode);
TiXmlAttribute* tiattr = lpnode->ToElement()->FirstAttribute();
//找到mfid节点,获取第一个属性值。注意,如果有多个属性值,需要判断哪个属性值是需要的
tiattr->SetValue(mfid.c_str());
替换一个节点
TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
4.4 查
获取link节点
const TiXmlNode* lpItemNode = NULL;//初始化
lpItemNode = lconfigXML.RootElement()->IterateChildren("link", lpItemNode);
if (lpItemNode == NULL)
{
//Can not find <link>break;
}
获取link节点中的type属性值
std::string strType = lpItemNode->ToElement()->Attribute("type");
遍历节点
const TiXmlNode* lpMapNode = NULL; //初始化
lpMapNode = lconfigXML.RootElement()->IterateChildren("node", lpMapNode);
if (lpMapNode)
{
rms::CStationMapping litem;
const TiXmlNode* lpItemNode = NULL ;
while(lpItemNode = lpMapNode->IterateChildren("item",lpItemNode))
{
string str = lpItemNode->ToElement()->Attribute("ABC");
}
}
遍历元素属性
TiXmlAttribute* pAttr = NULL;
for (pAttr = pNode->FirstAttribute(); pAttr; pAttr = pAttr->Next())
{
…
}
节点的下一个兄弟节点
const TiXmlNode* NextSibling() const;
元素的下一个元素
const TiXmlElement* NextSiblingElement() const;
属性的下一个属性
const TiXmlAttribute* Next() const;
返回值为NULL表示不存在
5. TinyXml常用操作封装
使用TinyXml的时候,经常会遇到两个问题:
1:TinyXml不检查输入参数,如果参数输入不当,会偶发异常。且该异常不易捕捉。
2:处理较大规模xml的时候,类似IterateChildren等的语句会出现很多行,重复代码量很大。 为解决以上两个问题,我对TinyXml进行简单封装。对于问题1,定义了几种处理状态,当参数不当或其他问题发生时,会返回对应的错误代码。用GetStatus可解析出该异常。
1 //tinyxml 宏
2 //N:Node,C:Child node,Cn:Child node's name,An:Attribute name,V:Value(string类型)
3 //D:tixmldocument,P:tixmlprinter,p:param,Pre:previous
4 #ifndef TNXML_COMMON
5 #define TNXML_COMMON
6
7 #define TNXML_XML_PARAM -2
8 #define TNXML_XML_FILE -1
9
10 #define TNXML_OK 0
11 #define TNXML_NOT_FIND_NODE 1
12 #define TNXML_NOT_FIND_ATTR 2
13 #define TNXML_PARAM_NODE_NULL 3
14 #define TNXML_PARAM_STR_NULL 4
15 #define TNXML_PARAM_NOT_XML 5
16 #define TNXML_OTHER_ERROR 9
17
18 class CTNXML
19 {
20 public:
21 //查找节点N下子节点Cn(Pre节点后),用output返回
22 static int CN(TiXmlNode* N,std::string Cn,TiXmlNode* Pre,TiXmlNode*& output)
23 {
24 if (N == NULL)
25 {
26 return TNXML_PARAM_NODE_NULL;
27 }
28 if (Cn.empty())
29 {
30 return TNXML_PARAM_STR_NULL;
31 }
32 TiXmlNode* node = N->IterateChildren(Cn.c_str(),Pre);
33 if (node)
34 {
35 output = node;
36 return TNXML_OK;
37 }
38 else
39 {
40
41 return TNXML_NOT_FIND_NODE;
42 }
43 }
44
45 //查找节点N下属性An的值,用output返回
46 static int ELE_ATTR_VAL(TiXmlNode* N,std::string An,std::string& output)
47 {
48 if (N == NULL)
49 {
50 return TNXML_PARAM_NODE_NULL;
51 }
52 else if (An.empty())
53 {
54 return TNXML_PARAM_STR_NULL;
55 }
56 if (N->ToElement()->Attribute(An.c_str()) == NULL)
57 {
58 return TNXML_NOT_FIND_ATTR;
59 }
60 else
61 {
62 output = N->ToElement()->Attribute(An.c_str());
63 return TNXML_OK;
64 }
65 }
66
67 //查找节点N下子节点Cn(Pre节点后),用output返回Cn下属性An的值
68 static int ITER_ELE_ATTR_VAL(TiXmlNode* N,std::string Cn,TiXmlNode* Pre,std::string An,std::string& output)
69 {
70 TiXmlNode* node = NULL;
71 int res = CN(N,Cn,Pre,node);
72 if ( res == TNXML_OK)
73 {
74 std::string str;
75 res = ELE_ATTR_VAL(node,An,str);
76 if (res == TNXML_OK)
77 {
78 output = str;
79 return TNXML_OK;
80 }
81 else
82 {
83 return res;
84 }
85 }
86 else
87 {
88 return res;
89 }
90 }
91
92 //设置节点N下属性An的值为V
93 static int ELE_SET_ATTR(TiXmlNode* N,std::string An,std::string V)
94 {
95 if (N == NULL)
96 {
97 return TNXML_PARAM_NODE_NULL;
98 }
99 else if (An.empty())
100 {
101 return TNXML_PARAM_STR_NULL;
102 }
103 else
104 {
105 N->ToElement()->SetAttribute(An.c_str(),V.c_str());
106 return TNXML_OK;
107 }
108 }
109
110 //设置节点N下子节点Cn(Pre后)属性An的值为V
111 static int ITER_ELE_SET_ATTR_VAL(TiXmlNode* N,std::string Cn,TiXmlNode* Pre,std::string An,std::string V)
112 {
113 TiXmlNode* node = NULL;
114 int res = CN(N,Cn,Pre,node);
115 if ( res == TNXML_OK)
116 {
117 res = ELE_SET_ATTR(node,An,V);
118 return res;
119 }
120 else
121 {
122 return res;
123 }
124 }
125
126 //读取xml参数(字符串),返回根节点
127 static int PARAM_TO_ROOTELE(std::string& str,TiXmlElement* output)
128 {
129 if (str.empty())
130 {
131 return TNXML_PARAM_STR_NULL;
132 }
133 TiXmlDocument* D = new TiXmlDocument;
134 if (D->Parse(str.c_str()))
135 {
136 output = D->RootElement();
137 if (output)
138 {
139 return TNXML_OK;
140 }
141 else
142 {
143 return TNXML_PARAM_NOT_XML;
144 }
145 }
146 else
147 {
148 return TNXML_PARAM_NOT_XML;
149 }
150 }
151
152 //读取xml参数(文件地址),返回根节点
153 static int DOC_TO_ROOTELE(std::string& str,TiXmlElement* output)
154 {
155 if (str.empty())
156 {
157 return TNXML_PARAM_STR_NULL;
158 }
159 TiXmlDocument* D = new TiXmlDocument;
160 if (D->LoadFile(str.c_str()))
161 {
162 output = D->RootElement();
163 if (output)
164 {
165 return TNXML_OK;
166 }
167 else
168 {
169 return TNXML_PARAM_NOT_XML;
170 }
171 }
172 else
173 {
174 return TNXML_PARAM_NOT_XML;
175 }
176 }
177
178 //N尾部插入名为Cn的新节点,属性名值An,值V
179 static int LinkNewNodeWithAttr(TiXmlNode* N,std::string Cn,std::string An,std::string V,TiXmlElement*& C)
180 {
181 if (N == NULL)
182 {
183 return TNXML_PARAM_NODE_NULL;
184 }
185 if (Cn.empty() || An.empty())
186 {
187 return TNXML_PARAM_STR_NULL;
188 }
189 TiXmlElement* ele = new TiXmlElement(Cn);
190 ele->SetAttribute(An,V);
191 N->LinkEndChild(ele);
192
193 C = ele;
194 return TNXML_OK;
195 }
196
197 //保存TiXmlDocument文档为字符串
198 static int Doc_To_String(TiXmlDocument& D,std::string& output)
199 {
200 TiXmlPrinter t_printer;
201 if (D.Accept(&t_printer))
202 {
203 output = std::string(t_printer.CStr());
204 return TNXML_OK;
205 }
206 else
207 {
208 return TNXML_OTHER_ERROR;
209 }
210 };
211
212 //保存TiXmlElement文档为字符串
213 static int Ele_To_String(TiXmlElement* N,std::string& output)
214 {
215 if (N==NULL)
216 {
217 return TNXML_PARAM_NODE_NULL;
218 }
219 TiXmlNode* ele = N->Clone();
220 if (ele)
221 {
222 TiXmlDocument doc;
223 doc.LinkEndChild(ele);
224 return Doc_To_String(doc,output);
225 }
226 else
227 {
228 return TNXML_OTHER_ERROR;
229 }
230 };
231
232 //保存ele至本地文件
233 static int Ele_To_File(TiXmlElement* N,std::string filepath)
234 {
235 if (N==NULL)
236 {
237 return TNXML_PARAM_NODE_NULL;
238 }
239 TiXmlNode* ele = N->Clone();
240 TiXmlDocument doc;
241 doc.LinkEndChild(ele);
242 doc.SaveFile(filepath.c_str());
243 return TNXML_OK;
244 };
245
246
247 //将字符串转成小写
248 static void Xml_To_Lower(std::string& param)
249 {
250 std::transform(param.begin(), param.end(), param.begin(), std::tolower);
251 }
252
253 //解析以上函数反馈信息
254 static std::string GetStatus(int index)
255 {
256 switch (index)
257 {
258 case TNXML_OK:
259 {
260 return std::string("OK");
261 }
262 case TNXML_NOT_FIND_NODE:
263 {
264 return std::string("Cannot find node");
265 }
266 break;
267 case TNXML_NOT_FIND_ATTR:
268 {
269 return std::string("Cannot find attribute");
270 }
271 break;
272 case TNXML_PARAM_NODE_NULL:
273 {
274 return std::string("Input param node is NULL");
275 }
276 break;
277 case TNXML_PARAM_STR_NULL:
278 {
279 return std::string("Input param string is NULL");
280 }
281 break;
282 case TNXML_PARAM_NOT_XML:
283 {
284 return std::string("Input param string is not XML");
285 }
286 break;
287 case TNXML_OTHER_ERROR:
288 {
289 return std::string("Other errors");
290 }
291 break;
292 default:
293 {
294 return std::string("Unknown");
295 }
296 break;
297 }
298 }
299 };
300
301 #endif
以上是我目前经常用到的处理语句,以后会逐步扩展其他操作语句。
6. 一个完整例子
void AppSettings::load(const char* pFilename)
{
TiXmlDocument doc(pFilename);
if (!doc.LoadFile()) return; TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlHandle hRoot(0); // block: name
{
pElem=hDoc.FirstChildElement().Element();
// should always have a valid root but handle gracefully if it does
if (!pElem) return;
m_name=pElem->Value(); // save this for later
hRoot=TiXmlHandle(pElem);
} // block: string table
{
m_messages.clear(); // trash existing table pElem=hRoot.FirstChild( "Messages" ).FirstChild().Element();
for( pElem; pElem; pElem=pElem->NextSiblingElement())
{
const char *pKey=pElem->Value();
const char *pText=pElem->GetText();
if (pKey && pText)
{
m_messages[pKey]=pText;
}
}
} // block: windows
{
m_windows.clear(); // trash existing list TiXmlElement* pWindowNode=hRoot.FirstChild( "Windows" ).FirstChild().Element();
for( pWindowNode; pWindowNode; pWindowNode=pWindowNode->NextSiblingElement())
{
WindowSettings w;
const char *pName=pWindowNode->Attribute("name");
if (pName) w.name=pName; pWindowNode->QueryIntAttribute("x", &w.x); // If this fails, original value is left as-is
pWindowNode->QueryIntAttribute("y", &w.y);
pWindowNode->QueryIntAttribute("w", &w.w);
pWindowNode->QueryIntAttribute("hh", &w.h); m_windows.push_back(w);
}
} // block: connection
{
pElem=hRoot.FirstChild("Connection").Element();
if (pElem)
{
m_connection.ip=pElem->Attribute("ip");
pElem->QueryDoubleAttribute("timeout",&m_connection.timeout);
}
}
}