Please, pay some of your attension to this:
///////tinyxml.h (to the XiXmlNode class declaration)
///Arlen Albert Keshabian addons: gets the node/element
a path points to
virtual TiXmlNode *NodeFromPath(const char *sPath, char
chSeparator = '.') const;
virtual TiXmlElement *ElementFromPath(const char
*sPath, char chSeparator = '.') const
{
TiXmlNode *l_pNode = NodeFromPath(sPath, chSeparator);
return (l_pNode) ? l_pNode->ToElement() : NULL;
}
#ifdef TIXML_USE_STL
virtual TiXmlNode *NodeFromPath( const std::string&
sPath, char chSeparator = '.') const {return
NodeFromPath(sPath.c_str(), chSeparator);}
virtual TiXmlElement *ElementFromPath( const
std::string& sPath, char chSeparator = '.') const
{return ElementFromPath(sPath.c_str(), chSeparator);}
#endif
//////////////////////////////////////////////////////////////////////////
///////tinyxml.cpp (do not forget to #include <tchar.h>)
TiXmlNode *TiXmlNode::NodeFromPath(const char *sPath,
char chSeparator) const
{
if(!firstChild || !sPath)
return NULL;
char *l_psStartPos = const_cast<char*>(sPath);
char *l_psEndPos = _tcschr(l_psStartPos, chSeparator);
char *l_psSubString = NULL;
int l_iLength = 0;
const TiXmlNode *l_pNode = NULL;
while(l_psEndPos)
{
l_iLength = l_psEndPos - l_psStartPos;
l_psSubString = new char[l_iLength + 1];
_tcsncpy(l_psSubString, l_psStartPos, l_iLength);
l_psSubString[l_iLength] = 0;
l_pNode = (l_pNode) ?
l_pNode->FirstChild(l_psSubString) :
FirstChild(l_psSubString);
delete[] l_psSubString;
if(!l_pNode)
return NULL;
l_psStartPos = l_psEndPos + 1;
l_psEndPos = _tcschr(l_psStartPos, chSeparator);
}
return const_cast<TiXmlNode*>((l_pNode) ?
l_pNode->FirstChild(l_psStartPos) :
FirstChild(l_psStartPos));
}
///////////////////////////////////////////////////////////////////////////
/////// an example code
TiXmlDocument doc1( "config.xml" );
if(doc1.LoadFile())
{
TiXmlElement* FastElement =
doc1.ElementFromPath("Settings.General");
TiXmlElement* FastElement2 =
FastElement->ElementFromPath("Folders.Temp");
MessageBox(NULL,
FastElement2->FirstChild()->ToText()->Value(), NULL, 0);
}
///////////////////////////////////////////////////////////////////////////
/////// an example XML file
<?xml version="1.0" standalone="no" ?>
<Header app="MyApplication" version="1.5"/>
<Settings>
<General updated="07.06.2005">
<Folders>
<System>C:\Windows</System>
<Working>C:\</Working>
<Temp>C:\Temp</Temp>
</Folders>
</General>
<Prefs name="Arlen">
<Use referto="General"/>
</Prefs>
<Prefs name="Joe">
<Use referto="this">
<Folders>
<System>D:\WinXP</System>
<Working>D:\</Working>
<Temp>D:\_Temp</Temp>
</Folders>
</Use>
</Prefs>
</Settings>
Logged In: YES
user_id=212370
Please, pay some of your attension to this:
///////tinyxml.h (to the XiXmlNode class declaration)
///Arlen Albert Keshabian addons: gets the node/element
a path points to
virtual TiXmlNode *NodeFromPath(const char *sPath, char
chSeparator = '.') const;
virtual TiXmlElement *ElementFromPath(const char
*sPath, char chSeparator = '.') const
{
TiXmlNode *l_pNode = NodeFromPath(sPath, chSeparator);
return (l_pNode) ? l_pNode->ToElement() : NULL;
}
#ifdef TIXML_USE_STL
virtual TiXmlNode *NodeFromPath( const std::string&
sPath, char chSeparator = '.') const {return
NodeFromPath(sPath.c_str(), chSeparator);}
virtual TiXmlElement *ElementFromPath( const
std::string& sPath, char chSeparator = '.') const
{return ElementFromPath(sPath.c_str(), chSeparator);}
#endif
//////////////////////////////////////////////////////////////////////////
///////tinyxml.cpp (do not forget to #include <tchar.h>)
TiXmlNode *TiXmlNode::NodeFromPath(const char *sPath,
char chSeparator) const
{
if(!firstChild || !sPath)
return NULL;
const char *l_psStartPos = sPath;
const char *l_psEndPos = _tcschr(l_psStartPos, chSeparator);
char *l_psSubString = NULL;
int l_iLength = 0;
const TiXmlNode *l_pNode = NULL;
while(l_psEndPos)
{
l_iLength = l_psEndPos - l_psStartPos;
l_psSubString = new char[l_iLength + 1];
_tcsncpy(l_psSubString, l_psStartPos, l_iLength);
l_psSubString[l_iLength] = 0;
l_pNode = (l_pNode) ?
l_pNode->FirstChild(l_psSubString) :
FirstChild(l_psSubString);
delete[] l_psSubString;
if(!l_pNode)
return NULL;
l_psStartPos = l_psEndPos + 1;
l_psEndPos = _tcschr(l_psStartPos, chSeparator);
}
return const_cast<TiXmlNode*>((l_pNode) ?
l_pNode->FirstChild(l_psStartPos) :
FirstChild(l_psStartPos));
}
///////////////////////////////////////////////////////////////////////////
/////// an example code
TiXmlDocument doc1( "config.xml" );
if(doc1.LoadFile())
{
TiXmlElement* FastElement =
doc1.ElementFromPath("Settings.General");
TiXmlElement* FastElement2 =
FastElement->ElementFromPath("Folders.Temp");
MessageBox(NULL,
FastElement2->FirstChild()->ToText()->Value(), NULL, 0);
}
///////////////////////////////////////////////////////////////////////////
/////// an example XML file
<?xml version="1.0" standalone="no" ?>
<Header app="MyApplication" version="1.5"/>
<Settings>
<General updated="07.06.2005">
<Folders>
<System>C:\Windows</System>
<Working>C:\</Working>
<Temp>C:\Temp</Temp>
</Folders>
</General>
<Prefs name="Arlen">
<Use referto="General"/>
</Prefs>
<Prefs name="Joe">
<Use referto="this">
<Folders>
<System>D:\WinXP</System>
<Working>D:\</Working>
<Temp>D:\_Temp</Temp>
</Folders>
</Use>
</Prefs>
</Settings>
Logged In: NO
Please support also relative and absolute paths as in
various file systems. i.e:
FastElement->ElementFromPath("Folders/Temp") //relative to
previous doc1.ElementFromPath call
FastElement->ElementFromPath("/Settings/Prefs") //absolute
path no matter how is the current doc1.ElementFromPath path set
Logged In: YES
user_id=1296012
Originator: NO
Just my $.02:
I think it would be best to support a subset of XPath syntax and not invent a new syntax. I'm currently using a custom external class to do exactly that. A full XPath implementation is quite complex (requiring a full LR parser, I believe) but a simple subset such as "x[1]/y[a=b]/@z" is quite useful and relatively easy to implement. Introducing another syntax for accomlpishing exactly the same goal (if I understand correctly what you're describing) seems like a bad idea.
Unfortunately, since attributes are not nodes, this is somewhat complicated in the case of an attribute selector like "@z" above, so it might be best to leave that out for now.
If you're interested in the XPath code that I mentioned, let me know and I'll check what I developed it for. (i.e., what it's license is). Also note that there's a project called TinyXPath that implements (almost) full XPath syntax, but it's not very mature or clean as it unnecessarily modifies the XML document during processing.
I would also recommend separating this functionality from the Node/Element classes, similar to the way that the read/write/stream code was recently separated. This will help prevent the core XML classes from becoming too crowded and will allow the "path" code to be included only if it's needed.