|
It's done!
Jonathan de Halleux, Belgium.
|
|
|
|
|
Great !
But the mentioned problem about the non-existent file being opened for reading still exists..
I handle this in my overloaded function Open()
Here is my code... Maybe it can be fixed in the next version
#include <io.h>
....
BOOL CD4WXMLFile::Open(LPCTSTR szFileName, BOOL bStoring , DWORD _dwMode )
{
if (!bStoring && _access(szFileName, 0) != 0) {
return FALSE;
}
BOOL bRet = (BOOL)CMarkupArchive::Open(szFileName, bStoring);
if (bRet && IsOpen()) {
SetModeFlag(_dwMode);
}
return bRet;
}
I'm sorry i did not post the fix earlier
Edit: <code> blocks doesn't understand whitespaces at the beginning very wel...
Also you need to include 'io.h' for the _acces() function
Albert van Peppen
|
|
|
|
|
Done.
I've added template to handle multiple types...
The question is: is it thread safe ?
Jonathan de Halleux, Belgium.
|
|
|
|
|
Hi,
Some points of notice:
- You forgot to implement the following function (both hdr and source):
bool FindGetData(LPCTSTR szName, long& _long)
{
bool found;
ResetPos();
found = FindElem(szName);
if (found)
_long = GetDataInt();
return found;
}
- I still need some extra functions (i use MFC so lots of CString and LPCTSTR), why don't you implement these as well? :
DWORD GetModeFlag() {return m_dwMode;};
bool AddElemEx(LPCTSTR szName, CString &str) {return AddElem(szName, str);}
bool AddElemEx(LPCTSTR szName, LPCTSTR lpctstr = "") {return AddElem(szName, lpctstr);}
bool AddChildElemEx(LPCTSTR szName, CString &str) {return AddChildElem(szName, str);}
bool AddChildElemEx(LPCTSTR szName, LPCTSTR lpctstr = "") {return AddChildElem(szName, lpctstr);}
bool AddAttribEx(LPCTSTR szName, CString &str) {return AddAttrib(szName, str);}
bool AddAttribEx(LPCTSTR szName, LPCTSTR lpctstr) {return AddAttrib(szName, lpctstr);}
bool AddChildAttribEx(LPCTSTR szName, CString &str) {return AddChildAttrib(szName, str);}
bool AddChildAttribEx(LPCTSTR szName, LPCTSTR lpctstr) {return AddChildAttrib(szName, lpctstr);}
Albert
PS I didn't test (yet) to see if it is thread safe. I don't need that (yet)
EDIT: Removed a remark... I looked with my nose (as they say in the Netherlands )
|
|
|
|
|
Hi (again),
Another remark
I transferring all my XML strings through CMarkupArchive now as well. While implementing this i came across the following:
In the CMarkupArchive::Close() function you should check m_sFileName == _T("")..
If so and m_bOpened is true (you already checked that ) then it is likely that a sting was opened using OpenString() but the mode can be set to Storing.. In this case you don't want to write to a file and you might as well skip that part
Albert van Peppen
|
|
|
|
|
Hi,
In MarkupArchive.h I found something odd...
In the 'FindGetData(...)' functions a 'ResetChildPos()' is called, prior to a call to 'FindElem(...)'
I think that you need to call 'ResetPos()' instead of 'ResetChildPos()'...
Can that be true?
I also need to read/write XML in the utf-8 character set, but in CMarkupArchive you have hardcoded the use of ISO-8859-1 Isn't it an idea to use a SetCharacterSet(...) (or something like that) function?? If you want to do it correctly you even cenvert special characters in the data accourdingly But this has no prio for me
Greetings,
Albert van Peppen
|
|
|
|
|
Hi,
Is it possible to find data which has a specified attribute defined, regardless the value of this attribute?
My XML code looks like this for example:
<br />
<RELATIONS><br />
<br />
<RELATION DebtorNr="1300"><br />
<NAME>Great customer</NAME><br />
... cutted out here ...<br />
</RELATION><br />
<br />
<RELATION CredNr="2991"><br />
<NAME>QWERTY Keyboards</NAME><br />
... cutted out here ...<br />
</RELATION><br />
<br />
</RELATIONS><br />
Now i wanna scan for all <relation> data which have the DebtorNr attribute set (to any value)...
Do i really need to scan the entire document myself and check the attributes?
Is there no other, easier way???
If not so, then i have to write my own function... (Can also be put here for anyones enjoyment )
Greetings,
Albert van Peppen
EDIT: Fixed the code so you can read the XML data
|
|
|
|
|
Due to a bug in FindElemAttrib(..) it already does it... But the bug is that the value is never checked
So when solved, my code fails...
Maybe it is possible to make it possible to pass NULL as value parameter, and then just check the existenz of the attribute...
This should be done in the FindChildElemAttrib as well than (there the value is checked ok )
Greetings,
Albert van Peppen
EDIT: Some stupid typos...
|
|
|
|
|
Hi,
In order to let the above work i have made some changes in the following functions:
Changes in FindElemAttrib(...)
<br />
.....<br />
BOOL bGotIt;
while ( iPos )<br />
{<br />
bGotIt = (x_GetTagName(iPos) == m_sNameSpace+szName);<br />
if (bGotIt && szAttribValue == NULL) {<br />
bGotIt = x_GetAttrib(iPos, szAttrib) != "";
}<br />
else {<br />
bGotIt = (x_GetAttrib(iPos, szAttrib) == szAttribValue);<br />
}<br />
if (bGotIt)<br />
{<br />
.....<br />
Changes in FindChildElemAttrib(...)
<br />
.....<br />
BOOL bGotIt;
while ( iPosChild )<br />
{<br />
bGotIt = (x_GetTagName(iPosChild) == m_sNameSpace+szName);<br />
if (bGotIt && szAttribValue == NULL) {<br />
bGotIt = x_GetAttrib(iPosChild, szAttrib) != "";
}<br />
else {<br />
bGotIt = (x_GetAttrib(iPosChild, szAttrib) == szAttribValue);<br />
}<br />
if (bGotIt)<br />
{<br />
.....<br />
I hope this was a good idea, please don't let the author be angry with me .
If there is another way, please let me know..
Greetings,
Albert van Peppen
PS It also fixes the mentioned bug, nor do the functions crash when a NULL is passed as value (like it did before )
|
|
|
|
|
I'll have a look at all your message and, for sure, post an update...
Jonathan de Halleux, Belgium.
|
|
|
|
|
Great extension, but since i am lazy, i've added the following functions to your class:
bool AddElemEx(LPCTSTR szName, CString &str) {return AddElem(szName, str);}<br />
bool AddElemEx(LPCTSTR szName, LPCTSTR lpctstr = "") {return AddElem(szName, lpctstr);}<br />
bool AddElemEx(LPCTSTR szName, bool _bool) {return AddElemBool(szName, _bool);}<br />
bool AddElemEx(LPCTSTR szName, int _int) { return AddElemInt(szName, _int);}<br />
bool AddElemEx(LPCTSTR szName, UINT _UINT) { return AddElemUINT(szName, _UINT);}<br />
bool AddElemEx(LPCTSTR szName, DWORD _DWORD) { return AddElemDWORD(szName, _DWORD);}<br />
bool AddElemEx(LPCTSTR szName, long _long) { return AddElemLong(szName, _long);}<br />
bool AddElemEx(LPCTSTR szName, float _float) { return AddElemFloat(szName, _float);}<br />
bool AddElemEx(LPCTSTR szName, double _double) { return AddElemDouble(szName, _double);}<br />
bool AddElemEx(LPCTSTR szName, const std::vector<double>& _v) { return AddElemVectorDouble(szName, _v);}<br />
<br />
bool AddChildElemEx(LPCTSTR szName, CString &str) {return AddChildElem(szName, str);}<br />
bool AddChildElemEx(LPCTSTR szName, LPCTSTR lpctstr = "") {return AddChildElem(szName, lpctstr);}<br />
bool AddChildElemEx(LPCTSTR szName, bool _bool) {return AddChildElemBool(szName, _bool);}<br />
bool AddChildElemEx(LPCTSTR szName, int _int) { return AddChildElemInt(szName, _int);}<br />
bool AddChildElemEx(LPCTSTR szName, UINT _UINT) { return AddChildElemUINT(szName, _UINT);}<br />
bool AddChildElemEx(LPCTSTR szName, DWORD _DWORD) { return AddChildElemDWORD(szName, _DWORD);}<br />
bool AddChildElemEx(LPCTSTR szName, long _long) { return AddChildElemLong(szName, _long);}<br />
bool AddChildElemEx(LPCTSTR szName, float _float) { return AddChildElemFloat(szName, _float);}<br />
bool AddChildElemEx(LPCTSTR szName, double _double) { return AddChildElemDouble(szName, _double);}<br />
bool AddChildElemEx(LPCTSTR szName, const std::vector<double>& _v) { return AddChildElemVectorDouble(szName, _v);}<br />
<br />
bool AddAttribEx(LPCTSTR szName, CString &str) {return AddAttrib(szName, str);}<br />
bool AddAttribEx(LPCTSTR szName, LPCTSTR lpctstr) {return AddAttrib(szName, lpctstr);}<br />
bool AddAttribEx(LPCTSTR szName, bool _bool) {return AddAttribBool(szName, _bool);}<br />
bool AddAttribEx(LPCTSTR szName, int _int) { return AddAttribInt(szName, _int);}<br />
bool AddAttribEx(LPCTSTR szName, UINT _UINT) { return AddAttribUINT(szName, _UINT);}<br />
bool AddAttribEx(LPCTSTR szName, DWORD _DWORD) { return AddAttribDWORD(szName, _DWORD);}<br />
bool AddAttribEx(LPCTSTR szName, long _long) { return AddAttribLong(szName, _long);}<br />
bool AddAttribEx(LPCTSTR szName, float _float) { return AddAttribFloat(szName, _float);}<br />
bool AddAttribEx(LPCTSTR szName, double _double) { return AddAttribDouble(szName, _double);}<br />
bool AddAttribEx(LPCTSTR szName, const std::vector<double>& _v) { return AddAttribVectorDouble(szName, _v);}<br />
<br />
bool AddChildAttribEx(LPCTSTR szName, CString &str) {return AddChildAttrib(szName, str);}<br />
bool AddChildAttribEx(LPCTSTR szName, LPCTSTR lpctstr) {return AddChildAttrib(szName, lpctstr);}<br />
bool AddChildAttribEx(LPCTSTR szName, bool _bool) {return AddChildAttribBool(szName, _bool);}<br />
bool AddChildAttribEx(LPCTSTR szName, int _int) { return AddChildAttribInt(szName, _int);}<br />
bool AddChildAttribEx(LPCTSTR szName, UINT _UINT) { return AddChildAttribUINT(szName, _UINT);}<br />
bool AddChildAttribEx(LPCTSTR szName, DWORD _DWORD) { return AddChildAttribDWORD(szName, _DWORD);}<br />
bool AddChildAttribEx(LPCTSTR szName, long _long) { return AddChildAttribLong(szName, _long);}<br />
bool AddChildAttribEx(LPCTSTR szName, float _float) { return AddChildAttribFloat(szName, _float);}<br />
bool AddChildAttribEx(LPCTSTR szName, double _double) { return AddChildAttribDouble(szName, _double);}<br />
bool AddChildAttribEx(LPCTSTR szName, const std::vector<double>& _v) { return AddChildAttribVectorDouble(szName, _v);}<br />
This way you don't have to bother what function to use for your vars... It's just a simple extension It saves some time thinking... Just use the ...Ex function and it doesn't care what type your var is
Note that you can add elements and childitems without data (very short adding tags ) But if it is usefull?? It is easy for testing: Export all possible items an try them on import
Greetings,
Albert van Peppen
|
|
|
|
|
I'll update the source soon...
Jonathan de Halleux, Belgium.
|
|
|
|
|
Great work. Just what I needed for my project, as I was going to have to do this anyway.
Could you please explain how to replace the Serialize(CArchive& ar) with CMarkupArchive? Maybe you have a better idea.
At this point, the file is already open, so I don't think the Open and Close methods won't work correctly. I've been digging into the Document code trying to find where the CArchive gets opened. It appears instead of calling this code:
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
I would have to duplicate that method within myDocument::OnOpenDocument, using CMarkupArchive.
|
|
|
|
|
Sounds difficult, CMarkupArchive is not inherited from CArchive and
overriding << or >> doesn't make sense for XML. What I do is ged rid of CArchive.
Here's my typical "Serialize" function:
class A;
class A: public B;
...
void B::SerializeXML( CMarkupArchive& xml)
{
static const TCHAR szTag[] = _T("B");
if(xml.IsStoring())
{
xml.AddChildElem(szTag);
xml.IntoElem();
A::SerializeXML(xml);
...
xml.OutOfElem();
}
else
{
if (!xml.FindChildElemAttrib(szTag,_T("Name"),GetName()))
return;
xml.IntoElem();
A::SerializeXML(xml);
...
xml.OutOfElem();
}
}
I don't know if I really understood your question ???
Jonathan de Halleux, Belgium.
|
|
|
|
|
I figured it out.
I copied the CDocument::OnOpenDocument code into my document class' OnOpenDocument class, and replaced CArchive with CMarkupArchive. I also changed the Serialize parameter.
BOOL CAMIDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
CString temp = lpszPathName;
int index = temp.ReverseFind('\\');
m_sProjectName = temp.Right(temp.GetLength() - index - 1);
m_pMain->m_pFrame->OnUpdateFrameTitle(TRUE);
UpdateAllViews(NULL);
SetModifiedFlag(FALSE);
ReloadLegend();
RestoreAppPath();
// copy of CDocument code instead of calling it
CFileException fe;
CMarkupArchive saveArchive(EArchiveModeNotZipped);
TRY
{
CWaitCursor wait;
if (saveArchive.Open(lpszPathName, TRUE))
Serialize(saveArchive); // save me
saveArchive.Close();
}
CATCH_ALL(e)
{
TRY
{
ReportSaveLoadException(lpszPathName, e,
TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
}
END_TRY
e->Delete();
return FALSE;
}
END_CATCH_ALL
SetModifiedFlag(FALSE); // back to unmodified
return TRUE; // success
}
void CAMIDoc::Serialize(CMarkupArchive& ar)
{
if (ar.IsStoring())
{
...
ar.AddElem("PROJECT");
version = 5.0;
ar.AddChildElemDouble("VERSION", version); // application version number
ar.AddChildElem("AUTHOR", (LPCTSTR)m_pApp->m_sUserID);
ar.AddChildElem("TITLE", m_sProjectName);
}
Now the document behaviour is (almost) the same as normal.
|
|
|
|
|
Cool.
Now think about this one:
Could someone design a new class CMarkupArchiveXSD that would generate the xml schema out of the same code...
- would this need a lot of redesign ?
- is-it useful anyway ?
Jonathan de Halleux, Belgium.
|
|
|
|
|
I, for one, would love to have an XML code generator (for VC++). I've worked on generators for Unix C, but have no experience with STL.
My Serialize is gonna be a monster, as my document stores over 40 Objects (from BOOL to CArray<...>). Now that I'm using XML, I'm going to have to wrap some of them and write Serialize for each.
If I could wrap it up in one object, and just << the whole thing, wonderful.
|
|
|
|
|
You mean a parser that scans your class definition and generates a serialize function ?
Jonathan de Halleux, Belgium.
|
|
|
|
|
Exactly.
|
|
|
|
|
that is very wonderful!it does save me a lot of time,thanks!
however ,how can I serialize my special Class.Such as:
class A
{
...
coblist Bset//which contains lots objects of the Class B
CStringArray Cset ////which contains lots objects of the Class C
}
Class B
{
....
}
class C{....}
can you help me ?
best regards!thanks!!!
my emailis : fesco_h@hotmail.com
fesco,a student coming from chian who studing mathematics
|
|
|
|
|
The easy way:
Write a SerializeXML(CMarkupArchive& ar) similar to MFC Serialize(CArchive& ar) for each class B,C,A.
For A, you will need to serialize each container or derive a CObListXML container with the SerializeXML feature
Jonathan de Halleux, Belgium.
|
|
|
|
|
i am very surprise and grateful for your help so soon!thanks!
I have writed the Serializexml() for each B ,C,A.
however,how can I write Serializexml() about each container!
|
|
|
|
|
hello,
I try to write the SerializeXML(CMarkupArchive& ar) in the container Coblist,but when compiling,it says that no CMarkupArchive ,then I add the namespace markup, while,it still doesn't recgnize the namespace and class CMarkupArchive. I then add the "include MarkupArihive.h"
at the head of that file.the rusult is a disaster!it display lots errors .help me!
class CKnowledgeDB
{ ...
Coblist Bsets;
...
void CKnowledgeDB::Serialize(CMarkupArchive& ar)
{
...
Bset.Serialize(ar);
...
}
}
"afxcoll.h" :
include "MarkupArchive.h"//I add this sentence to the file.then it displays lots errors!
using namespace markup;
public:
void Serialize(CMarkupArchive&);
}
"list_o.cpp":
...
void CObList::Serialize(CMarkupArchive& ar)
{
if (ar.IsStoring())
{
for (CNode* pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
{pNode.Serialize(ar);
}
}
}
//I don't know how to write the function serialize(cmarkuparchive&).
Best Regards!
|
|
|
|
|
Check it!
Best regards,
Paul.
Paul Selormey, Bsc (Elect Eng), MSc (Mobile Communication) is currently Windows open source developer in Japan.
|
|
|
|
|
Ooops.
Jonathan de Halleux, Belgium.
|
|
|
|
|