|
Hi, Mike
Realy great parser! Thanx for sharing sources
We found a litle problem here:
VARIANT_BOOL vBool = m_pIXMLDOMDocument->loadXML(inputStr);
in Windows98 this function (MSDN article) works just with 2 character sets (i suppose msxml.dll has an oldest version of this interface . And when i trying to parse CP-1251 encoded document, parser returns error (throw exception, but i do not remember it's description, something like "not supported charset encoding").
If i remove MSXML namespace whis MSXML2 (by defining it in precompiled header)
#define MSXML MSXML2
...it works, but... may be you know better solution?
|
|
|
|
|
Hello Alex.
Thank you for your comment.
My workaround: I am using utf-8 encoding in all my XML files.
Mike.
|
|
|
|
|
Hi Mike
Thanx by the share
Your code is fine (a little confusing but is fine)
Tip: The limitation of charsets is a big deal (I´m brazilian and, in my case, I need to use one charset different than you)
Maybe the low score can be given by the existence of more 'popular' xml libraries (Microsoft, dundas, ec ...)
I´m, in fact, using the microsoft parser to do this job with relative easy (and this library is common language in the work)
Woody
|
|
|
|
|
Hi Mike..
Thanx alot for your code..Am using it in an MFC phonebook application..everything was going great (using _DEBUG build) until i tried to run a release build. What happens is like this, when my application tries to save an XML doc to a file it crashes. I I tried to walk through the debug code of the CRT and found that memory alloc. is different for debug and release.
void ZXmlParserImpl::do_save()<br />
{<br />
m_proxy = new XMLPrivate::XmlParserProxySave(*this); <br />
m_document->determine(*m_proxy);
it crashes inside determine..in the release build the value of this changes while not in the debug build.By the way, there is no problem with the release built of the example code here. so i guess this is something to do with MFC headers. I'd appreciate it if you could check it and post a work-around.
Thanx alot..
Time is the best teacher; Unfortunately it kills all it's students!
|
|
|
|
|
Hi all,
It turns out that this problem is related to the compiler settings. This can be fixed by adding the /GR switch to the c/c++ settings in VC or ticking the Enable Run-Time Type Info. option. This is pretty tricky, i got no compile errors, no link errors and no clues in the error message when it crashes .
Hope this will save someone, somewhere, some time .
Time is the best teacher; Unfortunately it kills all it's students!
|
|
|
|
|
Hi ! Mike
I Like your code because I like templates
really great job !
but I've found that it is impossible to implement a 0 or more choice element in an XML file
that has this DTD
<!ELEMENT org ( group* | member*)*>
<!ATTLIST memeber
type (VIP | EXPERT | NORMAL | GUEST) #REQUIRED
name CDATA #REQUIRED
addr CDATA #IMPLIED
tel CDATA #REQUIRED
>
<!ELEMENT group ( group* | member*)*>
I found it difficult to do without changing your original code
any suggestion please
Bye
Sahbi
|
|
|
|
|
Hello Sahbi
I am sorry I can't understand the real problem.
can you send me small sample of xml file
and tell what part of it you can't read without modification of code (you can send me it by email)
Mike.
|
|
|
|
|
When add attributes to the first element, for example, in your sample, I add a attribute to pipeline, when parse, it will throw a exception.
I have use your code to my project, but I feel the code which isn't convenient, so I add some macro to my project to use your code.I think add some macro to your project, it will become friendly. for example #define XML_ELEMENT() ....
|
|
|
|
|
I want to get the string which already to save to file. How can I can that? Thanks!!
|
|
|
|
|
ZXmlParser::save has second optional parameter isFile, was not implemented in this article.
change function to this :
if (SUCCEEDED(createDocument()))
{
do_save();
if(isFile)
m_pIXMLDOMDocument->save(_variant_t(outputStr));
else
outputStr = m_pIXMLDOMDocument->Getxml();
m_pIXMLDOMDocument = 0;
}
Mike.
|
|
|
|
|
|
Hello
After fixing the memory leaks as John Kirk posted a few threads below, the map member of the Pipeline (Pipeline::m_map) stopped getting written to saved_test.xml.
The cause is the following change, from:
template <class T>
inline void determine(T& t,const char* str,XmlParserProxy& p,void*,common_t)
{
p.do_member(xmlproxy(t),str);
}
To:
template <class T>
inline void determine(T& t,const char* str,XmlParserProxy& p,void*,common_t)
{
XmlObject* pObj = new XMLPrivate::Value2<T>(t);
p.do_member(*pObj,str);
delete pObj;
}
I couldn't figure out why this happens, perhaps someone could help.
TIA,
Itay Szekely
http://come.to/itay
For every action, there is an equal and opposite criticism
|
|
|
|
|
Hi,
In the
void ZXmlParserImpl::do_save()
{
m_proxy = new XMLPrivate::XmlParserProxySave(*this);
m_document->determine(*m_proxy);
m_curnodes.clear();
}
how does m_document (a type of XmlObject) finds out its an object of type Document ? I think then the link is easy to figure out. Document ->
Pipeline.determineMember and then it calls determineMember of its other objects.
Even if the question is really dumb, pls do answer
Thanks.
|
|
|
|
|
it fails to handle xml header.
|
|
|
|
|
I think you are also using the same code in your 2Find toolbar. I think ppl(atleast me) arent commenting as we already have seen the code in 2Find toolbar
Great job dude!
Keep it up!!!
/Ram
|
|
|
|
|
Thanks, it's a good job !!
but there are many memory leaks in your app !!
Can you do something for this ??
thanks
|
|
|
|
|
There are a number of memory leaks dealing with bstr's (which I didn't take the time to track down and fix). However, many of the other leaks can be fixed by three simple changes:
Memory leak 1 (ZXmlParserImpl.h):
namespace XMLPrivate
{
. . .
class XmlParserProxyRead : public XmlParserProxy
{
virtual void do_attrib(const char* key, string& str)
{m_p.do_read_member(*(new Value2<string>(str)),key);}
// This method always allocates a new 'Value2<string>', but the new object
// is not always thrown. In fact, usually it is simply forgotten.
. . .
};
}
// Change to...
namespace XMLPrivate
{
. . .
class XmlParserProxyRead : public XmlParserProxy
{
virtual void do_attrib(const char* key, string& str)
{
XmlObject* pObj = new Value2<string>(str);
m_p.do_read_member(*pObj,key);
// If we made it to here, pObj was not thrown. Clean up.
delete pObj;
}
. . .
};
}
Memory leak 2 (ZXmlParserImpl.h):
inline XmlObject& xmlproxy(string &s) {return *(new XMLPrivate::Value2<string>(s));}
inline XmlObject& xmlproxy(int &i) {return *(new XMLPrivate::Value2<int>(i));}
inline XmlObject& xmlproxy(float &i) {return *(new XMLPrivate::Value2<float>(i));}
// ^ These functions always allocate a new object.
. . .
template <class T>
inline void determine(T& t,const char* str,XmlParserProxy& p,void*,common_t)
{
p.do_member(xmlproxy(t),str);
// ^ Always allocates a new XMLPrivate::Value2<> of some sort. If the
// new object is not thrown by p.do_member(), the object leaks.
}
class XmlParserProxyRead : public XmlParserProxy
{
. . .
virtual void do_member(XmlObject& t,const char* str) throw(XmlObject*)
{m_p.do_read_member(t,str);}
. . .
}
void ZXmlParserImpl::do_read_member(XmlObject& t,const char* str) throw(XmlObject*)
{
if(load()==str) // If this test is false, t leaks.
throw &t;
}
// Change to...
template <class T>
inline void determine(T& t,const char* str,XmlParserProxy& p,void*,common_t)
{
XmlObject* pObj = new XMLPrivate::Value2<T>(t);
p.do_member(*pObj,str);
// If we make it to here, pObj was not thrown. Clean up.
delete pObj;
}
Memory leak 3 (ZXmlParser.cpp):
void ZXmlParser::parse(const _bstr_t& strFileName, bool isFile)
{
XMLNode* hItemRoot = new XMLNode;
. . .
print(hItemRoot, "");
// ^ hItemRoot is allocated, but never freed.
}
// Change to...
void ZXmlParser::parse(const _bstr_t& strFileName, bool isFile)
{
XMLNode* hItemRoot = new XMLNode;
. . .
print(hItemRoot, "");
// Clean up.
delete hItemRoot;
}
I hope this helps
John Kirk
"Man - A figment of God's imagination" Mark Twain
|
|
|
|
|
Hi Mike,
What do u think about this changes???
|
|
|
|
|
Hey Mike:
Great job on the class. A couple questions/comments for you:
1. Personally, I really like third party classes to be in one .h file. I know it's somewhat... ugly when developing, but I hate having to put someone else's cpp files in my project... well, possibly a personal preference.
2. Will this class work if COM is initialized in Multithreaded mode? How about neutral?
3. I can't remember for sure, but I seem to recall reading in Effective STL that deriving from a container is a fairly bad idea... anyone else encountered this? I notice you're doing that with vector, just wondering if that might have bad consequences.
4. From what I understand of template specialization, you can't define a template function that takes a pointer, and then specialize it to take a base type. Indeed, when I compile your sample with VC.NET, it complains that it can't deduce the bool argument to _check from H* -- it's not picking up the specialization. I changed the H* to H, and tweaked your specialization so it now looks like this:
template<class H> inline bool _check(H hr)
{
return hr!=0;
}
template<> inline bool _check(bool hr)
{
return hr;
}
And that seems to work on VC.NET. (VC.NET supposadly implements more of the C++ standard than VC6... which would explain why VC6 would let it slide...)
Anyway, great job overall.
----------------------------------------
----I said my name wasn't important
---------------------------SlartiBartFast
|
|
|
|
|
Hello Eugene.
Sorry for delay. I just read your message
1. .h with .cpp
I guess that you put a lot of YOUR code in .cpp files and that is why don't like to see third party code there. You see, I put my code in .cpp
Without joke, it decreases compilation time.
2. Multithreaded mode
yes it is working in my 20 projects in Multithreaded mode. I don't make any CoInitialize in my "library" code.
3. deriving from a container
Yes is not good idea, but only for STL, I haven't read that book, but I think I will be near the author, because vector and etc. doesn't have virtual functions, may be some other issues. But I don't make any pointers to that vectors. You can use std::vector instead of vectordel, just don't forget to delete all stored pointers there.
4. typename in template
I wrote it to catch any pointer to a class , if _check(H ) work - very well.
Mike.
|
|
|
|
|
I really like your approach for XML processing.
However, in most cases I prefer std::list to std::vector , therefore I've made following additions to ZXmlParserImpl.h at the given positions:
line 175:
struct list_t{}; template <class T> list_t type(list<T>& ) {return list_t();}
line 260:
template <class T,typename NewT>
inline void determineList(list<T>& ls,const char* str,XmlParserProxy& p,NewT* _t, common_t t_)
{
if(p.isRead())
{
if(p.load()==str)
{
ls.push_back(T());
throw &xmlproxy(*ls.rbegin());
}
}
else
{
for (list<T>::iterator it = ls.begin (); it != ls.end(); ++it)
{
determine(*ls,str,p,_t,t_);
}
}
}
template <class T,typename NewT>
inline void determineList(list<T>& ls,const char* str,XmlParserProxy& p,NewT* _t,Object_t t_)
{
if(p.isRead())
{
if(p.load()==str)
{
NewT* node = new NewT();
ls.push_back(node);
throw node;
}
}
else
{
for (list<T>::iterator it = ls.begin (); it != ls.end(); ++it)
{
determine(*it,str,p,_t,ObjectPtr_t());
}
}
}
template <class T,typename NewT>
inline void determine(list<T>& ls,const char* str,XmlParserProxy& p,NewT* _t,list_t)
{
determineList(ls,str,p,_t,type(*_t));
}
Your usage of templates really facilitate the extension of your solution
Regards
Thomas
Sonork id: 100.10453 Thömmi
Disclaimer: Because of heavy processing requirements, we are currently using some of your unused brain capacity for backup processing. Please ignore any hallucinations, voices or unusual dreams you may experience. Please avoid concentration-intensive tasks until further notice. Thank you.
|
|
|
|
|
... just a bit more documentation would greatly enhance the use of your otherwise excellent implementation.
I think that its almost impossible for beginners to understand how and why it works.
Maybe you could add a more detailed and commented sample to your article?
cheers
Andreas
|
|
|
|
|
Thank you, Andreas
You are right.
Yes, I am planning to modify article (make some changes in sources and documentation) and give some more samples. Also I am planning to post one more article with a sample that will show real-life usage of my technology.
From another side, as I said in my article, I tried to simplify "clients" (programmers) work, that is why - "server" part (implementation) is enough complex.
Mike.
|
|
|
|
|
If u add some samples and improve a little the documentation ... It could beceome a great article!!!
I really hope u do it soon ´cause personally I do like the article.
|
|
|
|
|
I am using expat to read the xml files, this is my file
extern char **file(char *);
char html();
int index;
struct elementStruct
{
XML_Char elementData[9];
const XML_Char * elementArray;
const XML_Char ** elementAttr;
};
struct elementStruct EArray[3]={{NULL,"id",NULL},
{NULL,"number",NULL}, {NULL,"title",NULL}}
struct elementStruct EArray[3];
static void startElement(void *userData, const XML_Char *name, const XML_Char **atts){}
static void charHandler(void *userData, const char *s, int len){}
static void endElement(void *userData, const XML_Char *name){}
I can able to read the element name, and the all the data in order of xml file.
What I need is to able to read the element 'data' to pass through html form and display to the web using cgi.
Please help me with examle,
Thanks you very much
CD
cindy
|
|
|
|
|