|
hi alex,
can i ask why the destructors of the wrappers do not Release the underlying COM pointers? i would have thought that unless the user explicitly calls Detach or m_bAutoDelete is FALSE then the COM pointers need be cleaned up.
your thoughts?
.dan.g.
AbstractSpoon Software
|
|
|
|
|
Notice the:
if (!m_bAutoRelease)
m_xmlnode.Detach();
in the destructor.
Also notice that m_xmlnode is of type: IXMLDOMNodePtr
IXMLDOMNodePtr is of type _com_ptr_t
All of that means that _com_ptr_t will call "Release" on the underlying pointer unless "Detach" was called before.
so if m_bAutoRelease is FALSE I'm calling "Detach" and the "Release" function is not called, otherwise the Release is called in the destructor of IXMLDOMNodePtr.
Creative minds - create creative creations!
|
|
|
|
|
thanks alex.
btw, my question was related to an apparent memory leak in msxml that i was trying to find alternative causes for. i've googled on 'msxml memory leak' and it seems that many people are also experiencing it. do you know anything about this?
rgds
.dan.g.
AbstractSpoon Software
|
|
|
|
|
Hi, Alex,
Thanks a lot for your article! ^^
But I got a problem...
I Load File failure when I using my own project.
(of course I've added two files in it already.)
But in the demo sample it's okey!
Could you help me @@~ Did I miss something?
Thank you!
|
|
|
|
|
I found adding a line "CoInitialize(NULL);"
in the ProjectName.cpp
It works!!!
Thanks for Alex!
Thanks for my friend debugging with me!
|
|
|
|
|
You just saved me from going crazy. I couldn't understand why it wasn't working for me.
Thanks a lot!
|
|
|
|
|
Huge resource leak (Memory and Handles) with the following code (Checked with the Task Manager's Process List):
void test()
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
while(true)
{
CXmlDocumentWrapper xmlDoc;
xmlDoc.LoadXML("<ContactList>\n<ContactList>");
MSXML2::IXMLDOMNodePtr p(xmlDoc.AsNode());
CXmlNodeWrapper root(p);
for(int i=0; i<10; i++)
{
CXmlDocumentWrapper doc;
doc.LoadXML("<C><SomeObject></SomeObject></C>");
CXmlNodeWrapper node(doc.AsNode());
node.SetValue("NAME", "Lei Lei");
root.InsertNode(i, node.Interface());
}
}
}
It's due to the mixed use of smart pointers and raw pointers. A simple workaround is to find/replace all IXMLDOMNode*, IXMLDOMDocument*, and IXMLDOMNodeList* with IXMLDOMNodePtr, IXMLDOMDocumentPtr, and IXMLDOMNodeListPtr respectively, and then remove all ".Detach()".
Anyone noticed this problem?
|
|
|
|
|
This is NOT the correct way to use the API!
The same code should look like this:
CXmlDocumentWrapper xmlDoc;
xmlDoc.LoadXML("<Root/>");
CXmlNodeWrapper root(xmlDoc.AsNode());
for(int i=0; i<10; i++)
{
CXmlNodeWrapper node(root.InsertNode(-1,"NewNode"));
node.SetValue("NAME","lei lei");
}
xmlDoc.Save("D:\\xml.xml");
This way all the pointers gets released and there is no leak.
<span style="border-style: ridge; border-width: 1; background-color:#6699FF; font-weight:bold">
<font color="#FF3300">Creative minds - create creative creations!</font></span>
|
|
|
|
|
Sorry for my ignorance. I'm a newbie to COM and Smart Pointers.
Could you tell me whether it is harmful if I change the wrapper to use MSXML2::IXMLDOMDocumentPtr and not use MSXML2::IXMLDOMDocument*?
|
|
|
|
|
Actually the wrapper releases the interface on destruction.
So you shouldnt worry about it unless you access the direct pointers by ::Interface()
or ::Detach()
The ::Interface() function returns the pointer while calling AddRef on it, meaning it adds a refence count to the pointer so you should call Release() on that pointer later on to decrement the ref count. Or you could let the wrapper to do the work like that:
CXmlNodeWrapper node2(node1.Inteface());
Then when node2 goes out of scope it will automatically release the interface.
Same goes for Detach() only after Detach() the node becomes invalid and the interface is released completely.
There is no need to change anything in the wrapper itself, but you could use smart pointers to rceive the interface pointer when calling ::Interface() or ::Detach().
So that they'll get automatically released in destructor.
Creative minds - create creative creations!
|
|
|
|
|
<?xml version="1.0" encoding="utf-8" ?>
- <root>
- <input>
<nodeid>0</nodeid>
<parentid>0</parentid>
<userinputkey>9167791963</userinputkey>
</input>
- <output>
- <vrurequestscript>
- <datainput>
<mainmsgid>100</mainmsgid>
<correctvalues>1,2</correctvalues>
<charset>12</charset>
<length>1</length>
<timeout>10000</timeout>
<timeoutmsgid>200</timeoutmsgid>
<retrycount>3</retrycount>
<retryexitaction>end</retryexitaction>
<retryexitmsgid>300</retryexitmsgid>
</datainput>
- <confirminput>
<mainmsgid>101</mainmsgid>
<correctvalues>1,2</correctvalues>
<charset>12</charset>
<accept>1</accept>
<reject>2</reject>
<length>1</length>
<timeout>10000</timeout>
<timeoutmsgid>200</timeoutmsgid>
<retrycount>3</retrycount>
<retryexitaction>end</retryexitaction>
<retryexitmsgid>300</retryexitmsgid>
</confirminput>
</vrurequestscript>
<nodeid>0</nodeid>
<parentid>0</parentid>
</output>
</root>
|
|
|
|
|
The usage:
// Create the XML document
CXmlDocumentWrapper xmlDoc;
// Load the document from file
xmlDoc.Load(szFileName);
// Or from string
xmlDoc.LoadXml(szXml);
// Get the refence to the root node
CXmlNodeWrapper root(xmlDoc.AsNode());
// Get the correct node
CXmlNodeWrapper myInputNode(root.FindNode("input/userinputkey");
// Set the new value
myInputNode.SetText(szUserInput);
// Proccess the node
pADOObject->GetNextPrompt(myInputNode->GetXml(),szXml);
// Load the result xml
xmlDoc.LoadXml(szXml);
// Get the root
root = xmlDoc.AsNode();
// Get the output
CXmlNodeWrapper myOutPutNode(root.FindNode("output/messageid");
CString szValue = myOutPutNode.GetText();
Creative minds - create creative creations!
|
|
|
|
|
Hi Alex,
Thanks for your prompt reply. I was wondering if you could build a small module and show me how to get the value from the xml file and modify it. I tried working with the xml file with the way you had described but I didn't get the value from the node I wanted to, after passing the xml as string.
I appreciate any help in this.
Thank you
-Ray
|
|
|
|
|
Hi,
I am trying to parse my XML file using the XML parser pXMLPArser to accomplish the following tasks-
pXMLParser->ReplaceNodeVale("input\userinputkey", szUserInput);
pADOObject->GetNextPrompt(pXMLParser->Getxml(), szxml();
pXMLParser->Release();
pXMLParser->Loadxml(szxml);
pXMLParser->GetNodeValue("output\messageid", szNodeVale);
Here's how my xml file looks like-
- <root>
-
<nodeid>0
<parentid>0
<userinputkey>9167791963
-
- <vrurequestscript>
- <datainput>
<mainmsgid>100
<correctvalues>1,2
<charset>12
<length>1
<timeout>10000
<timeoutmsgid>200
<retrycount>3
<retryexitaction>end
<retryexitmsgid>300
Can someone show me how to write pXMLParser class. I am trying to use 'XmlNodeWrapper' but am confused since this is my first time dealing with xml parsers. Any help is greatly appreciated.
Thank you
Ray
|
|
|
|
|
alex,
i'm trying to build a fresh document from some data. i've instantiated a CXmlDocumentWrapper but when i call AsNode() on that object i get a NULL pointer returned.
i'm probably doing something daft, but can you help pls.
rgds
.dan.g.
AbstractSpoon Software
|
|
|
|
|
i discovered that the easiest way to initialize a document is to load it with some very simple xml,
eg doc.LoadXML("<a></a>");
and since xml must be contained within a single root item (i believe) this kinda makes sense.
.dan.g.
AbstractSpoon Software
|
|
|
|
|
Yep, that's exactly true.
You have to provide the root node.
Since when you instantiate a new document it doesn contain a single node. So you have to provide the root.
Creative minds - create creative creations!
|
|
|
|
|
alex,
i have some custom xml parsing code which i would like to replace with your wrappers but i have a one stumbling block at present: i need to build a xml document and then access the raw xml as text (specifically to encrypt it) before inserting that block as a CDATA element in another xml file. from my perusal of your source code i could not see a method which allows the raw xml to be grabbed straight from the document without having to save it to a temporary file and reload it as text. am i missing something?
rgds
.dan.g.
AbstractSpoon Software
|
|
|
|
|
There is a GetXML function for CXmlDocumentWrapper and CXmlNodeWrapper which returns a CString of the raw xml
Creative minds - create creative creations!
|
|
|
|
|
|
Great article, i could start a new application very efficiently. I have a problem now. I'm trying to retrieve all the nodes <day> within a precise <month> tag, but using this instruction:
CXmlNodeListWrapper daysList(month.FindNodes("//day"));
i get all the days in the year (suppose the XML is organized in monthes and days..) instead of the days in the requiered month. Seems like the result is the same as using rootnode like this:
CXmlNodeListWrapper daysList(rootnode.FindNodes("//day"));
instead of just a month.
Do i miss anything?
Thanks, really helpful...
Mirko Ortensi
|
|
|
|
|
You should use a contitional statenemt like this:
Suppose you have this XML:
<root>
<january>
<day number="20">
<day number="15">
<day number="26">
<day number="11">
<day number="08">
<february>
<day number="20">
<day number="15">
<day number="26">
<day number="11">
<day number="08">
You can than select all of the days in February with this statement: "//February/Day"
And to select aspecific day: "//Febuary/Day[@Number=15]"
And so on...
Check out the XSL pattern reference here: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/xmconpatterns.asp[^]
Creative minds - create creative creations!
|
|
|
|
|
Sorry the XML got formated...
The XML is as folows:
<Root>
<January>
<Day Number="12"></Day>
<Day Number="15"></Day>
<Day Number="16"></Day>
<Day Number="18"></Day>
<Day Number="25"></Day>
</January>
<Februaury>
<Day Number="05"></Day>
<Day Number="11"></Day>
<Day Number="16"></Day>
<Day Number="20"></Day>
<Day Number="26"></Day>
</Februaury>
</Root>
<span style="border-style: ridge; border-width: 1; background-color:#6699FF; font-weight:bold">
<font color="#FF3300">Creative minds - create creative creations!</font></span>
|
|
|
|
|
Also you could post your XML so I can write you the precise expression.
Creative minds - create creative creations!
|
|
|
|
|
Ok, i agree that having the XML structure you propose you can specify requested nodes like you say. My problem (it's not like days and monthes, but
it serves as a good example!) is related to the following XML:
<Root>
<Month>
<Day>1</Day>
<Day>2</Day>
<Day>3</Day>
<Day>4</Day>
<Day>5</Day>
</Month>
<Month>
<Day>6</Day>
<Day>7</Day>
<Day>8</Day>
<Day>9</Day>
<Day>10</Day>
</Month>
</Root>
I do not have the possibility to use attributes (i know it would make things easier, but no possibility), and doesn't matter which month is it, just consider as a set (it could really be <month>==<generic_set>).
So, i want to extract days separately from these sets, and i do like
this...:
// to get all monthes node
CXmlNodeListWrapper monthesList(Root.FindNodes("//Month"));
// parse each month
for (int j = 0; j < monthesList.Count(); j++){
// extract monthnode from list
CXmlNodeWrapper monthnode(monthesList.Node(j));
// get days under current Month
CXmlNodeListWrapper daysList(monthnode.FindNodes("//Day"));
// process daysList...
}
Well the problem i have is in the last instruction of the code:
instead of getting only the days under current Month (j==0:
1,2,3,4,5; j==1: 6,7,8,9,10) it gets all days (1,2,3,4,5,6,7,8,9,10)
for each month; so it seems like the instruction:
CXmlNodeListWrapper daysList(monthnode.FindNodes("//Day"));
acts like:
CXmlNodeListWrapper daysList(Root.FindNodes("//Day"));
getting the whole set of days in the sheet and not just the ones
under current month node.
I thank you for your attention, maybe it's an error of mine but i
cannot make headway!
Bye, Mirko
|
|
|
|