1

I am using boost::property_tree to read and write xml configuration files. I want to change the value of some tags in my code and write them back to file, with some reasonable xml formatting (new lines, indenting, etc.).

Currently I am using

std::fstream fs("filename");
boost::property_tree::ptree pt;
bpt::xml_parser::read_xml(fs,pt);

// replace value
pt.erase("tagname");
pt.put("tagname",newval);

bpt::xml_parser::xml_writer_settings<char> xmlstyle(' ',4);
bpt::xml_parser::write_xml("filename",pt,std::locale(),xmlstyle);

But it seems that every time a tag is deleted, it leaves behind a blank line and after some iterations the xml becomes unreadable. Is there a way to remove empty lines from the property tree itself or from the resulting xml file using boost?

I know there are other ways of removing the newlines by reading and parsing the entire file again, but I was hoping for a more convenient one-liner.

mattu
  • 944
  • 11
  • 24

2 Answers2

3

Ok, it looks like the answer was already out there on Stack Overflow, I just hadn't found it (newlines were not mentioned in the post)

boost::property_tree XML pretty printing

The solution is to read the file with boost::property_tree::xml_parser::trim_whitespace

Community
  • 1
  • 1
mattu
  • 944
  • 11
  • 24
2

Not Boost, but blank lines in particular. You can use std::regex_replace() on the output before it is written to the file, removing the blank lines, like this

std::regex_replace(std::ostreambuf_iterator<char>(fout), text.begin(), text.end(), std::regex("(\\n+)"), "\n");

With fout as the file output stream and text as the output data as a std::string.

This replaces every newline followed by another newline w/o any characters in between with a single newline.

FallenWarrior
  • 656
  • 3
  • 16
  • I see how your regex would replace redundant new lines in case you have a file output stream and the text given as a string. But as far as I understand i don't have either of those in the above code sample, so how would I make this work with the sample code from my question? – mattu Dec 15 '16 at 14:47
  • I see you already found a solution, but I'm still going to elaborate on this because it could be useful at some point. You begin by extracting the file contents into a `std::string text` and then declaring a `std::stringstream sstream`. Then you call the above function but pass the string stream instead of the file stream. Finally, you call `read_xml()` with the string stream instead of the file stream. – FallenWarrior Dec 15 '16 at 17:00
  • Your answer helped me because I want to preserve whitespace (particularly newline) on input, and then format the output neatly. I modified your code to do this: `boost::property_tree::xml_writer_settings settings('\t', 1); std::ostringstream text_out; boost::property_tree::write_xml(text_out, tree, settings); std::ofstream fout("filename", std::ios::out | std::ios::binary | std::ios::trunc); const std::string & text_str = text_out.str(); std::regex_replace(std::ostreambuf_iterator(fout), text_str.begin(), text_str.end(), std::regex("(\\n([ \\t]*\\n)+)"), "\n"); ` – kshepherd Sep 10 '18 at 13:06