Using MSXML to read/write XML files

In previous post, I talked about how to use Libxml2 library to read/write xml files. Actually, there are many Free C or C++ XML Parser Libraries. From now no, I will turn to MSXML instead because of Libxml2’s poor support for Windows-x64 systems.

In the followings, I will show how to use MSXML to read/write xml files.

Pre-work:

  • To install MSXML is quite easy, you just need to install Windows SDK, where it is integrated.
  • Add #import <msxml3.dll> to the beginning part of your code.
  • Use the following xml files as an example:

    1
    2
    3
    4
    5
    6
    <?xml version="1.0" encoding="UTF-8"?>
    <Appearance_model>
    <name>xxx</name>
    <Feature index="6" weight="0.017783"/>
    <Feature index="10" weight="0.003343"/>
    </Appearance_model>

Read from xml files:

For example, we want to load the above xml data to a vector<pair<int, float>> (name to a string), do like the following code, where input parameter gives the path of above xml file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
vector<pair<int, float>> load_appearance_model_from_xml(string file, string & name)
{
vector<pair<int, float>> app_model;

CoInitialize(NULL);

//read XML
MSXML2::IXMLDOMDocumentPtr spXMLDoc;
spXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30));
spXMLDoc->load(file.c_str());

MSXML2::IXMLDOMElementPtr spRoot = spXMLDoc->documentElement; //root node
if (spRoot->nodeName == (_bstr_t)"Appearance_model")
{
MSXML2::IXMLDOMNodeListPtr spNodeList = spRoot->childNodes;

// traverse child's nodes
for (long i = 0; i != spNodeList->length; ++i)
{
MSXML2::IXMLDOMNodePtr spNode = spNodeList->item[i];
if (spNode->nodeName == (_bstr_t)"name")
{
name = (char *) spNode->Gettext();
}
else if (spNode->nodeName == (_bstr_t)"Feature")
{
int index;
float weight;

// traverse node's attributes
MSXML2::IXMLDOMNamedNodeMapPtr spNameNodeMap = spNode->attributes;
for (long j = 0; j != spNameNodeMap->length; ++j)
{
MSXML2::IXMLDOMNodePtr spNode2 = spNameNodeMap->item[j];

if (spNode2->nodeName == (_bstr_t)"index")
index = (int)spNode2->nodeValue;
else if (spNode2->nodeName == (_bstr_t)"weight")
weight = (float)spNode2->nodeValue;
}

app_model.push_back(make_pair(index, weight));
}
}
}

spRoot.Release();
spXMLDoc.Release();
CoUninitialize();

return app_model;
}

Write to xml files:

Do like the following code, where input parameter file gives the file name that you want to save.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void write_appearance_model_to_xml(string file, vector<pair<int, float>> app_model, string name)
{
CoInitialize(NULL);

//read XML
MSXML2::IXMLDOMDocumentPtr spXMLDoc;
MSXML2::IXMLDOMElementPtr spRoot;
HRESULT hr = spXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30));

if (!SUCCEEDED(hr))
printf("Unable to create xml file.\n");
else
{
spXMLDoc->raw_createElement((_bstr_t)"Appearance_model", &spRoot);
spXMLDoc->raw_appendChild(spRoot, NULL);

MSXML2::IXMLDOMElementPtr childNode2;
spXMLDoc->raw_createElement((_bstr_t)"name", &childNode2);
childNode2->put_text((_bstr_t)xxx);
spRoot->appendChild(childNode2);

for (int i=0; i<app_model.size(); i++)
{
MSXML2::IXMLDOMElementPtr childNode;
spXMLDoc->raw_createElement((_bstr_t)"Feature", &childNode);

childNode->setAttribute("index", app_model[i].first);
childNode->setAttribute("weight", app_model[i].second);

spRoot->appendChild(childNode);
}

spXMLDoc->save(file.c_str());
}

spRoot.Release();
spXMLDoc.Release();
CoUninitialize();
}

Note: Above writing xml with <name>xxx</name> style is not fully tested.