I would like to validate an XML file in C++ using the MSXML6 parser and have followed the instructions on http://msdn.microsoft.com/en-us/library/ms762774%28v=vs.85%29.aspx . However, the project I'm working on requires the XSD schema to be embedded in the binary file.
This is the XML file, which should be validated (all files simplified for demonstration purposes):
<?xml version="1.0" encoding="UTF-8"?>
<Document xsi:schemaLocation="urn:test schema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:test">
<Party>
<Id>1</Id>
<Name>Bob</Name>
<Salary>100.00</Salary>
</Party>
<Party>
<Id>2</Id>
<Name>Alice</Name>
<Salary>200.00</Salary>
</Party>
<Party>
<Id>3</Id>
<Name>Günther</Name>
<Salary>300.00</Salary>
</Party>
</Document>
And here's the XSD schema:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<xs:schema xmlns="urn:test" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:test" elementFormDefault="qualified">
<xs:simpleType name="NameType">
<xs:restriction base="xs:string">
<xs:pattern value="([A-Za-z0-9ÄÖÜäöü]){1,10}"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="PartyType">
<xs:sequence>
<xs:element name="Id" type="xs:integer"/>
<xs:element name="Name" type="NameType"/>
<xs:element name="Salary" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Document">
<xs:complexType>
<xs:choice minOccurs="1" maxOccurs="9999999">
<xs:element name="Party" type="PartyType"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
The above XSD schema is embedded as a Win32 resource in the executable and can be referenced via the identifier "IDR_XSDSCHEMA1" (see comment line with OPTION 1):
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#import <msxml6.dll>
#include "resource.h"
// Macro that calls a COM method returning HRESULT value.
#define CHK_HR(stmt) do { hr=(stmt); if (FAILED(hr)) return bstrResult; } while(0)
//Method for acquiring own handle
HMODULE GetThisDllHandle()
{
MEMORY_BASIC_INFORMATION info;
size_t len = VirtualQueryEx(GetCurrentProcess(), (void*)GetThisDllHandle, &info, sizeof(info));
return len ? (HMODULE)info.AllocationBase : NULL;
}
_bstr_t validateFile(_bstr_t bstrFile)
{
//Schema collection
MSXML2::IXMLDOMSchemaCollectionPtr pXS;
//XML document
MSXML2::IXMLDOMDocument2Ptr pXD;
//XSD document
MSXML2::IXMLDOMDocument2Ptr pXSD;
//Validation object
MSXML2::IXMLDOMParseErrorPtr pErr;
_bstr_t bstrResult = L"";
HRESULT hr = S_OK;
//Load XSD schema from resource
HMODULE handle = GetThisDllHandle();
HRSRC rc = ::FindResource(handle, MAKEINTRESOURCE(IDR_XSDSCHEMA1), L"XSDSCHEMA");
HGLOBAL rcData = ::LoadResource(handle, rc);
LPVOID data = (::LockResource(rcData));
::FreeResource(rcData);
//Load schema stream into document
CHK_HR(pXSD.CreateInstance(__uuidof(MSXML2::DOMDocument60), NULL, CLSCTX_INPROC_SERVER));
if (pXSD->loadXML((LPCSTR)data) != VARIANT_TRUE)
return bstrResult;
// Create a schema cache
CHK_HR(pXS.CreateInstance(__uuidof(MSXML2::XMLSchemaCache60), NULL, CLSCTX_INPROC_SERVER));
//--> OPTION 1: VALIDATING AGAINST EMBEDDED XSD RESOURCE; DOESN'T WORK <--
CHK_HR(pXS->add(L"urn:test", pXSD.GetInterfacePtr()));
//--> OPTION 2: VALIDATING AGAINST PHYSICAL XSD FILE; WORKS FINE <--
//CHK_HR(pXS->add(L"urn:test", L"schema.xsd"));
// Create a DOMDocument and set its properties.
CHK_HR(pXD.CreateInstance(__uuidof(MSXML2::DOMDocument60), NULL, CLSCTX_INPROC_SERVER));
pXD->async = VARIANT_FALSE;
pXD->validateOnParse = VARIANT_TRUE;
pXD->preserveWhiteSpace = VARIANT_TRUE;
//Assign the schema cache to the Document's schema collection
pXD->schemas = pXS.GetInterfacePtr();
//Load XML file
if(pXD->load(bstrFile) != VARIANT_TRUE)
{
pErr = pXD->parseError;
bstrResult = _bstr_t(L"Validation failed on ") + bstrFile +
_bstr_t(L"\n=====================") +
_bstr_t(L"\nReason: ") + _bstr_t(pErr->Getreason()) +
_bstr_t(L"\nSource: ") + _bstr_t(pErr->GetsrcText()) +
_bstr_t(L"\nLine: ") + _bstr_t(pErr->Getline());
}
else
{
bstrResult = _bstr_t(L"Validation succeeded for ") + bstrFile +
_bstr_t(L"\n======================\n") +
_bstr_t(pXD->xml);
}
return bstrResult;
}
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = CoInitialize(NULL);
if(SUCCEEDED(hr))
{
try
{
_bstr_t bstrOutput = validateFile(L"Document.xml");
MessageBox(NULL, bstrOutput, L"schemaCache",MB_OK);
}
catch(_com_error &e)
{
MessageBox(NULL, e.Description(), L"schemaCache",MB_OK);
}
CoUninitialize();
}
return 0;
}
Unfortunately, I have encountered some strange behavior while trying to run the validation routine (OPTION 1 comment). It seems, that the umlauts in the XSD resource aren't properly decoded while being loaded into the stream. This results in a messed up validation reference, as seen in the following result:
However, when the schema file is loaded directly from disk (OPTION 2 comment), the validation routine runs just fine:
I have already tried to convert the loaded stream from Unicode to Multi-Byte and vice versa, however to no avail. Is there something I'm missing here? Or are Win32 resources limited to a specific character set? Thanks for any suggestions.
See comment from WhozCraig: Using MultiByteToWideChar() with CP_UTF8 as an input argument returns a valid Unicode string.
Related
I am trying to build a simple xml file using tinyxml2 in VS2019,
for some reason the code works until it hits the element named port.
this element and every element after it is ignored in the xml file.
I just noticed, it is also writing xml output in the wrong order, host should be the one right below , not port.
What am i missing here?
Truth be told, i have about 2 days experience writing c++, and very basic python knowlage.
#include <iostream>
#include <fstream>
#include <windows.h>
#include <Lmcons.h>
#include <stdlib.h>
#include <filesystem>
#include "tinyxml/tinyxml2.h"
using namespace tinyxml2;
using namespace std;
namespace fs = std::filesystem;
int main()
{
SetConsoleOutputCP(CP_UTF8);
char* appdata;
size_t len;
errno_t err = _dupenv_s(&appdata, &len, "APPDATA");
fs::path path = appdata;
path /= "FileZilla";
path /= "sitemanager.xml";
TCHAR username[UNLEN + 1];
DWORD size = UNLEN + 1;
GetUserName((TCHAR*)username, &size);
tinyxml2::XMLDocument xmlDoc;
//tinyxml2::XMLDeclaration* decl = new XMLDeclaration("1.0", "UTF-8", "");
XMLElement* pRoot = xmlDoc.NewElement("FileZilla3");
pRoot->SetAttribute("Version", "");
pRoot->SetAttribute("Platform", "");
xmlDoc.InsertFirstChild(pRoot);
XMLElement* child = xmlDoc.NewElement("Servers");
child->SetText("\n");
pRoot->InsertEndChild(child);
XMLElement* subchild = xmlDoc.NewElement("Server");
subchild->SetText("\n");
child->InsertEndChild(subchild);
XMLElement* host = xmlDoc.NewElement("host");
host->SetText("ftp.some.url");
subchild->InsertEndChild(host);
XMLElement* port = xmlDoc.NewElement("port");
port->SetText(21);
subchild->InsertEndChild(port);
XMLElement* protocol = xmlDoc.NewElement("Protocol");
protocol->SetText(0);
subchild->InsertEndChild(protocol);
XMLElement* type = xmlDoc.NewElement("type");
type->SetText(0);
subchild->InsertEndChild(type);
XMLElement* user = xmlDoc.NewElement("user");
user->SetText("test");
subchild->InsertEndChild(host);
xmlDoc.SaveFile("SavedData.xml");
cout << path << endl;
std::wcout << username << endl;
return 0;
}
The output file looks like this:
<FileZilla3 Version="" platform="">
<Servers>
<Server>
<port>21</port>
<Protocol>0</Protocol>
<type>0</type>
<host>ftp.some.url</host>
</Server>
</Servers>
</FileZilla3>
the desired uotput should be this:
<?xml version="1.0" encoding="UTF-8"?>
<FileZilla3 version="" platform="">
<Servers>
<Server>
<Host>saddf</Host>
<Port>21</Port>
<Protocol>0</Protocol>
<Type>0</Type>
<User>username</User>
<Pass encoding="base64" />
<Logontype>1</Logontype>
<PasvMode>MODE_DEFAULT</PasvMode>
<EncodingType>Auto</EncodingType>
<BypassProxy>0</BypassProxy>
<Name>Ny tjener</Name>
<SyncBrowsing>0</SyncBrowsing>
<DirectoryComparison>0</DirectoryComparison>
</Server>
</Servers>
</FileZilla3>
XMLElement* user = xmlDoc.NewElement("user");
user->SetText("test");
subchild->InsertEndChild(host);
should be
XMLElement* user = xmlDoc.NewElement("user");
user->SetText("test");
subchild->InsertEndChild(user);
I am newbie to xml and xslt area. I have written simple COM utility to transform xsl using xslt. But is failing at transformNodeToObject function call. I am using visual studio 15.
As you can see i am using the msxml6.dll import.
There was another type of call m_hrDOMInitStatus = CoCreateInstance(MSXML2::CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, MSXML2::IID_IXMLDOMDocument3, (void**)&m_pDoc); Not sure whether i need to use this API
#include "stdafx.h"
#include <windows.h>
#include "iostream"
#include <WTypes.h>
#include <comdef.h>
#include <wchar.h>
#include <vector>
#import <msxml6.dll>
using namespace MSXML2;
using namespace std;
int main()
{
HRESULT hResult = S_OK;
hResult = CoInitialize(NULL);
if (FAILED(hResult))
{
cerr << "Failed to initialize COM environment" << endl;
return 0;
}
// MSXML COM smart pointers
// Use the Document2 class to enable schema validation
IXMLDOMDocument2Ptr spDocSource;
IXMLDOMDocument2Ptr spDocResult;
IXMLDOMDocument2Ptr spDocStylesheet;
struct IDispatch * pDispatch;
// Create the COM DOM Document objects
hResult = spDocSource.CreateInstance(__uuidof(DOMDocument60));
if FAILED(hResult)
{
cerr << "Failed to create Source Document instance" << endl;
return 1;
}
hResult = spDocResult.CreateInstance(__uuidof(DOMDocument60));
if FAILED(hResult)
{
cerr << "Failed to create Result Document instance" << endl;
return 1;
}
hResult = spDocStylesheet.CreateInstance(__uuidof(DOMDocument60));
if FAILED(hResult)
{
cerr << "Failed to create Stylesheet Document instance" << endl;
return 1;
}
// Load the source document
spDocSource->async = VARIANT_FALSE;
hResult = spDocSource->load("xmlinputfile.xml");
if (hResult != VARIANT_TRUE)
{
cout << "Error parsing xmlinputfile.xml" << endl;
return 1;
}
spDocSource->async = VARIANT_FALSE;
hResult = spDocSource->load("XSLTFile1.xslt");
if (hResult != VARIANT_TRUE)
{
cout << "Error parsing XSLTFile1.xml" << endl;
return 1;
}
spDocResult->QueryInterface(IID_IDispatch, (void **)&pDispatch);
VARIANT vResultDoc;
vResultDoc.vt = VT_DISPATCH;
vResultDoc.pdispVal = pDispatch;
hResult = spDocSource->transformNodeToObject(spDocStylesheet, vResultDoc);
if FAILED(hResult)
{
cout << "Error in performing transformation" << endl;
return 1;
}
return 0;
}
xml input:
_____________
<?xml version="1.0"?>
-<MODEL-LIST ENTERPRISE-XML-VERSION="3">
<MODEL TYPE="Enhanced Macrocell" ID="450 MHz Default"> </MODEL>
</MODEL-LIST>
xslt:
----
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<MODEL-LIST>
<xsl:for-each select="MODEL">
<xsl:element name="MODEL">
<xsl:attribute name="ID">
<xsl:value-of select="#ID"/>
</xsl:attribute>
<xsl:attribute name="TYPE">
<xsl:value-of select="#TYPE"/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</MODEL-LIST>
</xsl:template>
</xsl:stylesheet>
The Microsoft online examples on using MSXML with smart pointers, like https://msdn.microsoft.com/en-us/ie/ms766389(v=vs.100), suggest that the call to transformNode would simply work as spDocSource->transformNodeToObject(spDocStylesheet, spDocResult.GetInterfacePtr()).
I think this is due to KB of CVE-2019-1357.
Does the phenomenon not stop when the following KB is uninstalled?
KB4522007: Windows 7 SP1/8.1/ServerR2 SP1/2012(IE10/IE11)/2012 R2/2008 SP2(IE9)
KB4522009: Windows 10(RTM、build10240)
KB4522010: Windows 10 ver1607/Server 2016
KB4522011: Windows 10 ver1703
KB4522012: Windows 10 ver1709
KB4522014: Windows 10 ver1803
KB4522015: Windows 10 ver1809/Server 2019
KB4522016: Windows 10 ver1903
I have an XML and XSD file. I can read the XML using Xerces if XSD file has the root XML element define as a named complexType but I am trying to figure out how to read the file if root item in XSD is not named type. Here are my files:
The XML file
<?xml version="1.0"?>
<x:books xmlns:x="urn:BookStore"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:BookStore books.xsd">
<book id="bk001">
<author>Writer</author>
<title>The First Book</title>
<genre>Fiction</genre>
<price>44.95</price>
<pub_date>2000-10-01</pub_date>
<review>An amazing story of nothing.</review>
</book>
<book id="bk002">
<author>Poet</author>
<title>The Poet's First Poem</title>
<genre>Poem</genre>
<price>24.95</price>
<pub_date>2001-10-01</pub_date>
<review>Least poetic poems.</review>
</book>
</x:books>
The XSD file:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:BookStore"
xmlns:bks="urn:BookStore">
<xsd:complexType name="BookForm">
<xsd:sequence>
<xsd:element name="author" type="xsd:string"/>
<xsd:element name="title" type="xsd:string"/>
<xsd:element name="genre" type="xsd:string"/>
<xsd:element name="price" type="xsd:float" />
<xsd:element name="pub_date" type="xsd:date" />
<xsd:element name="review" type="xsd:string"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string"/>
</xsd:complexType>
<xsd:element name="books"> <!-- not mapped to named typed! -->
<xsd:complexType >
<xsd:sequence>
<xsd:element name="book"
type="bks:BookForm"
minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Reading the library (reading only two fields)
#include <iostream>
#include "books.h"
using namespace std;
using namespace BookStore;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
try {
// what do I do here since BooksForm is not defined now and XSD file
// doesn't map it to the root element of XML?
auto_ptr<BooksForm> bookBank (books( "books.xml" ));
for (BooksForm::book_const_iterator i = (bookBank->book().begin());
i != bookBank->book().end();
++i)
{
cout << "Author is '" << i->author() << "'' " << endl;
cout << "Title is '" << i->title() << "'' " << endl;
cout << endl;
}
}
catch (const xml_schema::exception& e)
{
cerr << e << endl;
return 1;
}
return a.exec();
}
So this code works if XSD file is in format as in this post but I want to know how can I read the XML if the XSD file is in above format. I need to do this in this small demo so I can resolve the similar situation in another larger and more complex XML file which is a given thing.
I am trying to build a server application using gsoap 2.8.17. I've created a header file with service function prototype and a result record definition
testserver.h:
#ifndef TESTSERVER_H
#define TESTSERVER_H
#include <string>
//gsoap ns service name: TestServer
//gsoap ns service namespace: http://mycomp:8080/TestServer.wsdl
//gsoap ns service location: http://mycomp:8080/TestServer.cgi
//gsoap ns schema namespace: urn:TestServer
class Record
{
public:
int id;
std::string name;
std::string address;
double param1;
};
int ns__GetRecord(int id, Record* result);
#endif
Then I've invoked the gSOAP RPC compiler:
soapcpp2.exe testserver.h
The compiler produced the following files:
soapC.cpp
soapClient.cpp
soapClientLib.cpp
soapServer.cpp
soapServerLib.cpp
soapH.h
soapStub.h
TestServer.h
TestServer.nsmap
TestServer.wsdl
TestServer.GetRecord.req.xml
TestServer.GetRecord.res.xml
ns.xsd
TestServer.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="TestServer"
targetNamespace="http://mycomp:8080/TestServer.wsdl"
xmlns:tns="http://mycomp:8080/TestServer.wsdl"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ns="urn:TestServer"
xmlns:SOAP="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:HTTP="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:MIME="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:DIME="http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/"
xmlns:WSDL="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<schema targetNamespace="urn:TestServer"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ns="urn:TestServer"
xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="Record"><!-- Record -->
<sequence>
<element name="id" type="xsd:int" minOccurs="1" maxOccurs="1"/><!-- Record::id -->
<element name="name" type="xsd:string" minOccurs="1" maxOccurs="1"/><!-- Record::name -->
<element name="address" type="xsd:string" minOccurs="1" maxOccurs="1"/><!-- Record::address -->
<element name="param1" type="xsd:double" minOccurs="1" maxOccurs="1"/><!-- Record::param1 -->
</sequence>
</complexType>
<!-- operation request element -->
<element name="GetRecord">
<complexType>
<sequence>
<element name="id" type="xsd:int" minOccurs="1" maxOccurs="1"/><!-- ns__GetRecord::id -->
</sequence>
</complexType>
</element>
<!-- operation response element -->
<element name="GetRecordResponse">
<complexType>
<sequence>
<element name="result" type="ns:Record" minOccurs="0" maxOccurs="1" nillable="true"/><!-- ns__GetRecord::result -->
</sequence>
</complexType>
</element>
</schema>
</types>
<message name="GetRecordRequest">
<part name="Body" element="ns:GetRecord"/><!-- ns__GetRecord::ns__GetRecord -->
</message>
<message name="GetRecordResponse">
<part name="Body" element="ns:GetRecordResponse"/>
</message>
<portType name="TestServerPortType">
<operation name="GetRecord">
<documentation>Service definition of function ns__GetRecord</documentation>
<input message="tns:GetRecordRequest"/>
<output message="tns:GetRecordResponse"/>
</operation>
</portType>
<binding name="TestServer" type="tns:TestServerPortType">
<SOAP:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="GetRecord">
<SOAP:operation soapAction=""/>
<input>
<SOAP:body parts="Body" use="literal"/>
</input>
<output>
<SOAP:body parts="Body" use="literal"/>
</output>
</operation>
</binding>
<service name="TestServer">
<documentation>gSOAP 2.8.17 generated service definition</documentation>
<port name="TestServer" binding="tns:TestServer">
<SOAP:address location="http://mycomp:8080/TestServer.cgi"/>
</port>
</service>
</definitions>
As documentation recommends I added soapServerLib.cpp to my project, but the C++ Builder 2010 compiler produces errors:
[BCC32 Error] soapC.cpp(1611): E2238 Multiple declaration for 'ns__GetRecord(soap *,int,Record *)'
[BCC32 Error] soapStub.h(224): E2344 Earlier declaration of 'ns__GetRecord(soap *,int,Record *)'
[BCC32 Error] soapC.cpp(1611): E2303 Type name expected
[BCC32 Error] soapC.cpp(1611): E2379 Statement missing ;
[BCC32 Error] soapC.cpp(1717): E2379 Statement missing ;
soapStub.h(224):
SOAP_FMAC5 int SOAP_FMAC6 ns__GetRecord(struct soap*, int id, Record *result);
soapC.cpp(1598-1619):
SOAP_FMAC1 struct ns__GetRecord * SOAP_FMAC2 soap_instantiate_ns__GetRecord(struct soap *soap, int n, const char *type, const char *arrayType, size_t *size)
{
(void)type; (void)arrayType; /* appease -Wall -Werror */
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "soap_instantiate_ns__GetRecord(%d, %s, %s)\n", n, type?type:"", arrayType?arrayType:""));
struct soap_clist *cp = soap_link(soap, NULL, SOAP_TYPE_ns__GetRecord, n, soap_fdelete);
if (!cp)
return NULL;
if (n < 0)
{ cp->ptr = (void*)SOAP_NEW(struct ns__GetRecord);
if (size)
*size = sizeof(struct ns__GetRecord);
}
else
{ cp->ptr = (void*)SOAP_NEW_ARRAY(struct ns__GetRecord, n); // <<<-- error here
if (size)
*size = n * sizeof(struct ns__GetRecord);
}
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Instantiated location=%p\n", cp->ptr));
if (!cp->ptr)
soap->error = SOAP_EOM;
return (struct ns__GetRecord*)cp->ptr;
}
Why is ns__GetRecord interpreted as a structure while it's a function name? What should I fix in my TestServer.h to make soapcpp2.exe produce a compilable code ?
The only solution I found is to remove the soap_instantiate_ns__GetRecord function body.
SOAP_FMAC1 struct ns__GetRecord * SOAP_FMAC2 soap_instantiate_ns__GetRecord(struct
soap *soap, int n, const char *type, const char *arrayType, size_t *size)
{
return NULL;
}
Then the server code compiles and works fine.
I`m try to realize how to use TinyXML library.
I have to parse this conf file:
<?xml version="1.0" encoding="UTF-8"?>
<Client>
<port num = "20035">
<server_addr ip="127.0.0.1">
<AV_list>
<AV>
<AVNAME>BitDefender</AVNAME>>
<AVPATH> C:\Program Files\Common Files\BitDefender\BitDefender Threat Scanner\av64bit_26308\bdc.exe </AVPATH>
<AVMASK>0x80000000</AVMASK>
<AVCOMMANDLINE> %avpath% \log=%avlog% %scanpath% </AVCOMMANDLINE>
<AVREGEX>(%scanpath%.*?)+(([a-zA-Z0-9]+\\.)+[a-zA-Z]{2,4})+(.+[a-zA-Z_])</AVREGEX>
<AVLOG>C:\log\bd_log.txt</AVLOG>
</AV>
</AV_list>
</Client>
And c++ code
#include "stdafx.h"
#include "iostream"
#include "tinyxml.h"
int main(int argc, char* argv[])
{
TiXmlDocument doc( "D:\\client_conf.xml" );
bool loadOkay = doc.LoadFile();
if ( loadOkay )
printf("Yes \n");
else
printf("No \n");
TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlText* pText;
TiXmlHandle hRoot(0);
pElem = hDoc.FirstChildElement().Element();
if (!pElem)
printf("error element");
hRoot = TiXmlHandle(pElem);
pElem = hRoot.FirstChild("server_addr").Element();
const char* info = pElem->Attribute("ip");
printf( "%s \n", info);
pElem = hRoot.FirstChild("port").Element();
info = pElem->Attribute("num");
printf( "%s \n", info);
system("pause");
return 0;
}
Now I can get first two param, but dont figure out how to reach "AV_list" block. Any help will be appreciated. (:
Have a look at the TinyXml Documentation. Your friend is the TiXmlNode Class Reference. You may use most of the Node functions also on TiXmlElements.
You already use the FirstChild() function to get the first child of an element; use the NextSibling() function to iterate over all elements. You can also use the NextSiblingElement() function to get the element directly.
Antother more sophisticated solution would be to use XPath to retrieve elements from the xml file. There is TinyXPath that builds on top of TinyXML. It needs some knowledge of XPath but it might be worth it. (XPath standard)