0

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>
Colin747
  • 4,955
  • 18
  • 70
  • 118

1 Answers1

3

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.

GameDev
  • 136
  • 2
  • 6
  • Thanks that worked, I had to change a line as it was giving an error. `pNewTimeStamp.SetText("Your data here");` was changed too `pNewTimeStamp->SetText("Your data here");` – Colin747 Aug 05 '14 at 09:20
  • 1
    Ahh, good catch. :) I've been buried in Unity/C# for the last few months using `.` in place of C++'s `->`, and typed out the above code on the fly without actually testing it. The code snippet above has been updated. Thanks! :) – GameDev Aug 07 '14 at 08:37