TinyXML是一个非常小巧简单的XML解析库,采用DOM方式来解析XML文件。不足的是它本身不支持DTD和XSL,但普通简单的XML使用需求还是可以满足了。
TinyXML由2个头文件四个CPP文件构成。继承结构如下:
要操作XML首先需要加载XML,很简单:
- TiXmlDocumentdoc("demo.xml");
- doc.LoadFile();
一个更加真实的用例如下所示,加载一个XML文件然后显示内容到标准输出上。
//loadthenamedfileanddumpitsstructuretoSTDOUT
voiddump_to_stdout(constchar*pFilename)
{
TiXmlDocumentdoc(pFilename);
boolloadOkay=doc.LoadFile();
if(loadOkay)
printf("\n%s:\n",pFilename);
dump_to_stdout(&doc);//definedlater
写个简单的Main函数
intmain(void)
{
dump_to_stdout("example1.xml");
return0;
读下面的文件
读下面的文件
<?xmlversion="1.0"?>
<Hello>World</Hello>
输出如下
DECLARATION
+ELEMENTHello
+TEXT[World]
dump_to_stdout递归遍历输出所有的XML内容,详细实现在本文的末尾。
TinyXML同样可以简单的编程生成一个上面的XML:
voidbuild_simple_doc()
//Makexml:<?xml..><Hello>World</Hello>
TiXmlDocumentdoc;
TiXmlDeclaration*decl=newTiXmlDeclaration("1.0","","");
TiXmlElement*element=newTiXmlElement("Hello");
TiXmlText*text=newTiXmlText("World");
element->LinkEndChild(text);
doc.LinkEndChild(decl);
doc.LinkEndChild(element);
doc.SaveFile("madeByHand.xml");
}
与其等价的写法:
voidwrite_simple_doc2()
//sameaswrite_simple_doc1butaddeachnode
//asearlyaspossibleintothetree.
doc.LinkEndChild(decl);
doc.LinkEndChild(element);
doc.SaveFile("madeByHand2.xml");
给定一个节点,设置它的属性也很简单:
window=newTiXmlElement("Demo");
window->SetAttribute("name","Circle");
window->SetAttribute("x",5);
window->SetAttribute("y",15);
window->SetDoubleAttribute("radius",3.14159);
//printallattributesofpElement.
//returnsthenumberofattributesprinted
intdump_attribs_to_stdout(TiXmlElement*pElement,unsignedintindent)
if(!pElement)return0;
TiXmlAttribute*pAttrib=pElement->FirstAttribute();
inti=0;
intival;
doubledval;
constchar*pIndent=getIndent(indent);
printf("\n");
while(pAttrib)
printf("%s%s:value=[%s]",pIndent,pAttrib->Name(),pAttrib->Value());
if(pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS)printf("int=%d",ival);
if(pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS)printf("d=%1.1f",dval);
printf("\n");
i++;
pAttrib=pAttrib->Next();
}
returni;
我们经常通过配置文件来保存程序的一些配置信息。下面给一个实例来用XML加载和保存C++对象。
#include<string>
#include<map>
usingnamespacestd;
typedefstd::map<std::string,std::string>MessageMap;
//abasicwindowabstraction-demopurposesonly
classWindowSettings
public:
intx,y,w,h;
stringname;
WindowSettings()
:x(0),y(0),w(100),h(100),name("Untitled")
}
WindowSettings(intx,inty,intw,inth,conststring&name)
this->x=x;
this->y=y;
this->w=w;
this->h=h;
this->name=name;
};
classConnectionSettings
public:
stringip;
doubletimeout;
};
classAppSettings
stringm_name;
MessageMapm_messages;
list<WindowSettings>m_windows;
ConnectionSettingsm_connection;
AppSettings(){}
voidsave(constchar*pFilename);
voidload(constchar*pFilename);
//justtoshowhowtodoit
voidsetDemoValues()
m_name="MyApp";
m_messages.clear();
m_messages["Welcome"]="Welcometo"+m_name;
m_messages["Farewell"]="Thankyouforusing"+m_name;
m_windows.clear();
m_windows.push_back(WindowSettings(15,15,400,250,"Main"));
m_connection.ip="Unknown";
m_connection.timeout=123.456;
};
类AppSettings提供了保存和加载配置信息的函数save和load。如下代码表示利用缺省的配置保存和加载:
AppSettingssettings;
settings.save("appsettings2.xml");
settings.load("appsettings2.xml");
同样的我们可以运行时修改配置:
//block:customiseandsavesettings
settings.m_name="HitchHikerApp";
settings.m_messages["Welcome"]="Don'tPanic";
settings.m_messages["Farewell"]="Thanksforallthefish";
settings.m_windows.push_back(WindowSettings(15,25,300,"BookFrame"));
settings.m_connection.ip="192.168.0.77";
settings.m_connection.timeout=42.0;
//block:loadsettings
AppSettingssettings;
settings.load("appsettings2.xml");
printf("%s:%s\n",settings.m_name.c_str(),
settings.m_messages["Welcome"].c_str());
WindowSettings&w=settings.m_windows.front();
printf("%s:Showwindow'%s'at%d,%d(%dx%d)\n",
settings.m_name.c_str(),w.name.c_str(),w.x,w.y,w.w,w.h);
printf("%s:%s\n",settings.m_messages["Farewell"].c_str());
有很多方法可以保存对象的属性信息,也就是对象的状态信息。下面的实例展示如何将对象的状态编码进XML文件。
voidAppSettings::save(constchar*pFilename)
TiXmlDocumentdoc;
TiXmlElement*msg;
TiXmlComment*comment;
strings;
TiXmlElement*root=newTiXmlElement(m_name.c_str());
doc.LinkEndChild(root);
comment=newTiXmlComment();
s="Settingsfor"+m_name+"";
comment->SetValue(s.c_str());
root->LinkEndChild(comment);
//block:messages
MessageMap::iteratoriter;
TiXmlElement*msgs=newTiXmlElement("Messages");
root->LinkEndChild(msgs);
for(iter=m_messages.begin();iter!=m_messages.end();iter++)
conststring&key=(*iter).first;
conststring&value=(*iter).second;
msg=newTiXmlElement(key.c_str());
msg->LinkEndChild(newTiXmlText(value.c_str()));
msgs->LinkEndChild(msg);
//block:windows
TiXmlElement*windowsNode=newTiXmlElement("Windows");
root->LinkEndChild(windowsNode);
list<WindowSettings>::iteratoriter;
for(iter=m_windows.begin();iter!=m_windows.end();iter++)
constWindowSettings&w=*iter;
TiXmlElement*window;
window=newTiXmlElement("Window");
windowsNode->LinkEndChild(window);
window->SetAttribute("name",w.name.c_str());
window->SetAttribute("x",w.x);
window->SetAttribute("y",w.y);
window->SetAttribute("w",w.w);
window->SetAttribute("h",w.h);
//block:connection
TiXmlElement*cxn=newTiXmlElement("Connection");
root->LinkEndChild(cxn);
cxn->SetAttribute("ip",m_connection.ip.c_str());
cxn->SetDoubleAttribute("timeout",m_connection.timeout);
doc.SaveFile(pFilename);
下面的示例展示如何从XML文件中获得对象的状态信息:
voidAppSettings::load( TiXmlDocumentdoc(pFilename);
if (!doc.LoadFile())return;
TiXmlHandlehDoc(&doc);
TiXmlElement*pElem;
TiXmlHandlehRoot(0);
//block:name
pElem=hDoc.FirstChildElement().Element();
//shouldalwayshaveavalidrootbuthandlegracefullyifitdoes
if(!pElem) m_name=pElem->Value();
//savethisforlater
hRoot=TiXmlHandle(pElem);
//block:stringtable
m_messages.clear();//trashexistingtable
pElem=hRoot.FirstChild("Messages").FirstChild().Element();
for(pElem;pElem;pElem=pElem->NextSiblingElement())
constchar*pKey=pElem->Value();
constchar*pText=pElem->GetText();
if(pKey&&pText)
m_messages[pKey]=pText;
m_windows.clear();//trashexistinglist
TiXmlElement*pWindowNode=hRoot.FirstChild("Windows").FirstChild().Element();
for(pWindowNode;pWindowNode;pWindowNode=pWindowNode->NextSiblingElement())
WindowSettingsw;
constchar*pName=pWindowNode->Attribute("name");
if(pName)w.name=pName;
pWindowNode->QueryIntAttribute("x",&w.x);//Ifthisfails,originalvalueisleftas-is
pWindowNode->QueryIntAttribute("y",&w.y);
pWindowNode->QueryIntAttribute("w",&w.w);
pWindowNode->QueryIntAttribute("hh",&w.h);
m_windows.push_back(w);
pElem=hRoot.FirstChild("Connection").Element();
if(pElem)
m_connection.ip=pElem->Attribute("ip");
pElem->QueryDoubleAttribute("timeout",&m_connection.timeout);
函数dump_to_stdout如下:
#include"stdafx.h"
#include"tinyxml.h"
//----------------------------------------------------------------------
//STDOUTdumpandindentingutilityfunctions
constunsignedintNUM_INDENTS_PER_SPACE=2;
constchar*getIndent(unsignedintnumIndents)
staticconstchar*pINDENT="+";
constunsignedintLENGTH=strlen(pINDENT);
unsignedintn=numIndents*NUM_INDENTS_PER_SPACE;
if(n>LENGTH)n=LENGTH;
return&pINDENT[LENGTH-n];
//sameasgetIndentbutno"+"attheend
constchar*getIndentAlt(unsignedintnumIndents)
constchar*pINDENT="";
constunsignedintLENGTH=strlen(pINDENT);
unsignedintn=numIndents*NUM_INDENTS_PER_SPACE;
if(n>LENGTH)n=LENGTH;
return&pINDENT[LENGTH-n];
intdump_attribs_to_stdout(TiXmlElement*pElement,unsignedintindent)
TiXmlAttribute*pAttrib=pElement->FirstAttribute();
inti=0;
intival;
doubledval;
constchar*pIndent=getIndent(indent);
while(pAttrib)
printf("%s%s:value=[%s]",pAttrib->Value());
i++;
pAttrib=pAttrib->Next();
returni;
voiddump_to_stdout(TiXmlNode*pParent,unsignedintindent=0)
if(!pParent)return;
TiXmlNode*pChild;
TiXmlText*pText;
intt=pParent->Type();
printf("%s",getIndent(indent));
intnum;
switch(t)
caseTiXmlNode::TINYXML_DOCUMENT:
printf("Document");
break;
caseTiXmlNode::TINYXML_ELEMENT:
printf("Element[%s]",pParent->Value());
num=dump_attribs_to_stdout(pParent->ToElement(),indent+1);
switch(num)
case0:printf("(Noattributes)");break;
case1:printf("%s1attribute",getIndentAlt(indent));default:printf("%s%dattributes",getIndentAlt(indent),num);caseTiXmlNode::TINYXML_COMMENT:
printf("Comment:[%s]",pParent->Value());
caseTiXmlNode::TINYXML_UNKNOWN:
printf("Unknown");
caseTiXmlNode::TINYXML_TEXT:
pText=pParent->ToText();
printf("Text:[%s]",pText->Value());
caseTiXmlNode::TINYXML_DECLARATION:
printf("Declaration");
default:
for(pChild=pParent->FirstChild();pChild!=0;pChild=pChild->NextSibling())
dump_to_stdout(pChild,indent+1);
//loadthenamedfileanddumpitsstructuretoSTDOUT
boolloadOkay=doc.LoadFile();
if(loadOkay)
printf("\n%s:\n",pFilename);
dump_to_stdout(&doc);//definedlaterinthetutorial
如果你想在MFC中使用TinyXML,会出现这样的编译错误fatal error C1010: unexpected end of file while looking for precompiled header。因为预编译头文件通过编译stdafx.cpp生成,可以在4个实现CPP文件中引入头#include "stdafx.h"。记得放在最前面。这样就可以编译通过了。