#37 TiXmlNode Addition

open
None
7
2005-06-07
2005-06-07
No

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:\&lt;/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:\&lt;/Working>
<Temp>D:\_Temp</Temp>
</Folders>
</Use>
</Prefs>
</Settings>

Discussion

  • Arlen Keshabyan

    Arlen Keshabyan - 2005-06-07
    • assigned_to: nobody --> leethomason
     
  • Arlen Keshabyan

    Arlen Keshabyan - 2005-06-07
    • priority: 5 --> 7
     
  • Arlen Keshabyan

    Arlen Keshabyan - 2005-06-07

    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:\&lt;/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:\&lt;/Working>
    <Temp>D:\_Temp</Temp>
    </Folders>
    </Use>
    </Prefs>
    </Settings>

     
  • Nobody/Anonymous

    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

     
  • Tim Sylvester

    Tim Sylvester - 2007-04-03

    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.

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

JavaScript is required for this form.





No, thanks