Search code examples
c++xmltinyxml

TinyXML2 - insert element in middle of XML


I'm looking to add new elements with data to the middle of my XML structure. How can I append them where I need them?

Current code:

XMLElement *node = doc.NewElement("timeStamp");
XMLText *text = doc.NewText("new time data");
node->LinkEndChild(text);
doc.FirstChildElement("homeML")->FirstChildElement("mobileDevice")->FirstChildElement("event")->LinkEndChild(node);
doc.SaveFile("homeML.xml"); 

And an example part of my XML structure:

<mobileDevice>
    <mDeviceID/>
    <deviceDescription/>
    <units/>
    <devicePlacement/>
    <quantisationResolution/>
    <realTimeInformation>
        <runID/>
        <sampleRate/>
        <startTimeStamp/>
        <endTimeStamp/>
        <data/>
    </realTimeInformation>
    <event>
        <mEventID/>
        <timeStamp/>
        <data/>
        <support/>
    </event>
</mobileDevice>

I'm looking to add it addtional timeStamp tags under mobileDevice->event between mEventID and data, at the moment they are being appended after the support tag how can I get them to be entered in the correct place?

Current placement when ran:

<mobileDevice>
    <mDeviceID/>
    <deviceDescription/>
    <units/>
    <devicePlacement/>
    <quantisationResolution/>
    <realTimeInformation>
        <runID/>
        <sampleRate/>
        <startTimeStamp/>
        <endTimeStamp/>
        <data/>
    </realTimeInformation>
    <event>
        <mEventID/>
        <timeStamp/>
        <data/>
        <support/>
        <timeStamp>new time data</timeStamp>
    </event>
</mobileDevice>

Solution

  • You want to use InsertAfterChild() to do this. Here's an example which should do what you want (assuming that "mobileDevice" is your document's root element):

    // Get the 'root' node
    XMLElement * pRoot = doc.FirstChildElement("mobileDevice");
    
    // Get the 'event' node
    XMLElement * pEvent = pRoot->FirstChildElement("event");
    
    // This is to store the element after which we will insert the new 'timeStamp'
    XMLElement * pPrecedent = nullptr;
    
    // Get the _first_ location immediately before where
    //     a 'timeStamp' element should be placed
    XMLElement * pIter = pEvent->FirstChildElement("mEventID");
    
    // Loop through children of 'event' & find the last 'timeStamp' element
    while (pIter != nullptr)
    {
        // Store pIter as the best known location for the new 'timeStamp'
        pPrecedent = pIter;
    
        // Attempt to find the next 'timeStamp' element
        pIter = pIter->NextSiblingElement("timeStamp");
    }
    
    if (pPrecedent != nullptr)
    {
        // Build your new 'timeStamp' element,
        XMLElement * pNewTimeStamp = xmlDoc.NewElement("timeStamp");
        pNewTimeStamp->SetText("Your data here");
    
        // ..and insert it to the event element like this:
        pEvent->InsertAfterChild(pPrecedent, pNewTimeStamp);
    }
    

    This is an interesting and probably common use case. I wrote a TinyXML2 tutorial a couple of months ago, so I'll add this to it.