How to change XML attribute value? - c++

I want change an attribute value of a XML file.
I already change a node value, in this manner:
xercesc_3_2::XMLPlatformUtils::Initialize();
xercesc_3_2::XercesDOMParser* parser = new xercesc_3_2::XercesDOMParser;
parser->setValidationScheme(xercesc_3_2::XercesDOMParser::Val_Never);
parser->parse(fileName.c_str());
xercesc_3_2::DOMDocument* doc = parser->getDocument();
xercesc_3_2::DOMElement* root = doc->getDocumentElement();
xercesc_3_2::DOMXPathResult* result = doc->evaluate(
xercesc_3_2::XMLString::transcode("/document/child1/child2"),
root,
NULL,
xercesc_3_2::DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
NULL);
result->getNodeValue()->getFirstChild()->setNodeValue(xercesc_3_2::XMLString::transcode(value.c_str()));
But I don't understand how to change the attribute value.
How can I do?

Related

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>
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.

xmlReadMemory - unknown 'url' parameter

I have my xml as char buffer (that's fetched from server, I don't want to save it -> takes extra time and is completely obsolete):
char myword[] = "...xml..."
xmlSchemaParserCtxtPtr ctxt = xmlSchemaNewParserCtxt(xsdFilePath);
xmlDocPtr doc = ?;
Now I need to get doc. I'm trying to use following function:
doc = xmlReadMemory(myword, sizeof(myword), ?URL?, NULL, 0)
But the problem is with URL, what should I put in there..? Am I using this function right? Maybe there is another way to get xmlDocPtr?
BTW: I need xmlDocPtr to perform:
ret = xmlSchemaValidateDoc(ctxt, doc);
Simply pass a NULL pointer:
doc = xmlReadMemory(myword, sizeof(myword), NULL, NULL, 0);

RapidXML - how can I handle missing nodes/values

I'd like to read from XML to C++ using RapidXML. However, if a node doen't exist or a value is missing the program crashes.
for (rapidxml::xml_node<> * xmlasset_node = root_node->first_node("Asset"); xmlasset_node; xmlasset_node = xmlasset_node->next_sibling())
{mystring += xmlasset_node->first_attribute("name")->value()};
However, this "name" attribute doesn't exist in all nodes and is to be filled with a default value, if its not in XML. Similar to this, I've got some sub-nodes not in all nodes. The reason is just to keep the XML as small and clear as possible for manual adjustments.
How can a check/test be implemented (C++), to prevent the program from crashing and just taking default values if a value/node doesn't exist?
Kind regards,
- Corak
Here is what I do, you can compare if the value of the node and its attribute matches your criteria then you accepts it:
// basically I am looking for "settings" node then "network" subnode, then "port" attribute
if( boost::iequals(doc.first_node()->next_sibling()->name(), "settings"))
{
for (xml_node<> *node = doc.first_node()->next_sibling()->first_node(); node; node = node->next_sibling())
{
// find network tag
if (boost::iequals(node->name(),"network"))
{
for (xml_attribute<> *attr = node->first_attribute(); attr; attr = attr->next_attribute())
{
if ( boost::iequals(attr->name(), "port"))
{
strcpy(attr->value(), portname);
}
}
}
}
}

set value in the droplink field

How do I assign values in a droplink through coding?
Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Data.Items.Item PriceBookHome = master.GetItem("/sitecore/content/Administration/Price Books/Clarisonic-us-retail");
string currency = "INR";
string currenySource = PriceBookHome.Fields["Currency"].Source;
Sitecore.Data.Items.Item currenyDictSource = master.GetItem(currenySource);
foreach (Item im in currenyDictSource.GetChildren())
{
if (im.Fields["Key"].Value == currency)
{
PriceBookHome.Editing.BeginEdit();
PriceBookHome.Fields["Currency"].SetValue(im.DisplayName, true);
PriceBookHome.Editing.EndEdit();
}
}
I am getting the following error on the droplink after insertion: "This field contains a value that is not in the selection list"
Error I am getting as follows:
droplink source[Currency path as given source in droplink]
You need to set the ID of the currency item as value, not the name.
PriceBookHome.Fields["Currency"] = im.ID.ToString();
Most likely it's because you're storing a string (the displayname) in the field.
As Ruud says, you can put the ID in, or do something like this:
PriceBookHome.Editing.BeginEdit();
var field = (Sitecore.Data.Fields.ReferenceField)PriceBookHome.Fields["Currency"];
field.TargetItem = im;
PriceBookHome.Editing.EndEdit();

Parsing <multi_path literal="not_measured"/> in TinyXML

How do I parse the following in TinyXML:
<multi_path literal="not_measured"/>
I am able to easily parse the below line:
<hello>1234</hello>
The problem is that the first statement is not getting parsed the normal way. Please suggest how to go about this.
Not 100% sure what youre question is asking but here is a basic format too loop through XML files using tinyXML:
/*XML format typically goes like this:
<Value atribute = 'attributeName' >
Text
</value>
*/
TiXmlDocument doc("document.xml");
bool loadOkay = doc.LoadFile(); // Error checking in case file is missing
if(loadOkay)
{
TiXmlElement *pRoot = doc.RootElement();
TiXmlElement *element = pRoot->FirstChildElement();
while(element)
{
string value = firstChild->Value(); //Gets the Value
string attribute = firstChild->Attribute("attribute"); //Gets the attribute
string text = firstChild->GetText(); //Gets the text
element = element->NextSiblingElement();
}
}
else
{
//Error conditions
}