How do I create child elements using msxml parser? - c++

I have a users.xml
<?xml version="1.0"?>
<Data>
<Users>
<User name="xyz" email="xyz#xyz.com">
<Tasks/>
</User>
</Users>
</Data>
I have got a reference to Users element using the following code
IXMLDOMDocumentPtr pXMLDom;
// code to load the xml dox
IXMLDOMElementPtr pXMLDocElement = NULL;
IXMLDOMNodeListPtr pXMLUsers = NULL;
//gets <Data>
pXMLDocElement = pXMLDom->GetdocumentElement();
//gets <Users>
pXMLUsers = pXMLDocElement->childNodes;
Now how do I create a child element User in Users element.
I have tried using createElement() on pXMLUsers, but it says IXMLDOMNodeListPtr has no member appendChild.
I don't know how to create a new element.
Thanks.

You cannot use the IXMLDOMNodeListPtr to append a child - it's just for iterating existing children.
You can use the IXMLDOMElementPtr directly to call pXMLDocElement->appendChild() to add a child element in your Document.

Ok, I've found a solution, thanks to TERACytE
IXMLDOMDocumentPtr pXMLDom;
// code to load the xml dox
//Creating <User>
MSXML2::IXMLDOMElementPtr pUser = pXMLDom->createNode(NODE_ELEMENT, "User", "");
//Creating <User name="">
MSXML2::IXMLDOMAttributePtr pName = pXMLDom->createAttribute("name");
pName->value = name;
//Creating <User email="">
MSXML2::IXMLDOMAttributePtr pEmail = pXMLDom->createAttribute("email");
pEmail->value = email;
//Adding name attrib to <User>
pUser->setAttributeNode(pName);
//Adding email attrib to <User>
pUser->setAttributeNode(pEmail);
//Creating <Tasks>
MSXML2::IXMLDOMElementPtr pTasks = pXMLDom->createNode(NODE_ELEMENT, "Tasks", "");
//Creating <Task>
MSXML2::IXMLDOMElementPtr pTask = pXMLDom->createNode(NODE_ELEMENT, "Task", "");
//Creating <Task name="">
MSXML2::IXMLDOMAttributePtr pTName = pXMLDom->createAttribute("name");
pTName->value = task;
//Creating <User status="">
MSXML2::IXMLDOMAttributePtr pStatus = pXMLDom->createAttribute("status");
pStatus->value = status;
//Adding name attrib to <User>
pTask->setAttributeNode(pTName);
//Adding status attrib to <User>
pTask->setAttributeNode(pStatus);
//Adding <Task> to <Tasks>
pTasks->appendChild(pTask);
//Adding <Tasks> to <User>
pUser->appendChild(pTasks);
//Selecting <Users>
MSXML2::IXMLDOMNodePtr pUsers = pXMLDom->selectSingleNode("/Data/Users");
//Adding <User> to <Users>
pUsers->appendChild(pUser);

Related

C++ Pugixml get children of parent by attribute id

For example:
<levels>
<level id="1">
<somestuff></somestuff>
</level>
<level id="2">
<somestuff></somestuff>
</level>
</levels>
How do you get the data of level with id 1?
Now i am using pugi::xml_node level = levels.child("level") But that return all levels..
Regards,
GJJ
levels.find_child_by_attribute("level", "id", "1")
Try it:
for (pugi::xml_node ambil = doc.child("levels").child("level"); ambil; ambil = ambil.next_sibling("level"))
{
int id = ambil.attribute("id").as_int();
CCLog("%d",id);
}
foreach children & compare attribute value.
e.g.
for (const auto& node : levels.children("level"))
{
if (node.attribute("id").as_int() == 1)
{
// TODO: add ur code here
}
}

pass xml variable into c# method in xslt

i have xslt transform where im using c# code to save input and output xml to database.
but it saves only the values of all tags.
but i want to save vhole xml.
<msxsl:script language="CSharp" implements-prefix="ConnectDatabase">
<msxsl:assembly name = "System.Data"/>
<msxsl:using namespace = "System.Data"/>
<msxsl:using namespace = "System.Data.SqlClient"/>
<msxsl:using namespace = "System.Collections.Generic"/>
<![CDATA[
public void LogINOUT(string inputxml, string outputxml)
{
SqlCommand cmd = null;
string command = "INSERT INTO dbo.XsltLog (InputXml,OutputXml) VALUES (#inputxmlpar,#outputxmlpar)";
string connectionString ="Data Source=MyConneCtionStiring;
SqlParameter inputxmlpar = new SqlParameter("#inputxmlpar", SqlDbType.NVarChar);
inputxmlpar.Value=inputxml;
SqlParameter outputxmlpar = new SqlParameter("#outputxmlpar", SqlDbType.NVarChar);
outputxmlpar.Value =outputxml;
using (SqlConnection connection = new SqlConnection(connectionString))
{
cmd = new SqlCommand(String.Format(command), connection);
cmd.Parameters.Add(inputxmlpar);
cmd.Parameters.Add(outputxmlpar);
connection.Open();
cmd.ExecuteScalar();
}
}
]]></msxsl:script>
then a call it <xsl:copy-of select ="ConnectDatabase:LogINOUT( $inputxml,$outputxml)" />
and outputxml in database is something like this:
TO_TESTY45000.0000000020
from this string i know nothing
i wont its
<Data>
<Result>TO_TEST</Result>
<IncludeInVolume>Y</IncludeInVolume>
<FinancedAmont>
<xsl:value-of select="/Contract/ContractCalculations/Calculation/CalculationStep[#Code='FinancedAmount']"/>
</FinancedAmont>
<NumberOfInstalments>
<xsl:value-of select="format-number(/Contract/ContractCalculations/Calculation/CalculationStep[#Code='InstalmentNumber'],'#')"/>
</NumberOfInstalments>
</Data>
the same problem its with inputxml
thanks for Help Dana

How to delete nested xml element using qt

i have xml file like this
<root>
<element>
<child id = "0"> Some Text </child> <-- Target To Delete
</element>
<element>
<child id = "1"> Some Text </child>
</element>
</root>
how can i delete child element of id "0" ? using Qt library.
QDomDocument doc;
doc.setContent(oldXml);
QDomNodeList nodes = doc.elementsByTagName("element");
for (int i = 0; i < nodes.count(); ++i)
{
QDomNode node = nodes.at(i);
QDomElement child = node.firstChildElement("child");
if (!child.isNull() && child.attribute("id") == "0")
{
node.removeChild(child);
}
}
QString newXml = doc.toString();

How to edit the end of the XML document end in Qt (writeEndDocument)?

I write a small program address book, contacts stored in the xml file. Here is the part off the code
void new_engine::main_window::write_to_db(const QString& n, const QString& s)
{
QFile m_db_file(m_db_path);
QString t("User");
m_db_file.open(QIODevice::Append);
QXmlStreamWriter wxml(&m_db_file);
wxml.setAutoFormatting(true);
if(m_size == 1)
{
wxml.writeStartDocument();
wxml.writeStartElement("Persons");
}
wxml.writeStartElement(t);
QString id = QString::number(m_size);
wxml.writeAttribute("id", id);
wxml.writeTextElement("Name", n);
wxml.writeTextElement("Surname", s);
wxml.writeEndElement();
wxml.writeEndDocument();
m_db_file.close();
}
but the problem is that after the first contact of the tag file is closed. here is the result
<?xml version="1.0" encoding="UTF-8"?>
<Persons>
<User id="1">
<Name>das</Name>
<Surname>vcvx</Surname>
</User>
</Persons>
<User id="2">
<Name>eqwevxcv</Name>
<Surname>xcvxcx</Surname>
</User>
<User id="3">
<Name>das</Name>
<Surname>dasdasd</Surname>
</User>
but it must be so
<Persons>
<User id="1">
<Name>das</Name>
<Surname>vcvx</Surname>
</User>
<User id="2">
<Name>eqwevxcv</Name>
<Surname>xcvxcx</Surname>
</User>
<User id="3">
<Name>das</Name>
<Surname>dasdasd</Surname>
</User>
</Persons>
How can we do this, after each new record will have to change document end ?
This is an example:
void write_to_db(QXmlStreamWriter& writer, QString id, QString name, QString surname)
{
writer.writeStartElement("User");
writer.writeAttribute(QXmlStreamAttribute("id", id));
writer.writeTextElement("Name", name);
writer.writeTextElement("Surname", surname);
writer.writeEndElement();
}
// This can be a file, or whatever iodevice your heart desires.
QString out;
QXmlStreamWriter writer(&out);
writer.writeStartDocument();
writer.writeStartElement("Persons");
write_to_db(writer, "1", "das", "vcvx");
write_to_db(writer, "2", "das", "vcvx");
write_to_db(writer, "3", "das", "vcvx");
writer.writeEndElement(); // Close <persons> tag
writer.writeEndDocument();
The output (using QXmlStreamWriter::setAutoFormatting/Indent):
<?xml version="1.0"?>
<Persons>
<User id="1">
<Name>das</Name>
<Surname>vcvx</Surname>
</User>
<User id="2">
<Name>das</Name>
<Surname>vcvx</Surname>
</User>
<User id="3">
<Name>das</Name>
<Surname>vcvx</Surname>
</User>
</Persons>

tinyxml and c++ to save data

I am using tinyxml to save data input by the user in a c++ console program. I pass a save function an array of structs that look like the following
struct day
{
string name;
string note;
};
I have seven of these, and pass all seven to the save function that looks like the following
void saveData(day dayArr[])
{
TiXmlDeclaration* declaration = new TiXmlDeclaration("1.0", "UTF-8", "no");//Create DTD
TiXmlDocument* doc = new TiXmlDocument;
doc->LinkEndChild(declaration);
TiXmlElement* week = new TiXmlElement("week");
TiXmlElement* day = new TiXmlElement("day");
TiXmlElement* name = new TiXmlElement("name");
TiXmlElement* note = new TiXmlElement("note");
TiXmlElement* tl = new TiXmlElement("tl");
TiXmlElement* ti = new TiXmlElement("ti");
TiXmlText* dayName = new TiXmlText("");
TiXmlText* dayNote = new TiXmlText("");
for(int i=0; i<7; i++)
{
dayName = new TiXmlText(dayArr[i].name.c_str());
dayNote = new TiXmlText(dayArr[i].note.c_str());
name->LinkEndChild(dayName);
note->LinkEndChild(dayNote);
day->LinkEndChild(name);
day->LinkEndChild(note);
}
week->LinkEndChild(day);
doc->LinkEndChild(week);
doc->SaveFile("test.xml");
cout << "SAVED";
}
It writes this to the file
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<week>
<day>
<name>SundayMondayTuesdayWednesdayThursdayFridaySaturday
</name>
<note>
</note>
</day>
</week>
What i need is this
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<week>
<day>
<name>Sunday</name>
<note> </note>
</day>
<day>
<name>Monday</name>
<note>
</note>
</day>
<day>
<name>Tuesday</name>
<note> </note>
</day>
<day>
<name>Wednesday</name>
<note> </note>
</day>
<day>
<name>Thursday</name>
<note> </note>
</day>
<day>
<name>Friday</name>
<note> </note>
</day>
<day>
<name>Saturday</name>
<note> </note>
</day>
</week>
I can't figure out how to create new elements of the day tag. Thanks in advance for any help.
I haven't used TinyXml before but looking at the structure of the code, you need to create the day element inside your for loop and add it to the week element 7 times - once for each day.
Your current code only adds the day element to the week element once at the end - this is reflected in your xml output.
Taking part of your code - maybe something similar to this below. (This may not compile or be exactly correct but should provide the right idea).
TiXmlElement* week = new TiXmlElement("week");
TiXmlElement* name = new TiXmlElement("name");
TiXmlElement* note = new TiXmlElement("note");
TiXmlElement* tl = new TiXmlElement("tl");
TiXmlElement* ti = new TiXmlElement("ti");
TiXmlText* dayName = new TiXmlText("");
TiXmlText* dayNote = new TiXmlText("");
for(int i=0; i<7; i++)
{
TiXmlElement* day = new TiXmlElement("day");
dayName = new TiXmlText(dayArr[i].name.c_str());
dayNote = new TiXmlText(dayArr[i].note.c_str());
name->LinkEndChild(dayName);
note->LinkEndChild(dayNote);
day->LinkEndChild(name);
day->LinkEndChild(note);
week->LinkEndChild(day);
}
doc->LinkEndChild(week);
void saveData(std::vector<day*> vecDay)
{
TiXmlDeclaration* declaration = new TiXmlDeclaration("1.0", "UTF-8", "no");//Create DTD
TiXmlDocument* doc = new TiXmlDocument;
doc->LinkEndChild(declaration);
TiXmlElement* week = new TiXmlElement("week");
for(std::vector<day*>::iterator it = vecDay.begin(); it != vecDay.end(); it++)
{
TiXmlElement* day_ = new TiXmlElement("day");
TiXmlElement* name = new TiXmlElement("name");
TiXmlElement* note = new TiXmlElement("note");
TiXmlElement* tl = new TiXmlElement("tl");
TiXmlElement* ti = new TiXmlElement("ti");
TiXmlText* dayName = new TiXmlText("");
TiXmlText* dayNote = new TiXmlText("");
dayName = new TiXmlText((*it)->name.c_str());
dayNote = new TiXmlText((*it)->note.c_str());
name->LinkEndChild(dayName);
note->LinkEndChild(dayNote);
day_->LinkEndChild(name);
day_->LinkEndChild(note);
week->LinkEndChild(day_);
}
doc->LinkEndChild(week);
doc->SaveFile("test2.xml");
cout << "SAVED" << endl;
}