Tinyxml2 append function - c++

I have been looking for a way to append my xml file using tinyxml2 but couldn't find anything. I would appreciate any help.
Here is my code:
function savedata() {
XMLNode * pRoot = xmlDoc.NewElement("Cars");
xmlDoc.InsertFirstChild(pRoot);
XMLElement * pElement = xmlDoc.NewElement("Brand");
pElement->SetText("Audi");
pRoot->InsertEndChild(pElement);
pElement = xmlDoc.NewElement("type");
pElement->SetText("4x4");
pRoot->InsertEndChild(pElement);
pElement = xmlDoc.NewElement("Date");
pElement->SetAttribute("day", 26);
pElement->SetAttribute("month", "April");
pElement->SetAttribute("Year", 2015);
pElement->SetAttribute("dateFormat", "26/04/2015");
pRoot->InsertEndChild(pElement);
XMLError eResult = xmlDoc.SaveFile("SavedData1.xml");
XMLCheckResult(eResult);
}
Everytime I run the function, the xml is overwritten and I want to append to the existing file.
My xml file:
<Cars>
<Brand>Audi</Brand>
<Whatever>anothercrap</Whatever>
<Date day="26" month="April" Year="2015" dateFormat="26/04/2015"/>
</Cars>
My root is and I want to append to the existing file. For example,
<Cars>
<Brand>Audi</Brand>
<type>4x4</type>
<Date day="26" month="April" Year="2015" dateFormat="26/04/2015"/>
<Brand>BMWM</Brand>
<type>truck</type>
<Date day="26" month="April" Year="2015" dateFormat="26/04/2015"/>
</Cars>

XML is structured data so a textual append would be tricky and possibly error-prone, as you would have to make sure you don't add the root node twice, and that you maintain indentation etc.
What might be easier is to load the XML, parse it with TinyXML, and write it back.

You can append if you use the FILE overload for xmldoc.Save.
FILE* file = fopen("myfile.xml","a");
xmlDoc.Save(file);
fclose(file);
You just have to be careful when doing this since it will mess up the doc if you're printing multiple root nodes. If you're doing this for logging purposes I would just leave out the root node entirely and just have whatever is reading the log back know to append them or just not even care about proper xml format.

Related

How to create a xml node using rapidxml

Hi I want to create the following xml file in C++ using rapidxml on Linux.
How to add an element which is of type name.
<wrapit>
<mainNode>
<name>something1</name>
</mainNode>
</wrapit>
what my code generates looks like following which I don't want.
<wrapit>
<mainNode>
<name something1=""/>
</mainNode>
</wrapit>
I could not find much information for this. Few on wordpress but the xml formats are different.
Code snippet
xml_node<>* root = doc.allocate_node(node_element, "mainNode");
doc.append_node(root);
xml_node<>* child = doc.allocate_node(node_element,"name");
child->append_attribute(doc.allocate_attribute("something1"));
root->append_node(child);
ugg....
xml_node<>* child = doc.allocate_node(node_element,"name","something1");
does it.

Add XML contained in string as XML nodes to existing pugixml tree

I have a configuration file saver/loader. In addition to the expected data, there is a <CustomData> node. When saving the node, we'd simply have a std::string _customData and add it to the node, like this:
pugi::xml_document doc;
pugi::xml_node config = doc.append_child("OurConfig");
// save custom data
pugi::xml_node customData = config.append_child("CustomData");
customData.append_child(pugi::node_pcdata).set_value(_customData);
Our _customData was base64 encoded XML. It is provided from another part of the application. It must be a string, since the other part of the application uses different programming language (C#). As you can imagine, that became annoying, because it wasn't human readable. First step to fix this was simply to get rid of base64 in the app that provides _customData. So now we have readable version, which looks like this:
<?xml version="1.0"?>
<OurConfig>
<CustomData><CfgRoot>
<SomeValue name="External setting for foo" value="Foo"/>
<SomeValue name="External setting for bar" value="Bar"/>
</CfgRoot></CustomData>
</OurConfig>
But it could probably improve if the custom data was directly appended to XML tree instead of as string value. How can I append XML string as XML and not as string to pugixml tree?
Ie. the output I'd like:
<?xml version="1.0"?>
<OurConfig>
<CustomData>
<CfgRoot>
<SomeValue name="External setting for foo" value="Foo"/>
<SomeValue name="External setting for bar" value="Bar"/>
</CfgRoot>
</CustomData>
</OurConfig>
In the docs, there are three methods listed. I used the first one, making a convenience function like this:
bool AppendXMLString(pugi::xml_node target, const std::string& srcString)
{
// parse XML string as document
pugi::xml_document doc;
if (!doc.load_buffer(srcString.c_str(), srcString.length()))
return false;
for (pugi::xml_node child = doc.first_child(); child; child = child.next_sibling())
target.append_copy(child);
return true;
}

How to add a line break to each XML node?

How can I add a line break to each XML child bode so the output looks formatted?
The template file contains <Faults> and </Faults> tags. Now I want to insert a line break inside this node.
C++ CODE:
_di_IXMLNode nodeFault = NULL;
IXMLNode *m_pRootNode = FormMain->GetBBReportTXMLDocPtr()->DocumentElement;
...
for(; it_Events != lstEvent.end(); it_Events++){
nodeFault = m_pRootNode->ChildNodes[EVENT_REPORT].Get(EXmlTagOrder::extoFaults)->AddChild("Fault");
nodeFault->Attributes[WideString("Entry")] = ((*it_Events).m_sEntry).c_str();
nodeFault->AddChild("Time")->Text = ((*it_Events).m_sTimeStamp).c_str();
nodeFault->AddChild("Code")->Text = ((*it_Events).m_sCode).c_str();
}
But I am not getting output with line breaks or formatting.
When I open the XML file in Notepad, all nodes are on a single line:
<Faults><Fault Entry="0"><Time>0</Time><Code>20</Code></Fault><Fault Entry="1"><Time>2</Time><Code>10</Code></Faults>
The XML file looks formatted when I open it in Internet Explorer instead:
<Faults>
<Fault Entry="0">
<Time>0</Time>
<Code>20</Code>
</Fault>
<Fault Entry="1">
<Time>2</Time>
<Code>10</Code>
</Fault>
</Faults>
How can I add a line break to each node so my final output file looks formatted when I open it in Notepad++?
You have to set some formatting options before saving to file.
In your specific case:
FormMain->GetBBReportTXMLDocPtr()->Options =
FormMain->GetBBReportTXMLDocPtr()->Options << doNodeAutoIndent
Look at the FormatXMLData() function:
Formats a string of XML so that it is more readable.
Use FormatXMLData to convert a string of XML into a format that represents its structure. FormatXMLData changes the input string (XMLData) so that each element node appears on its own line, indented appropriately to reflect its nesting in the node hierarchy.

XML Getting attibute value of a Node

I am using XML DOM API in C++ to parse an XML file. I can't find any method to get the attribute value in a node element.
For example, in the following xml
<test>
<fruit count="10">
...
...
</fruit>
<test>
I need to get the count string("10") using XML APIs. Can anybody help me with some code snippets.
Use DOM Parser API to get attribute value count.
Refer below sample code:
//code to perform some process for parsing the input file and get rootElement
DOMNodeList* fruitNodes= rootElement->getElementsByTagName(XMLString::transcode("fruit"));
DOMNode* node = fruitNodes->item(0);
DOMElement* fruitElement = dynamic_cast <xercesc::DOMElement*>(node);
const XMLCh* attrValue = fruitElement->getAttribute(XMLString::transcode("count"));
you can get value 10 from attrValue using: string(XMLString::transcode(attrValue))
Based on http://msdn.microsoft.com/en-us/library/windows/desktop/ms754523(v=vs.85).aspx
Try something like:
pXMLDomNodeList = pXMLDocElement->selectNodes("/test/fruit/#count");

MSXML node.clode method does not work as expected

Using the MSXML2 functions from the "msxml3.dll" library, I'm trying to duplicate sections in an XML document, but it does not work as I expected.
Here is the XML:
<result>
<Target>
<Point>
<pos dimension="2">60.384005 5.333862</pos>
</Point>
</Target>
</result>
What I want is to add multiple sections. So I want to take the node, duplicate it and put it under the existing <Target> node. I'm almost convinced I should use the Clone method, but it does not seem to work.
The C++ code:
typedef MSXML2::IXMLDOMNodePtr XmlNode;
XmlNode pNode = pXMLRequest->selectSingleNode("//result");
if(pNode==NULL)
{ m_szErrorText = m_szErrorText + _T(" 'result' node not found");return FALSE;}
XmlNode pTargetNode = pNode->selectSingleNode("Target");
XmlNode pNewTargetNode = pTargetNode->cloneNode(true);
pNode->appendChild(pNewTargetNode);
But when I run this code nothing happens to the XML document. And when I inspect the XML text in pNewTargetNode I see it is '<result>' only which is just the name of the node While I would expect it to contain all the nodes in <Target>...</Target>. Is there something I am missing ?
I used the wrong kind of 'true'.
If I replace
XmlNode pNewTargetNode = pTargetNode->cloneNode(true);
with
XmlNode pNewTargetNode = pTargetNode->cloneNode(VARIANT_TRUE);
it works fine. I had already thought about this and used TRUE instead of true, but that does not work either.
So when using the msxml library alsways use VARIANT_BOOL, VARIANT_FALSE and VARIANT_TRUE.
Raymond Chen explains why there are so many variations:
http://blogs.msdn.com/b/oldnewthing/archive/2004/12/22/329884.aspx