Runtime error with tinyXML element access - c++

yester day was my first attempt. I am trying to catch the variable "time" in the following "new.xml" file
<?xml version="1.0" standalone=no>
<main>
<ToDo time="1">
<Item priority="1"> Go to the <bold>Toy store!</bold></Item>
<Item priority="2"> Do bills</Item>
</ToDo>
<ToDo time="2">
<Item priority="1"> Go to the Second<bold>Toy store!</bold></Item>
</ToDo>
</main>
Here is my code
TiXmlDocument doc("new.xml");
TiXmlNode * element=doc.FirstChild("main");
element=element->FirstChild("ToDo");
string temp=static_cast<TiXmlElement *>(element)->Attribute("time");
But I am getting run time errors from the third and fourth lines. Can anybody shed a light on this isssue?

It seems to me that you forgot to load the file. Normally I do something along these lines:
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(); // In your example xml file this gives you ToDo
string attribute = firstChild->Attribute("time"); //Gets you the time variable
element = element->NextSiblingElement();
}
}
else
{
//Error conditions
}
Hope this helps

#include "tinyXml/tinyxml.h"
const char MY_XML[] = "<?xml version='1.0' standalone=no><main> <ToDo time='1'> <Item priority='1'> Go to the <bold>Toy store!</bold></Item> <Item priority='2'> Do bills</Item> </ToDo> <ToDo time='2'> <Item priority='1'> Go to the Second<bold>Toy store!</bold></Item> </ToDo></main>";
void main()
{
TiXmlDocument doc;
TiXmlHandle docHandle(&doc);
const char * const the_xml = MY_XML;
doc.Parse(MY_XML);
TiXmlElement* xElement = NULL;
xElement = docHandle.FirstChild("main").FirstChild("ToDo").ToElement();
int element_time = -1;
while(xElement)
{
if(xElement->QueryIntAttribute("time", (int*)&element_time) != TIXML_SUCCESS)
throw;
xElement = xElement->NextSiblingElement();
}
}
That's how it works. Compiled & tested.
As you can see your tries to make it extra-safe code cost you with an exceotion at your third line (of the question), and without testing I can bet it's a "pointing-to-null" exception.
Just load it my style, as TinyXml's docs say as well: "docHandle.FirstChild("main").FirstChild("ToDo").ToElement();".
Hope it helps you understand, let me know if it's not clear. I accept visa (:

Is it just me or the the pugixml version looks much better?
#include <iostream>
#include "pugixml.hpp"
using namespace std;
using namespace pugi;
int main()
{
xml_document doc;
if (!doc.load_file("new.xml"))
{
cerr << "Could not load xml";
return 1;
}
xml_node element = doc.child("main");
element = element.child("ToDo");
cout << "Time: " << element.attribute("time") << endl;
}
Also new.xml had an error, instead of:
<?xml version="1.0" standalone=no>
should be
<?xml version="1.0" standalone="no"?>
Compilation was just a matter of cl test.cpp pugixml.cpp

Related

How to manually create a boost ptree with different XML attributes?

I am using boost libraries to parse XML files and I have to create a ptree manually.
I want to create below xml file using boost ptree.
<?xml version="1.0"?>
<Txn>
<Resp errCode="0" errInfo="" />
<A exptime="20171230">xyz Information</A>
<B>xyz Information</B>
<C type="Active">xyz Information</C>
</Txn>
To achieve above xml,
Below is my sample code:
boost::property_tree::ptree pt;
boost::property_tree::ptree ptr1;
boost::property_tree::ptree ptr2;
boost::property_tree::ptree ptr3;
ptr1.put("<xmlattr>.errCode", Txn.resp.errCode);
ptr1.put("<xmlattr>.errInfo", Txn.resp.errInfo);
ptr2.push_back(boost::property_tree::ptree::value_type("A", boost::property_tree::ptree(data)));
ptr2.push_back(boost::property_tree::ptree::value_type("C", boost::property_tree::ptree(data)));
ptr2.put("A.<xmlattr>.exptime", data);
ptr2.put("C.<xmlattr>.type", data);
ptr3.put("<xmlattr>", data);
pt.add_child("Txn.Resp", ptr1);
pt.add_child("Txn", ptr2);
pt.add_child("Txn.B", ptr3);
Here Child A and C always create as a separate with Parent Txn But I want to add all child in Txn Parent
. I did not understand, why child A and C are different here.
It would be very helpful, If someone help me to provide right way.
Here's the simplest thing I can think of:
Live On Coliru
#include <boost/property_tree/xml_parser.hpp>
#include <iostream>
using boost::property_tree::ptree;
static auto pretty = boost::property_tree::xml_writer_make_settings<std::string>(' ', 4);
int main() {
ptree root;
root.add("Txn.Resp.<xmlattr>.errCode", 0);
root.add("Txn.Resp.<xmlattr>.errInfo", "");
root.add("Txn.A", "xyz Information");
root.add("Txn.A.<xmlattr>.exptime", "20171230");
root.add("Txn.B", "xyz Information");
root.add("Txn.C", "xyz Information");
root.add("Txn.C.<xmlattr>.type", "Active");
write_xml(std::cout, root, pretty);
}
Prints:
<?xml version="1.0"?>
<Txn>
<Resp errCode="0" errInfo="" />
<A exptime="20171230">xyz Information</A>
<B>xyz Information</B>
<C type="Active">xyz Information</C>
</Txn>
Key point is to create the element node before adding attributes, otherwise you get this instead:
Live On Coliru
<?xml version="1.0" encoding="utf-8"?>
<Txn>
<Resp errCode="0" errInfo=""/>
<A exptime="20171230"/>
<A>xyz Information</A>
<B>xyz Information</B>
<C type="Active"/>
<C>xyz Information</C>
</Txn>

Xerces XPath causes seg fault when path doesn't exist

I can successfully use Xerces XPath feature to query for information from an XML with the following XML and C++ code.
XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<ApplicationSettings>
hello universe
</ApplicationSettings>
</root>
C++
int main()
{
XMLPlatformUtils::Initialize();
// create the DOM parser
XercesDOMParser *parser = new XercesDOMParser;
parser->setValidationScheme(XercesDOMParser::Val_Never);
parser->parse("fake_cmf.xml");
// get the DOM representation
DOMDocument *doc = parser->getDocument();
// get the root element
DOMElement* root = doc->getDocumentElement();
// evaluate the xpath
DOMXPathResult* result=doc->evaluate(
XMLString::transcode("/root/ApplicationSettings"), // <-- HERE IS THE XPATH
root,
NULL,
DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, //DOMXPathResult::ANY_UNORDERED_NODE_TYPE, //DOMXPathResult::STRING_TYPE,
NULL);
// look into the xpart evaluate result
result->snapshotItem(0);
std::cout<<TranscodeToStr(result->getNodeValue()->getFirstChild()->getNodeValue(),"ascii").str()<<std::endl;;
XMLPlatformUtils::Terminate();
return 0;
}
The problem is that sometimes my XML will only have certain fields. But if I remove the ApplicationSettings entry from the XML it will seg fault. How can I properly handle these optional fields? I know that trying to correct from seg faults is risky business.
The seg fault is occurring in this line
std::cout<<TranscodeToStr(result->getNodeValue()->getFirstChild()->getNodeValue(),"ascii").str()<<std::endl;
specifically in get getFirstChild() call because the result of getNodeValue() is NULL.
This is my quick and dirty solution. It's not really ideal but it works. I would prefer a more sophisticated evaluation and response.
if (result->getNodeValue() == NULL)
{
cout << "There is no result for the provided XPath " << endl;
}
else
{
cout<<TranscodeToStr(result->getNodeValue()->getFirstChild()->getNodeValue(),"ascii").str()<<endl;
}

Find Key in XML with Boost

I am using boost for the first time within an old code base that we have
iptree children = pt.get_child(fieldName);
for (const auto& kv : children) {
boost::property_tree::iptree subtree = (boost::property_tree::iptree) kv.second ;
//Recursive call
}
My problem is sometimes the fieldName doesn`t exist in the XML file and I have an exception
I tried :
boost::property_tree::iptree::assoc_iterator it = pt.find(fieldName);
but I dont know how to use the it I can`t use: if (it != null)
Any help please will be appreciated
I am using VS 2012
If it`s very complicated is there any other way to read a XML with nested nodes? I am working on that since 3 days
This is an Example of the XML
<?xml version="1.0" encoding="utf-8"?>
<nodeA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<nodeA.1>This is the Adresse</nodeA.1>
<nodeA.2>
<node1>
<node1.1>
<node1.1.1>Female</node1.1.1>
<node1.1.2>23</node1.1.2>
<node1.1.3>Engineer</node1.1.3>
</node1.1>
<node1.2>
<node1.2.1>Female</node1.2.1>
<node1.2.2>35</node1.2.2>
<node1.2.3>Doctors</node1.2.3>
</node1.2>
</node1>
</nodeA.2>
<nodeA.3>Car 1</nodeA.3>
</nodeA>
Use pt.get_child_optional(...) to prevent an exception. pt.find(...) returns an iterator which compares true to pt.not_found() on failure.
EDIT: How to use boost::optional<--->
boost::optional< iptree & > chl = pt.get_child_optional(fieldname);
if(chl) {
for( auto a : *chl )
std::cerr << ":" << a.first << ":" << std::endl;
}

Rapidxml and start tags

I am having a few problems with rapidxml. When I compile my code no start tags are included..any and all help will be greatly appreciated
int main(){
xml_document<> doc;
//xml declaration
xml_node<>* decl = doc.allocate_node(node_declaration);
decl->append_attribute(doc.allocate_attribute("version","1.0"));
decl->append_attribute(doc.allocate_attribute("encoding", "utf-8"));
doc.append_node(decl);
// root node
xml_node<>* root = doc.allocate_node(node_element, "root");
root->append_attribute(doc.allocate_attribute(""));
doc.append_node(root);
// child/sibling node
xml_node<>* sibling0 = doc.allocate_node(node_element, "old");
root->append_node(sibling0);
xml_node<>* sibling = doc.allocate_node(node_element,"boy");
root->append_node(sibling );
std::string xmlstring;
print(back_inserter(xmlstring), doc);
cout << xmlstring << endl;}
Apart from the necessary #includes, and missing using namespace rapidxml; your code compiles and runs fine for me.
xmlstring contains this:
<?xml version="1.0" encoding="utf-8"?>
<root ="">
<old/>
<boy/>
</root>
Because old and boy have no content, they use xml empty element tags, <tagname/>rather than start and end pairs like <tagname></tagname>

problem with XSLT

I am trying to create a html based template with xslt transformation.The string result returned by the transformer is perfectly fine.but when i try to send it to display, the browser is not interpreting it. The output looks like<html><body>...</body></html>.
when i do view source it is displaying <html>... How can i resolve it?Please help.
Thanks in advance
Did you specify the output method correctly? It should be set to HTML:
<xsl:output method="html" encoding="UTF-8" />
<xsl:output value="html"/>
<xsl:template match="mail[#type='pinReset']">
<html><body>
<xsl:variable name="userService" select="java:new()"/>
<i><u>Message body </u><xsl:value-of select="mailMessage/mail/body/prefix"/></i>
<a><xsl:attribute name="href">
<xsl:value-of select="java:getResetPinUrl($userService)"/></xsl:attribute>
reset pin
</a>
<i><xsl:value-of select="mailMessage/body/suffix"/></i><br/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
This is my XSl.
public String getXformedString(int type){
String xFormedString = "";
String xsltFile = "D:\\SitesContent\\sitescontent_war\\JavaSource\\com\\tgt\\mobile\\gc\\controller\\email.xsl";
String xmlFile="D:\\SitesContent\\sitescontent_war\\JavaSource\\com\\tgt\\mobile\\gc\\controller\\emailBody.xml";
StringWriter stWr = new StringWriter();
File xsltfile = new File(xsltFile);
File xmlfile = new File(xmlFile);
Source xmlSource = new StreamSource(xmlfile);
Source xsltSource = new StreamSource(xsltfile);
Result result = new StreamResult(stWr);
TransformerFactory transFact = TransformerFactory.newInstance();
try {
Transformer transformer= transFact.newTransformer(xsltSource);
transformer.setParameter("type",new Integer(type));
transformer.transform(xmlSource, result);
xFormedString = stWr.toString();
System.out.println("Str->"+xFormedString);
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return xFormedString;
}
This is the code to get the formed string from xml and xslt.