|
Of course it can, it has only about 10000000 different "ifs".
Such as what prosessor do you have, what is the speed of your hard disk, wether your process has the highest priority , what processor time is available for your process, how big is your file going to be, is the mashine doing something elese at this moment (updating the untivirus for example) , etc...
What I'm trying to say is that you should NEVER under no circumstanses expect some task finish in some predefined time , please either work on some other strategy in your application or at least explain why is the time so critical.
Creative minds - create creative creations!
|
|
|
|
|
Why the process is time critical ? the answer to that is , i am generating an export for a device configuration , the configuration is saved as an xml file . Now when the user exports the configuration , i dont have any status bar for indicating the status of the export, thus the application which i am using for export appears to be hung. I dont want to spoil the user experience by taking too long a time to generate an export,thats why a self imposed time criticality is there.I was talking to one of my friends about MSXML 3.0 taking too long to taverse the DOM tree if the XML document is too big , I wanted your opinion on weather MSXML is slow . I have worked with it earlier and i found it really fast , generating an xml in milli seconds.But i still need a confiration from someone before i go ahead.After reading the article i felt you might be the one. Thanx in advance for paying attention.
|
|
|
|
|
MSXML is capble of producing 50000 nodes XML in less than a second.
It also capble of quiering this XML 5~50 quieries in less than a second.
But as I said before it all depends on many issues.
My advise for you is to try first, than if you see that the process of saving the configuration is taking too long (more than couple of seconds) consined adding a progress bar or if that is not possible, at least some flashing message like "Saving configuration, please wait...".
Creative minds - create creative creations!
|
|
|
|
|
Hi,
first : thanks for your good work.
I'm trying to use your function GetUrl() to know if the document has been already saved, but it doesn't work.
<br />
if(_myDoc.GetUrl() != ""){<br />
return (_myDoc.Save(""));<br />
}else{<br />
CFileDialog fDlg(FALSE,"xml",NULL,OFN_HIDEREADONLY | OFN_PATHMUSTEXIST,"Xml Files (*.xml)|*.xml||");<br />
...<br />
Can you give me a clue ?
Thx !
|
|
|
|
|
What is it exactly that doesn't work?
What do you get from the GetUrl function?
Creative minds - create creative creations!
|
|
|
|
|
I always get an empty string...and that's strange because always use Load or Save before.
Debug-mode says that returned PTR for url is invalid and converts it to "" (???)
Thx for help
|
|
|
|
|
Hi~ Alex:
First I would like to thank you for your wrapper class. It is a perfect class and help me a lot.
However, I have one little question that need you help to answer.
1. I had used your class and I can add a new node in xml file. But when I open the xml by text editor like UltraEdit. It did not have the line feed effection.
For example:
////////////////////////////////////////////////
// original
<book id="bk112">
<author>Galos, Mike
<title>Visual Studio 7: A Comprehensive Guide
<genre>Computer
<price>49.95
<publish_date>2001-04-16
<description>Microsoft Visual Studio 7 is explored in depth, looking at how Visual Basic, Visual C++, C#, and ASP+ are integrated into a comprehensive development environment.
////////////////////////////////////////////////
// New item
<book_user id="123"><arthur>Keven Yang<title>This is a test<grene>test<date>20050728<description>This is a test item
If you have free time, please help me to answer it!
thanks...
|
|
|
|
|
You should alter the "preserveWhiteSpace" property of DOMDocument.
This requires you to change the originginal code!
Creative minds - create creative creations!
|
|
|
|
|
Hi, I’m new to using XML but would like to incorporate it into one of the applications I’m writing. I am very clueless about both XML in general and using this class. I’ve painfully tried many things and just can’t seem to get the output I’m looking for.
First of all, here is an XML example of what I’m trying to do:
<PrinterDefines>
<Group>Epson SIDM Printers
<Printer>LQ-570
<Lang>ESC/P2</Lang>
<Pins>24</Pins>
</Printer>
<Printer>FX-870
<Lang>ESC/P2</Lang>
<Pins>9</Pins>
</Printer>
</Group>
<Group>Epson POS Printers
<Printer>TM-U220
<Lang>ESC/POS</Lang>
<Pins>9</Pins>
</Printer>
</Group>
</PrinterDefines>
Ideally, I’m defining printer groups and types. The groups in this example are Epson SIDM printers and Epson POS printers. Under each group, there are printers listed. For example, under the SIDM group, there are two printers defined: LQ-570 and FX-870. Under each printer there are further fields pertaining to that printer. For example, the LQ-570 uses ESC/P2 language and it has 24 pins.
What I’m trying to do is obviously retrieve this data. For example, if I want to retrieve the LQ-570, I also want to retrieve it’s language and the number of pins associated with it; and I want these individual strings to end-up in CStrings. Of course, these are two of many fields that I need to associate with that printer. This one is just a start so that I can understand it. Once I understand it, the list will be quite complex, and this data will end up in various classes. For now, CStrings will be fine for me to learn.
Anyway, I can successfully get the entire list of ‘Groups’ with the following:
CXmlNodeListWrapper GroupList(node.FindNodes("//Group"));
My problem is I don’t know what to do next! I’ve tried many things, and each is way way off, so any help would greatly be appreciated.
Thanks!
|
|
|
|
|
To get specific group:
CXmlNodeWrapper Group(node.FindNode("//Group[text() = 'Epson POS Printers'"));
This will get the group "Epson POS Printers"
To get specific printer:
CXmlNodeWrapper Printer(node.FindNode("//Printer[text() = 'FX-870'"));
This will get the FX-870 printer.
Since all the printer properties are defined as Nodes rather than attributes,
You have to use GetNode function to get a specific node, and you cant use GetValue function.
Example:
CXmlNodeWrapper node;
node = Printer.GetNode("Lang");
CString szLang = node.Text();
Creative minds - create creative creations!
|
|
|
|
|
Hi Alex, Thanks for the info. In my case, the example to get a specific group such as:
CXmlNodeWrapper Group(node.FindNode("//Group[text() = 'Epson POS Printers'"));
will not work for me as I am defining the groups and printers in the XML file. In other words, I do not know the names to search for until I've loaded and parsed the XML file. The XML file defines printer types, names, and properties in my application. Anyway, here is the way I ended up doing it and it worked fine for me...
void CPrinterFileInfo::ParsePrinterDefinesNode(IDispatch *pNode)
{
CGroupEntryInfo *gei;
CXmlNodeWrapper node(pNode);
CXmlNodeListWrapper GroupList(node.FindNodes(_T("//Group"))); // Thermal, SIDM, etc...
GroupList.Start();
CXmlNodeWrapper List2(GroupList.Next());
while(List2.IsValid())
{
gei = new CGroupEntryInfo;
ParseGroupDefinesNode(List2, *(gei));
AddGroupEntry(*(gei));
List2 = GroupList.Next();
delete gei;
}
}
void CPrinterFileInfo::ParseGroupDefinesNode(CXmlNodeWrapper& node, CGroupEntryInfo& gei)
{
CDeviceEntryInfo *dei;
gei.SetGroupName(node.GetAttribVal(XML_GROUP_NAME));
gei.SetGroupDescription(node.GetAttribVal(XML_GROUP_DESC));
for(int j= 0; j < node.NumNodes(); j++)
{
dei = new CDeviceEntryInfo;
CXmlNodeWrapper List(node.GetNode(j));
ParseMemberDefinesNode(List, *(dei));
gei.AddMemberEntry(*(dei));
delete dei;
}
}
void CPrinterFileInfo::ParseMemberDefinesNode(CXmlNodeWrapper& node, CDeviceEntryInfo& dei)
{
dei.SetDeviceName(node.GetAttribVal(XML_DEVICE_NAME));
dei.SetDeviceClass(node.GetAttribVal(XML_DEVICE_CLASS));
dei.SetDeviceFeatures(node.GetAttribVal(XML_DEVICE_FEATURES));
dei.SetDevicePaperPaths(node.GetAttribVal(XML_DEVICE_PAPER));
dei.SetDeviceFonts(node.GetAttribVal(XML_DEVICE_FONTS));
dei.SetDeviceColumns(node.GetAttribVal(XML_DEVICE_COLS));
dei.SetDeviceInterface(node.GetAttribVal(XML_DEVICE_INTERFACES));
dei.SetDeviceLanguage(node.GetAttribVal(XML_DEVICE_LANG));
dei.SetDeviceExFeatures(node.GetAttribVal(XML_DEVICE_EXFEATURES));
dei.SetDeviceBuffer(node.GetAttribVal(XML_DEVICE_BUFFERSIZE));
}
Part of the XML File...
<?xml version="1.0" encoding="UTF-8"?>
<DeviceDefines>
<Group Name="TM-T Series" Desc="Thermal Point Of Sale Printers">
<Device Name="TM-T88III"
Class="1"
Features="2147610751"
PaperPaths="15"
Fonts="3"
Cols="12"
Interface="15"
Lang="3"
ExFeatures="41"
Buffer="4096">
</Device>
</Group>
</DeviceDefines>
Thanks for your reply!
|
|
|
|
|
I have two CXmlDocumentWrapper objects (doc1 and doc2). And I need to copy xml document from doc1 to doc2. So I must free memory used by doc1.m_xmldoc and copy data from doc2.m_xmldoc to doc1.m_xmldoc. As I can see now you working with pointers, so if I change doc1.m_xmldoc, doc2.m_xmldoc will be changed too. What should I do?
I cannot use Clone method because I must free doc1.m_xmldoc first
|
|
|
|
|
Assume you have doc1 object:
CXmlDocumentWrapper doc2(doc1.Clone());
Creative minds - create creative creations!
|
|
|
|
|
I mean if I have some xml document already loaded in doc2
CXmlDocumentWrapper doc2;
doc2.Load( _T("sample.xml") );
....
doc2 = doc1.Clone();
So I want to know will the memory already occupied in doc2 be free when I do doc2 = doc1.Clone() ?
|
|
|
|
|
Yep.
Creative minds - create creative creations!
|
|
|
|
|
Hi, Alex
I have only one little question: How I can add the string like <?xml version="1.0" encoding="UTF-8"?> in my xml file. I try to do like your suggestion in your old article( insert createProcessingInstruction() in the document constructor). But in this case if I make after then LoadXML(something) to start new tree, the instruction row has been disappeared.
I fixed it now by loading doc from template file, but may be you have a better resolve?
Thanks
|
|
|
|
|
The create processing instructio function is not implemented in this release, but since the class operates on ditect pointers you can ask for raw pointer to the document via Interface() finction and add the instruction yourself.
Creative minds - create creative creations!
|
|
|
|
|
Anyone know what modifications need to be made in order to get this to work with MSXML 4.0 SP2?
Overall, an excellent article alex, thank you!
Dru
|
|
|
|
|
Basically i guess you just need to import msxml4.dll instead of msxml3.dll
And agiain that is only an unchecked guess...
I'll try to check this later when i have time...
Creative minds - create creative creations!
|
|
|
|
|
Yes, but You also have to change the two occurenses of CLSID_DOMDocument to CLSID_DOMDocument40 , or the msxml3.dll will be loaded even though you've #imported "msxml4.dll".
(I struggled with this for a while; I couldn't understand why it would validate my .xml files which contained a reference to a .xsd. Now I know that msxml3 doesn't grok .xsd's.)
Thanks for the classes anyway Alex, even though I hope You will take the time to update it regarding the memory issues. I'm not into this COM stuff, so I can't really do it myself (and I'm lazy, too ).
|
|
|
|
|
Ah that might explain why my application doesn't work at my workplace. I only imported the msxml4.dll and we don't have msxml3.dll installed on our machines. So, the program did nothing.
I'll post the results. I am hopeful now that this was the problem
|
|
|
|
|
My main problem is that i currently dont understand how msxml.3 works. Im not familiar with it, but this article has helped me allot. If I had to I could break down the wrapper to see who msxml works. However, right now im just tring to get away with plug and play.
I need to parse an xml file that has a scheme and database like records at the bottom, it might resemble...
I used the included application to determine how to parse the tags i wanted, but it seems indirect. This is what im doing now...
<br />
void ParseNode(IDispatch *pNode)<br />
{<br />
CXmlNodeWrapper node(pNode);<br />
<br />
if (node.Name() == "row")<br />
{<br />
for (int i = 0; i < node.NumAttributes(); i++)<br />
{<br />
node.GetAttribName(i); <br />
node.GetAttribVal(i);<br />
<br />
}<br />
}<br />
<br />
for (int i = 0; i < node.NumNodes(); i++)<br />
{<br />
ParseNode( node.GetNode(i), szRec, szFileDate );<br />
}<br />
}<br />
And ild like to use the query function, but i cant seem to figure out how to use it. ie...
CXmlNodeWrapper nodeMode( xmlNode.FindNode("//RowsetSchema:row[@Type='Mode']") );
CXmlNodeWrapper nodeKeyr( xmlNode.FindNode("//RowsetSchema:row[@Type='Keyer']") );
CXmlNodeWrapper nodeC3 ( xmlNode.FindNode("//RowsetSchema:row[@Type='C3']") );
CXmlNodeWrapper nodeC4 ( xmlNode.FindNode("//RowsetSchema:row[@Type='C4']") );
So instead of recursivly looping, ild rather just query for each field in each record individually..
Im a little unsure of the syntax fo the FindNode parameter? I greatly appreciate any insight ^^
thx,
-SD
_____________________________________________________________________
〈xml xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882'
xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882'
xmlns:rs='urn:schemas-microsoft-com:rowset'
xmlns:z='#RowsetSchema'〉
〈s:Schema id='RowsetSchema'〉
〈s:ElementType name='row' content='eltOnly' rs:updatable='true'>
〈s:AttributeType name='SortMode' rs:number='1' rs:write='true'>
〈s:datatype dt:type='i1' dt:maxLength='1' rs:precision='0' rs:fixedlength='true' rs:maybenull='false'/〉
〈/s:AttributeType〉
〈s:AttributeType name='Mode' rs:number='2' rs:write='true'>
〈s:datatype dt:type='string' rs:dbtype='str' dt:maxLength='20' rs:precision='0' rs:fixedlength='true' rs:maybenull='false'/〉
〈/s:AttributeType〉
〈s:AttributeType name='Keyer' rs:number='3' rs:write='true'>
〈s:datatype dt:type='string' rs:dbtype='str' dt:maxLength='50' rs:precision='0' rs:fixedlength='true' rs:maybenull='false'/〉
〈/s:AttributeType〉
// ... and so on ....
〈/s:ElementType〉
〈/s:Schema〉
// and here would be the data in the file...
〈rs:data〉
〈rs:insert〉
〈z:row SortMode='11' Mode='COA ADDRESS' Keyer='We**, Ri***' c3='2:34:52' c4='0:00:19'/〉
〈z:row SortMode='10' Mode='COA NON ADDRESS' Keyer='Ti*****, So****' c3='3:37:43' c4='0:00:02'/〉
〈z:row SortMode='10' Mode='COA NON ADDRESS' Keyer='La****, ***cy ' c3='0:57:03' c4='0:00:01'/〉
〈/rs:insert〉
〈/rs:data〉
〈/xml〉
|
|
|
|
|
I got it, Basically , i just needed a way to loop through the records and pull the required fields. Here is what i turned up, course ill have to add it to the api.
<br />
void CXmlDocumentWrapper::Test()<br />
{<br />
long numitems;<br />
<br />
MSXML2::IXMLDOMNodeListPtr items = m_xmldoc->getElementsByTagName("z:row");<br />
<br />
items->get_length(&numitems);<br />
for (int i=0;i < numitems;i++)<br />
{<br />
MSXML2::IXMLDOMNodePtr item ;<br />
items->get_item(i, &item);<br />
_variant_t sz1 = item->attributes->getNamedItem("Mode")->GetnodeValue();<br />
_variant_t sz2 = item->attributes->getNamedItem("Keyer")->GetnodeValue();<br />
}<br />
printf("Found %f Records\n", numitems);<br />
}<br />
|
|
|
|
|
Look at the CXmlNodeListWrapper class, that is what you need,
also user CXmlNodeWrapper::FindNodes , wich returns a node list.
i.e : CXmlNodeListWrapper list(xmlNode.FindNodes("//Z:Row[@Type='sometype']");
Creative minds - create creative creations!
|
|
|
|
|
Hi again!
I might be off here but why does almost every function return a BOOL?
In the msxml3.tli (created by VC.NET from the #import) every call has a:
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
which throws a _com_error.
So dosent all functions either return TRUE or throw an exception? Or am I missing something elementary (I am not an expert in COM)?
/Aldus
P.s.
Good work with the XML wrapper!
D.s.
|
|
|
|