boost read_xml from stringstream does not read xml format - c++

I want to fill a boost::property_tree::ptree with the data from a xml,
the xml format is in a string which I passed to stringstream and then I try
to read it with read_xml, but the ptree data is null or empty when I look at the object
while debugging, my code:
std::stringstream ss;
ss << "<?xml ?><root><test /></root>";
boost::property_tree::ptree pt;
boost::property_tree::xml_parser::read_xml( ss, pt);
result:
pt {m_data="" m_children=0x001dd3b0 }
before I had a string with this xml code:
<?xml version="1.0"?><Response Location="910" RequesterId="12" SequenceNumber="0">
<Id>1</Id>
<Type>P</Type>
<StatusMessage></StatusMessage>
<Message>Error</Message>
</Response>
But nothing works using visual studio with c++.

There is no data associated with root node so m_data is empty but there is a child node (test) and m_children != nullptr.
Please consider this example:
#include <sstream>
#include <string>
#include <boost/property_tree/xml_parser.hpp>
int main()
{
std::stringstream ss;
ss << "<?xml ?><root><test /></root>";
boost::property_tree::ptree pt;
boost::property_tree::xml_parser::read_xml(ss, pt);
// There is no data associated with root node...
std::string s(pt.get<std::string>("root"));
std::cout << "EXAMPLE1" << std::endl << "Data associated with root node: " << s << std::endl;
// ...but there is a child node.
std::cout << "Children of root node: ";
for (auto r : pt.get_child("root"))
std::cout << r.first << std::endl;
std::cout << std::endl << std::endl;
std::stringstream ss2;
ss2 << "<?xml ?><root>dummy</root>";
boost::property_tree::xml_parser::read_xml(ss2, pt);
// This time we have a string associated with root node
std::string s2(pt.get<std::string>("root"));
std::cout << "EXAMPLE2" << std::endl << "Data associated with root node: " << s2 << std::endl;
return 0;
}
It'll print:
EXAMPLE1
Data associated with root node:
Children of root node: test
EXAMPLE2
Data associated with root node: dummy
(http://coliru.stacked-crooked.com/a/34a99abb0aca78f2).
The Boost propertytree library doesn’t fully document its capabilities, but a good guide for parsing XML with Boost is http://akrzemi1.wordpress.com/2011/07/13/parsing-xml-with-boost/

Related

Parse json array string using jsoncpp

I have this JSON:
[{"header": "test" , "test2" : "test2"}]
I'm trying to parse this using jsoncpp.
Here's my code snippet:
Json::CharReaderBuilder builder;
Json::CharReader *reader = builder.newCharReader();
Json::Value root;
bool parseRet = reader->parse(serverResponse.c_str(),serverResponse.c_str() +serverResponse.size(), &root, &errors);
parseRet returns true. But root does not include json data.
How do I parse this?
parseRet returns true. But root does not include JSON data.
This sounds like an issue with the way you're accessing the parsed JSON elements.
Below is a complete working example with a raw string literal as JSON input.
A few points:
Use std::unique_ptr for reader to de-allocate memory appropriately at the end. In your code snippet, it's a memory leak.
Read the documentation carefully! Accessing an element using a method or operator might return a default value or an exception so handle accordingly. For example, the JSON in root is an array so it should be accessed by index and then each index contains an object i.e. root[0]["header"].
Example (C++11):
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
int main()
{
const std::string raw_json = R"json([{"header": "test" , "test2" : "test2"}])json";
Json::CharReaderBuilder builder {};
// Don't leak memory! Use std::unique_ptr!
auto reader = std::unique_ptr<Json::CharReader>( builder.newCharReader() );
Json::Value root {};
std::string errors {};
const auto is_parsed = reader->parse( raw_json.c_str(),
raw_json.c_str() + raw_json.length(),
&root,
&errors );
if ( !is_parsed )
{
std::cerr << "ERROR: Could not parse! " << errors << '\n';
return -1;
}
std::cout << "Parsed JSON:\n" << root << "\n\n";
try
{
std::cout << "header: " << root[0]["header"] << '\n';
std::cout << "test2 : " << root[0]["test2"] << '\n';
}
catch ( const Json::Exception& e )
{
std::cerr << e.what() << '\n';
}
return 0;
}
Output:
Parsed JSON:
[
{
"header" : "test",
"test2" : "test2"
}
]
header: "test"
test2 : "test2"

boost ptree access first element with no path name

I am using boost library to manipulate a JSON string and I would like to access to a first element.
I was wondering if there where some convenient way to access a first element of ptree with no path name.
I do this, but I got no value :
namespace pt = boost::property_tree;
pt::ptree pt2;
string json = "\"ok\"";
istringstream is(json);
try
{
pt::read_json(is, pt2);
cout << pt2.get_child("").equal_range("").first->first.data() << endl;
}
catch (std::exception const& e)
{
cerr << e.what() << endl;
}
Solution:
replace cout << pt2.get_child("").equal_range("").first->first.data() << endl;
by cout << pt2.get_value<std::string>() << endl;
Firstly, Property Tree is not a JSON library.
Secondly, the input is not in the subset of JSON supported by the library (e.g.).
Thirdly, since the input results in a tree that has no child nodes, you should use the value of the root node itself.
Lastly, if you had wanted the first node, use ordered_begin()->second:
Live On Coliru
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <iostream>
void broken_input() {
boost::property_tree::ptree pt;
std::istringstream is("\"ok\"");
read_json(is, pt);
std::cout << "Root value is " << pt.get_value<std::string>() << std::endl;
}
void normal_tree() {
boost::property_tree::ptree pt;
pt.put("first", "hello");
pt.put("second", "world");
pt.put("third", "bye");
std::cout << pt.ordered_begin()->second.get_value<std::string>() << std::endl;
write_json(std::cout, pt);
}
int main() {
try {
broken_input();
normal_tree();
}
catch (std::exception const& e)
{
std::cerr << e.what() << std::endl;
}
}
Prints
Root value is ok
hello
{
"first": "hello",
"second": "world",
"third": "bye"
}
I would like to access to a first element.
It is impossible in general case, since JSON elements are not place-fixed by definition. The current first element can change its place after JSON transformations and a resulting JSON will be the same, although elements are reordered. Thus such API is not provided by BOOST.

writing the vector map to a file in Omnetpp

I am having problem in writing the vector map to a file. I would like to know the detail value inside the wsmdata. I know that inorder to access the detail information I need to use operator overloading like “std::ostream& operator<<(std::ostream& os, map& );” in header file as well as in .cc file. But I don’t know how to use it in detail to access the vector data or output the vector data in the file. I have bee stuck in this problem for a long time. Can anybody help ?
Here is the portion of codes:
.h file:
using std::map;
typedef std::vector<WaveShortMessage*> WaveShortMessages;
std::map<long,WaveShortMessages> receivedWarningMap;
.cc file:
// add warning message to received messages storage
receivedWarningMap[wsm->getTreeId()].push_back(wsm->dup());
std::cout<<"Wsm dup() values/ receivedWarningMap="<<wsm->dup()<<endl;
std::ofstream tracefile;
tracefile.clear();
tracefile.open("traceFile1.txt", std::ios_base::app);
for (UINT i = 0; i < receivedWarningMap[wsm->getTreeId()].size(); i++)
{
std::cout << receivedWarningMap[wsm->getTreeId()][i] << std::endl;
EV<< "MyID="<<getMyID()<< "Recepient ID"<<wsm->getRecipientAddress()<<"Neighbor ID="<< wsm->getSenderAddress()<< std::endl;
}
tracefile.close();
First of all define operator << for your class WaveShortMessage, for example this way:
std::ostream & operator<<(std::ostream &os, WaveShortMessage * wsm) {
os << "Recepient ID=" << wsm->getRecipientAddress() << "; ";
os << "Neighbor ID=" << wsm->getSenderAddress() << "; ";
// and any other fields of this class
//...
return os;
}
Then use the following code to write map to text file:
// remember to add this two includes at the beginning:
// #include <fstream>
// #include <sstream>
std::ofstream logFile;
logFile.open("log.txt"); // if exists it will be overwritten
std::stringstream ss;
for (auto it = receivedWarningMap.begin(); it != receivedWarningMap.end(); ++it) {
ss << "id=" << static_cast<int>(it->first) << "; wsms=";
for (auto it2 : it->second) {
ss << it2 << "; ";
}
ss << endl;
}
logFile << ss.str();
logFile.close();

Trouble using get_value with Boost's property trees

I have to write an XML parser with Boost. However I have some trouble.
I can access the nodes name without any problem, but for some reason I can't access the attributes inside a tag by using get_value, which should work instantly. Maybe there is a mistake in my code I didn't spot? Take a look:
void ParametersGroup::load(const boost::property_tree::ptree &pt)
{
using boost::property_tree::ptree;
BOOST_FOREACH(const ptree::value_type& v, pt)
{
name = v.second.get_value<std::string>("name");
std::string node_name = v.first;
if (node_name == "<xmlattr>" || node_name == "<xmlcomment>")
continue;
else if (node_name == "ParametersGroup")
sg.load(v.second); // Recursion to go deeper
else if (node_name == "Parameter")
{
// Do stuff
std::cout << "PARAMETER_ELEM" << std::endl;
std::cout << "name: " << name << std::endl;
std::cout << "node_name: " << node_name << std::endl << std::endl;
}
else
{
std::cerr << "FATAL ERROR: XML document contains a non-recognized element: " << node_name << std::endl;
exit(-1);
}
}
}
So basically I ignore and tags, when I'm in a ParametersGroup tag I go deeper, and when I'm in a Parameter tag I recover the datas to do stuff. However, I can't get the "name" properly.
This is the kind of lines I'm scanning in the last else if :
<Parameter name="box">
The std::cout << name displays things like that:
name: ^M
^M
^M
^M
^M
^M
which is obvisouly not what I'm asking for.
What am I doing wrong? Any help would be greatly appreciated.
Since your question isn't particularly selfcontained, here's my selfcontained counter example:
Live On Coliru
#include <sstream>
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
using namespace boost::property_tree;
int main() {
ptree pt;
std::istringstream iss("<Parameter name=\"box\" />");
xml_parser::read_xml(iss, pt);
for (auto& element : pt)
{
std::cout << "'" << element.first << "'\n";
for (auto& attr : element.second)
{
std::cout << "'" << attr.first << "'\n";
for (auto& which : attr.second)
{
std::cout << "'" << which.first << "': \"" << which.second.get_value<std::string>() << "\"\n";
}
}
}
}
It prints
'Parameter'
'<xmlattr>'
'name': "box"
I hope you can see what you need to do (likely an unexpected level of nodes in the tree?). To get directly to the leaf node:
pt.get_child("Parameter.<xmlattr>.name").get_value<std::string>()

how copy from one stringstream object to another in C++?

I have std::stringstream object ss1. Now, I would like to create another copy from this one.
I try this:
std::stringstream ss2 = ss1;
or:
std::stringstream ss2(ss1)
neither works
The error message is like this:
std::ios::basic_ios(const std::ios &) is not accessible from
bsl::basic_stringstream,
bsl::allocator>::basic_stringstream(const
bsl::basic_stringstream,
bsl::allocator>&).
Indeed, streams are non-copyable (though they are movable).
Depending on your usage, the following works quite well:
#include <iostream>
#include <sstream>
int main()
{
std::stringstream ss1;
ss1 << "some " << 123 << " stuff" << std::flush;
std::stringstream ss2;
ss2 << ss1.rdbuf(); // copy everything inside ss1's buffer to ss2's buffer
std::cout << ss1.str() << std::endl;
std::cout << ss2.str() << std::endl;
}
Output:
some 123 stuff
some 123 stuff
As std::stringstream does not provide a copy constructor, you have to build it from the std::string ss1outputs:
std::stringstream ss2(ss1.str());