I have the following code:
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file( "C:/Users/James/Documents/Visual Studio 2013/Projects/Games/Jimmy/Game/Assets/Levels/Scene.dae" );
std::cout << "Load result: " << result.description( ) << ", mesh name: " << doc.child( "mesh" ).attribute( "name" ).value( ) << std::endl;
pugi::xml_node tools = doc.child( "Profile" ).child( "Tools" );
for( pugi::xml_node tool = tools.child( "Tool" ); tool; tool = tool.next_sibling( "Tool" ) )
{
std::cout << "Tool " << tool.attribute( "Filename" ).value( );
std::cout << ": AllowRemote " << tool.attribute( "AllowRemote" ).as_bool( );
std::cout << ", Timeout " << tool.attribute( "Timeout" ).as_int( );
std::cout << ", Description '" << tool.child_value( "Description" ) << "'/n";
}
For some reason I am getting:
+ result {status=status_file_not_found (1) offset=0 encoding=encoding_auto (0) } pugi::xml_parse_result
Any ideas why it can't find my file?
pugi only opens .xml... I also had to change my path to a relative one.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 days ago.
Improve this question
i am trying to make a program in ns3 with OLSR protocol to drop a packet with 1024bytes size when energy of the node under 500j.but when i tried to compile in 1000s, i got a problem "free(): double free detected in tcache 2 when the node send package 1024 bytes and the energy hit under 500j. Here's the code what i am trying to modify in routeinput method file olsr-routing-protocol.cc in ns3
bool RoutingProtocol::RouteInput (Ptr<const Packet> p,
const Ipv4Header &header, Ptr<const NetDevice> idev,
UnicastForwardCallback ucb, MulticastForwardCallback mcb,
LocalDeliverCallback lcb, ErrorCallback ecb)
{
NS_LOG_FUNCTION (this << " " << m_ipv4->GetObject<Node> ()->GetId () << " " << header.GetDestination ());
/**/ //rekayasa
std::string deviceName = idev->GetInstanceTypeId ().GetName ();
Ptr<Node> node = m_ipv4->GetObject<Node> ();
Ptr<EnergySourceContainer> energysourcecont = (node)->GetObject<EnergySourceContainer> ();
Ptr<EnergySource> source = energysourcecont->Get(0);
NS_ASSERT(node !=NULL);
NS_LOG_LOGIC (node << " nodes "
<<node->GetId() << " "
<< energysourcecont->Get(0) << " "
<< source->GetRemainingEnergy() << " = "
<< "\n"
);
/**/
Ipv4Address dst = header.GetDestination ();
Ipv4Address origin = header.GetSource ();
// Consume self-originated packets
if (IsMyOwnAddress (origin) == true)
{
return true;
}
// Local delivery
NS_ASSERT (m_ipv4->GetInterfaceForDevice (idev) >= 0);
uint32_t iif = m_ipv4->GetInterfaceForDevice (idev);
if (m_ipv4->IsDestinationAddress (dst, iif))
{
if (!lcb.IsNull ())
{
NS_LOG_LOGIC ("Local delivery to " << dst);
if (source->GetRemainingEnergy() > 500.0){
NS_LOG_LOGIC("ENERGY > 500, deliver" << " size payload = "<< p->GetSize() << " id packet= " << p->GetUid() << " Node: " <<node->GetId() << " Energy: " <<source->GetRemainingEnergy() << " from: " << origin << " to: " << dst );
lcb (p, header, iif);
}
else if (source->GetRemainingEnergy()<= 500.0){
if((p->GetSize() - 8) == 1024){
NS_LOG_LOGIC("ENERGY < 500, not deliver " << " size payload = "<< p->GetSize() << " id packet= " << p->GetUid() << " Node: " <<node->GetId() << " Energy: " <<source->GetRemainingEnergy());
}
else{
NS_LOG_LOGIC("ENERGY < 500, deliver " << " size payload = "<< p->GetSize() << " id packet= " << p->GetUid() << " Node: " <<node->GetId() << " Energy: " <<source->GetRemainingEnergy() << " from: " << origin << " to: " << dst );
lcb (p, header, iif);
}
}
return true;
}
else
{
// The local delivery callback is null. This may be a multicast
// or broadcast packet, so return false so that another
// multicast routing protocol can handle it. It should be possible
// to extend this to explicitly check whether it is a unicast
// packet, and invoke the error callback if so
NS_LOG_LOGIC ("Null local delivery callback");
return false;
}
}
NS_LOG_LOGIC ("Forward packet");
// Forwarding
Ptr<Ipv4Route> rtentry;
RoutingTableEntry entry1, entry2;
if (Lookup (header.GetDestination (), entry1))
{
bool foundSendEntry = FindSendEntry (entry1, entry2);
if (!foundSendEntry)
{
NS_FATAL_ERROR ("FindSendEntry failure");
}
rtentry = Create<Ipv4Route> ();
rtentry->SetDestination (header.GetDestination ());
uint32_t interfaceIdx = entry2.interface;
// the source address is the interface address that matches
// the destination address (when multiple are present on the
// outgoing interface, one is selected via scoping rules)
NS_ASSERT (m_ipv4);
uint32_t numOifAddresses = m_ipv4->GetNAddresses (interfaceIdx);
NS_ASSERT (numOifAddresses > 0);
Ipv4InterfaceAddress ifAddr;
if (numOifAddresses == 1)
{
ifAddr = m_ipv4->GetAddress (interfaceIdx, 0);
}
else
{
/// \todo Implement IP aliasing and OLSR
NS_FATAL_ERROR ("XXX Not implemented yet: IP aliasing and OLSR");
}
rtentry->SetSource (ifAddr.GetLocal ());
rtentry->SetGateway (entry2.nextAddr);
rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIdx));
NS_LOG_DEBUG ("Olsr node " << m_mainAddress
<< ": RouteInput for dest=" << header.GetDestination ()
<< " --> nextHop=" << entry2.nextAddr
<< " interface=" << entry2.interface);
if (source->GetRemainingEnergy() > 500.0){
NS_LOG_LOGIC("PACKET FORWARD" << " size payload = "<< p->GetSize() << " id packet= " << p->GetUid() <<" Node: " <<node->GetId() << " Energy: " <<source->GetRemainingEnergy());
ucb (rtentry,p,header);
return true;
}
else if(source->GetRemainingEnergy()<= 500.0){
if((p->GetSize()- 8) == 1024){
NS_LOG_LOGIC("DROP PACKET FORWARD "<< p->GetSize() << " " << p->GetUid()<< " Node: " <<node->GetId() << " Energy: " <<source->GetRemainingEnergy()
);
}
else {
NS_LOG_LOGIC("PACKET FORWARD "<< p->GetSize() << " " << p->GetUid()<<
" Node: " <<node->GetId() << " Energy: " <<source->GetRemainingEnergy()
);
ucb (rtentry,p,header);
return true;
}
}
}
else
{
NS_LOG_LOGIC ("No dynamic route, check network routes");
if (m_hnaRoutingTable->RouteInput (p, header, idev, ucb, mcb, lcb, ecb))
{
return true;
}
else
{
#ifdef NS3_LOG_ENABLE
NS_LOG_DEBUG ("Olsr node " << m_mainAddress
<< ": RouteInput for dest=" << header.GetDestination ()
<< " --> NOT FOUND; ** Dumping routing table...");
for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator iter = m_table.begin ();
iter != m_table.end (); iter++)
{
NS_LOG_DEBUG ("dest=" << iter->first << " --> next=" << iter->second.nextAddr
<< " via interface " << iter->second.interface);
}
NS_LOG_DEBUG ("** Routing table dump end.");
#endif // NS3_LOG_ENABLE
return false;
}
}
}
all!
I request a JSON from TMDB and save it as a file on the local harddisk. Then I read in the file and decode it with nlohmann::json. The next step is to iterate the json data and extract a few parts of the info. While it is no problem getting types „string“, „boolean“ etc. I’m struggling with an „array“ type. (Later on the type „object“ might show same problems…) Goal is to transform the json data into some „ini“ style type like
[tt1234567]
title = abcdefghij
runtime = 123
...
I iterate through the root of the decoded json by:
using json = nlohmann::json;
{
auto jsonData = json::parse( jsonText );
// std::cout << jsonData.dump( 1 ) << "\n";
for ( const auto &jsonItem : jsonData.items() )
{
jsonKey = jsonItem.key();
jsonValue = "";
if ( jsonItem.value().is_null() ) { jsonValue = "(null)"; }
else if ( jsonItem.value().is_boolean() ) { if ( jsonItem.value() ) { jsonValue = "(boolean) yes"; } else { jsonValue = "(boolean) no"; } }
else if ( jsonItem.value().is_string() ) { jsonValue = "(string) '" + string_left( jsonItem.value(), 25 ) + "'"; }
[ . . . ]
std::cout << jsonKey << ": " << jsonValue << "\n";
Screen output is like:
adult: (boolean) no
belongs_to_collection: (null)
budget: (unsigned) 45000000
credits: (object)
genres: (array) [ . . . ]
[ et al ]
My problem is that I don’t know the correct syntax to handle the „array“ type and, in fact, I’m not quite sure if it is really an array despite the fact it is enclosed in []. The code block
else if ( jsonItem.key() == "genres" ) // array
{
std::cout << " jsonItem: " << jsonItem << "\n"; // {"genres":[{"id":12,"name":"Abenteuer"},{"id":28,"name":"Action"}]}
jsonKey = jsonItem.key();
std::cout << " jsonKey: " << jsonKey << "\n"; // genres
// jsonValue = jsonItem.value(); // <-- returns array, but jsonValue expects string
// std::cout << " jsonValue: " << jsonValue << "\n";
auto jsonValueArray = jsonItem.value().array();
std::cout << " jsonValueArray: " << jsonValueArray << " (" << sizeof( jsonValueArray ) << ")\n"; // [] (16)
auto jsonValueFlat = jsonItem.value().flatten();
std::cout << " jsonValueFlat: " << jsonValueFlat << "\n"; // {"/0/id":12,"/0/name":"Abenteuer","/1/id":28,"/1/name":"Action"}
std::cout << " " << jsonKey << " elements: " << jsonValueArray.size() << "\n"; // 0
i = 0;
// for ( const auto &jsonValue : jsonValueArray )
// for ( i = jsonValueArray.begin(); i < jsonValueArray.end(); i++ )
for ( i = 0; i < jsonValueArray.size(); i++ )
{
std::cout << jsonValue << "\n";
iniKey = "Genre" + std::to_string( i );
iniValue = "";
iniValue = jsonValue;
iniText.append( iniKey );
iniText.append( " = " );
iniText.append( iniValue );
iniText.append( "\n" );
// i++;
}
}
produces
jsonItem: {"genres":[{"id":12,"name":"Abenteuer"},{"id":28,"name":"Action"}]}
jsonKey: genres
jsonValueArray: [] (16)
jsonValueFlat: {"/0/id":12,"/0/name":"Abenteuer","/1/id":28,"/1/name":"Action"}
genres elements: 0
So I see a jsonItem with „genres: [xxx]“ content, thus it is identified as an array. The „sizeof“ returns 16 and I interpret it as 4 pointer with 4 bytes each (or 2 with 8 bytes?). On the other hand the array() function seems to return an empty array [] with 0 elements. And now I’m stuck…
What I want to achieve: Extracting the „genres“ list from the json and concatenate the elements with „;“ like
genres = Abenteuer;Action
in the above exampe.
Michael
Ok, I figured it out. The central point was the misunderstanding of .array() from the JSON object. After fiddling around a bit the following branch
else if ( jsonItem.key() == "genres" ) // array
{
std::cout << " jsonItem: " << jsonItem << "\n"; // {"genres":[{"id":12,"name":"Abenteuer"},{"id":28,"name":"Action"}]}
jsonKey = jsonItem.key();
std::cout << " jsonKey: " << jsonKey << "\n"; // genres
auto jsonValueArray = jsonItem.value(); // [{"id":12,"name":"Abenteuer"},{"id":28,"name":"Action"}] (16)
std::cout << " jsonValueArray: " << jsonValueArray << " (" << sizeof( jsonValueArray ) << ")\n"; // [] (16)
i = 0;
for ( const auto &jsonValue : jsonValueArray )
{
iniKey = "Genres";
iniValue = jsonValue["name"];
std::cout << " " << jsonValue << " --> key:'" << iniKey << "', value:'" << iniValue << "'\n";
if ( i == 0 )
{
iniText.append( iniKey );
iniText.append( " = " );
}
else
{
iniText.append( ";" );
}
iniText.append( iniValue );
i++;
}
iniText.append( "\n" );
std::cout << " genres added: " << std::to_string( i ) << "\n";
}
now produces
genres: (array) [ . . . ]
jsonItem: {"genres":[{"id":12,"name":"Abenteuer"},{"id":28,"name":"Action"}]}
jsonKey: genres
jsonValueArray: [{"id":12,"name":"Abenteuer"},{"id":28,"name":"Action"}] (16)
{"id":12,"name":"Abenteuer"} --> key:'Genres', value:'Abenteuer'
{"id":28,"name":"Action"} --> key:'Genres', value:'Action'
genres added: 2
resp.
[tt0446013]
adult = no
Genres = Abenteuer;Action
ID_TMDB = 1534
ID_IMDB = tt0446013
Title_Original = Pathfinder
Overview = An sich stammt der junge
Release_Date = 2007-01-11
Runtime = 99
Tagline = Zwei Welten , ein Krieger
Title = Pathfinder - Fährte des
and that's the output I wanted to have.
I have the following json file
[
{
"a":5855925.424944928,
"b":0,
"c":96,
"d":2096640,
"e":0
}
]
I do this,
boost::property_tree::ptree jsontree;
std::stringstream ss;
ss << "[{\"a\": 5855925.424944928, \"b\": 0, \"c\": 96, \"d\": 2096640, \"e\": 0}]";
boost::property_tree::read_json(ss, jsontree);
// get the children, i.e. the list elements
auto bounds = jsontree.equal_range("");
std::cout << "Size of list : " << std::distance( bounds.first, bounds.second ) << "\n";
But I don't know how to read this from a property tree (eg: get<float>("a"), get<int>("c"))?
Any help would be greatly appreciated.
Thanks
Notice: top-level arrays are not actually supported (you cannot roundtrip that with Boost Property Tree).
The limitations are described in the documentation
Saving this same tree will lose all type information and convert the array to this:
{
"": {
"a": "5855925.424944928",
"b": "0",
"c": "96",
"d": "2096640",
"e": "0"
}
}
Arrays are "objects with empty keys". You already seemed to know that, judging from your sample. So, just use it:
for (auto& object_node : boost::make_iterator_range(jsontree.equal_range(""))) {
ptree const& object = object_node.second;
std::cout << "a: " << object.get<double>("a") << "\n";
std::cout << "b: " << object.get<int>("b") << "\n";
std::cout << "c: " << object.get<int>("c") << "\n";
std::cout << "d: " << object.get<int>("d") << "\n";
std::cout << "e: " << object.get<int>("e") << "\n";
}
Improved Demo
It's often nicer to extract some types/functions:
Live On Coliru
#include <iostream>
#include <boost/property_tree/json_parser.hpp>
using boost::property_tree::ptree;
struct Object {
double a;
int b, c, d, e;
friend std::ostream& operator<<(std::ostream& os, Object const& object) {
return os << "a: " << object.a << "\n"
<< "b: " << object.b << "\n"
<< "c: " << object.c << "\n"
<< "d: " << object.d << "\n"
<< "e: " << object.e << "\n";
}
static Object parse(ptree const& from) {
return {
from.get<double>("a"),
from.get<int>("b"),
from.get<int>("c"),
from.get<int>("d"),
from.get<int>("e"),
};
}
};
int main() {
boost::property_tree::ptree jsontree;
{
std::stringstream ss(R"([{"a": 5855925.424944928, "b": 0, "c": 96, "d": 2096640, "e": 0}])");
boost::property_tree::read_json(ss, jsontree);
}
for (auto& object_node : boost::make_iterator_range(jsontree.equal_range(""))) {
std::cout << Object::parse(object_node.second);
}
}
Prints
a: 5.85593e+06
b: 0
c: 96
d: 2096640
e: 0
You can use BOOST_FOREACH for this. I am attaching some code but they are based on xml_data. But u can use similar to this for getting each value without knowing the key.
BOOST_FOREACH(pt::ptree::value_type &v, tree) {
std::string at = v.first + ATTR_SET;
std::cout << "Extracting attributes from " << at << ":\n";
BOOST_FOREACH(pt::ptree::value_type &v2,v.second.get_child("<xmlattr>")){
std::cout<<""<<v2.first.data()<<" : " <<v2.second.data()<<"\n";
}
std::cout<<"now in book\n";
BOOST_FOREACH(pt::ptree::value_type &v3,tree.get_child("bookstore."+v.first)){
std::cout<<""<<v3.first.data()<<" : " <<v3.second.data()<<"\n";
}
m_modules.insert(v.second.data());
}
here tree is boost::Property_tree::ptree
I am using RapidXML to parse a string of xml.
There is my string:
std::string str("<?xml version=\"1.0\" encoding=\"UTF-8\"
standalone=\"yes\"?><protocol version=\"1.5\"><srvResponse>
<dateTime>2016-10-18T08:51:50.657+01:00</dateTime><responseFrom ag=\"1\"
/><idMessage>0</idMessage><rejectionCode>0</rejectionCode>
</srvResponse></protocol>");
And here is how I try to parse:
XML::xml_document<> doc;
doc.parse<0>((char*) str.c_str());
XML::xml_node<>* firstNode = doc.first_node();
However, what I get is that it is parsed as with just one node: protocol, ie, siblings, children of protocol are null, simply it does not have.
I think I am missing one principal thing.
Could you find and tell me?
Thank you.
You can save XML data to file, such as "1.xml", then you can do as following:
<?xml version="1.0" encoding="utf-8"?>
<protocol version="1.5">
<srvResponse>
<dateTime>2016-10-18T08:51:50.657+01:00</dateTime>
<responseFrom ag="1"/>
<idMessage>0</idMessage>
<rejectionCode>0</rejectionCode>
</srvResponse>
</protocol>
void ParseWithAtrribute(std::string strFilePath /*= "1.xml"*/)
{
rapidxml::file<> docFile(strFilePath.c_str());
rapidxml::xml_document<> doc;
doc.parse<0>(docFile.data());
rapidxml::xml_node<> *pRootNode = doc.first_node();
if (pRootNode != NULL)
{
std::cout << pRootNode->name() << " " << pRootNode->value()<< std::endl; // protocol
rapidxml::xml_attribute<> *pAttr = pRootNode->first_attribute();
if (pAttr != NULL)
{
std::cout << pAttr->name() << " " << pAttr->value() << std::endl; // version
}
rapidxml::xml_node<> *pChildNode = pRootNode->first_node();
if (pChildNode != NULL)
{
std::cout << pChildNode->name() << " " << pChildNode->value() << std::endl;
rapidxml::xml_node<> * pSonNode = pChildNode->first_node();
for(; pSonNode != NULL; pSonNode = pSonNode->next_sibling())
{
std::cout << pSonNode->name() << " " << pSonNode->value() << std::endl;
rapidxml::xml_attribute<> *pSonAttr = pSonNode->first_attribute();
if (pSonAttr != NULL)
{
std::cout << " " << pSonAttr->name() << ":" << pSonAttr->value() << std::endl;
}
}
}
}
}
Now we do not need to save xml data to file:
void ParseWithAtrribute()
{
std::string str("<?xml version=\"1.0\" encoding=\"utf-8\"?> <protocol version=\"1.5\"> <srvResponse> <dateTime>2016-10-18T08:51:50.657+01:00</dateTime> <responseFrom ag=\"1\"/> <idMessage>0</idMessage> <rejectionCode>0</rejectionCode> </srvResponse> </protocol>");
rapidxml::xml_document<> doc;
doc.parse<0>((char *)(str.c_str()));
rapidxml::xml_node<> *pRootNode = doc.first_node();
if (pRootNode != NULL)
{
std::cout << pRootNode->name() << " " << pRootNode->value() << std::endl; // protocol
rapidxml::xml_attribute<> *pAttr = pRootNode->first_attribute();
if (pAttr != NULL)
{
std::cout << pAttr->name() << " " << pAttr->value() << std::endl; // version
}
rapidxml::xml_node<> *pChildNode = pRootNode->first_node();
if (pChildNode != NULL)
{
std::cout << pChildNode->name() << " " << pChildNode->value() << std::endl;
rapidxml::xml_node<> * pSonNode = pChildNode->first_node();
for (; pSonNode != NULL; pSonNode = pSonNode->next_sibling())
{
std::cout << pSonNode->name() << " " << pSonNode->value() << std::endl;
rapidxml::xml_attribute<> *pSonAttr = pSonNode->first_attribute();
if (pSonAttr != NULL)
{
std::cout << " " << pSonAttr->name() << ":" << pSonAttr->value() << std::endl;
}
}
}
}
}
I have below simple XML template in my C++ source code. Within below code block I need to get values for <scannerID> and <subscannerID>. both elements are children of pugixml document root.
xml_document doc;
xml_parse_result r;
std::string sXml = "<inArgs><scannerID>1</scannerID><subScannerID>2</subScannerID></inArgs>";
r = doc.load_buffer(sXml.c_str(), sXml.length());
if (!r) {
return false;
}
xml_node root = doc.child("inArgs");
if (!root) {
return false;
}
std::cout << "root = " << root.name() << std::endl;
xml_node scanner_node = root.child("scannerID");
if (scanner_node) {
std::cout << "scannerID = " << scanner_node.name() << std::endl;
std::cout << "scannerID = " << scanner_node.value() << std::endl;
}
xml_node sub_scanner_node = root.child("subscannerID");
if (scanner_node) {
std::cout << "sub_scanner_node = " << sub_scanner_node.name() << std::endl;
std::cout << "sub_scanner_node = " << sub_scanner_node.value() << std::endl;
}
this code portion giving an output like below. I can get the node's names correctly but failed to retrieve the values.
Out put: values are empty strings.
root = inArgs
scannerID = scannerID
scannerID =
subscannerID = subscannerID
subscannerID =
Edited to add modification for the approach in the answer
node = root.child("scannerID");
if (!node) {
return false;
}
std::cout << "nodeName = %s" << node.name() << std::endl;
std::cout << "text value: " << node.child_value() << std::endl;
but still the output is the same. I saw something different while reading the documents in
The data is in the pcdata child of your element_nodes.
Try scanner_node.child_value()
see the Getting node data section for further examples and explanation.
see node_element
see node_pcdata