Boost read/write XML file: how to change the characters encoding?

3.7k Views Asked by At

I'm trying to read/write an XML file, using Boost functions read_xml and write_xml. The XML file original encoding is "windows-1252", but after the read/write operations, the encoding became "utf-8".

This is the XML original file:

<?xml version="1.0" encoding="windows-1252" standalone="no" ?>
<lot>
  <name>Lot1</name>
  <lot_id>123</lot_id>
  <descr></descr>
  <job>
    <name>TEST</name>
    <num_items>2</num_items>
    <item>
      <label>Item1</label>
      <descr>Item First Test</descr>
    </item>
    <item>
      <label>Item2</label>
      <descr>Item Second Test</descr>
    </item>
  </job>
</lot>

And this is the output one:

<?xml version="1.0" encoding="utf-8"?>
<lot>
    &#10;&#10;  &#10;&#10;  &#10;&#10;  &#10;&#10;  &#10;&#10;  &#10;&#10;  &#10;&#10;  &#10;&#10;
  <name>Lot1</name>
  <lot_id>123</lot_id>
  <descr></descr>
  <job>
    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;    &#10;  
    <name>TEST</name>
    <num_items>2</num_items>
    <item>
      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;    
      <label>Item1</label>
      <descr>Item First Test</descr>
    </item>
    <item>
      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;      &#10;    
      <label>Item2</label>
      <descr>Item Second Test</descr>
    </item>
  </job>
</lot>

This is my C++ code (just a test code):

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
using boost::property_tree::ptree;

ptree xmlTree;
read_xml(FILE_XML, xmlTree);

for (auto it = xmlTreeChild.begin(); it != xmlTreeChild.end();)
{
    std::string strItem = it->first.data();
    if (strcmp(strItem.c_str(), "item") == 0)
    {
        std::string strLabel = it->second.get_child("label").data();
        if (strcmp(strLabel.c_str(), "item3") != 0)
        {
            it = xmlTreeChild.erase(it);
        }
    }       
    ++it;
}

auto settings = boost::property_tree::xml_writer_make_settings<std::string>('\t', 1);
write_xml(FILE_XML, xmlTree, std::locale(), settings);

I need to read and re-write the file using the same encoding from the original file. I've tried also to change the Locale settings, using:

std::locale newlocale1("English_USA.1252");
read_xml(FILE_XML, xmlTree, 0, newlocale1);
...
auto settings = boost::property_tree::xml_writer_make_settings<std::string>('\t', 1);
write_xml(FILE_XML, xmlTree, newlocale1, settings);

but I've got the same result.

How can I be able to read and write, using the original file encoding, with Boost functions?

Thank you

3

There are 3 best solutions below

0
On

To fix the problem you experience you have to replace this line:

read_xml(FILE_XML, xmlTree); 

with

read_xml(FILE_XML, 
         xmlTree, 
         boost::property_tree::xml_parser::trim_whitespace); 

as far as I know your issue cannot be fixed only by modifying the settings of the write_xml function.

I tried it and worked: when I compare the files ignoring the whitespaces, the input and output xml files are identical.

0
On

You can pass an encoding via the writer settings:

auto settings = boost::property_tree::xml_writer_make_settings<std::string>(
    '\t', 1, "windows-1252");

Of course, make sure key/values are in fact latin1/cp1252 compatible (this makes sense as long as you read all the information from the source file; however you have to take care when e.g. assigning user input to a property tree node; you might need to convert from the input encoding to cp1252 first).

Live On Coliru

0
On

You can also write to a string stream as following:

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

boost::property_tree::ptree pt;
std::ostringstream oss;
write_xml(
    oss, pt,
    boost::property_tree::xml_writer_make_settings<char>(
                  '\t', 0, "ASCII"));