Issue Parsing File with YAML-CPP

2.6k views Asked by At

In the following code, I'm having some sort of issue getting my .yaml file parsed using parser.GetNextDocument(doc);. After much gross debugging, I've found that the (main) issue here is that my for loop is not running, due to doc.size() == 0; What am I doing wrong?

void
BookView::load()
{
  aBook.clear();

  QString fileName =
    QFileDialog::getOpenFileName(this, tr("Load Address Book"),
                 "", tr("Address Book (*.yaml);;All Files (*)"));
  if(fileName.isEmpty())
    {
      return;
    }
  else
    {
      try
    {
      std::ifstream fin(fileName.toStdString().c_str());
      YAML::Parser parser(fin);
      YAML::Node doc;
      std::map< std::string, std::string > entry;

      parser.GetNextDocument(doc);
      std::cout << doc.size();

      for( YAML::Iterator it = doc.begin(); it != doc.end(); it++  )
        {
          *it >> entry;
          aBook.push_back(entry);
        }

    }
      catch(YAML::ParserException &e)
    {
      std::cout << "YAML Exception caught: "
            << e.what()
            << std::endl;
    }
    }
  updateLayout( Navigating );
}

The .yaml file being read was generated using yaml-cpp, so I assume it is correctly formed YAML, but just in case, here's the file anyways.

^@^@^@\230---
-
  address: ******************
  comment: None.
  email: andrew(dot)levenson(at)gmail(dot)com
  name: Andrew Levenson
  phone: **********^@

Edit: By request, the emitting code:

void
BookView::save()
{
  QString fileName =
    QFileDialog::getSaveFileName(this, tr("Save Address Book"), "",
                 tr("Address Book (*.yaml);;All Files (*)"));
  if (fileName.isEmpty())
    {
      return;
    }
  else
    {
      QFile file(fileName);
      if(!file.open(QIODevice::WriteOnly))
    {
      QMessageBox::information(this, tr("Unable to open file"),
                   file.errorString());
      return;
    }

      std::vector< std::map< std::string, std::string > >::iterator itr;
      std::map< std::string, std::string >::iterator mItr;
      YAML::Emitter yaml;

      yaml << YAML::BeginSeq;
      for( itr = aBook.begin(); itr < aBook.end(); itr++ )
    {
      yaml << YAML::BeginMap;
      for( mItr = (*itr).begin(); mItr != (*itr).end(); mItr++ )
        {
          yaml << YAML::Key << (*mItr).first << YAML::Value << (*mItr).second;
        }
      yaml << YAML::EndMap;
    }
      yaml << YAML::EndSeq;

      QDataStream out(&file);
      out.setVersion(QDataStream::Qt_4_5);
      out << yaml.c_str();
    }      
}
1

There are 1 answers

3
Jesse Beder On BEST ANSWER

Along the lines of what you thought, the problem is that you're writing using QDataStream but reading using plain std::ifstream. You need to do either one or the other.

If you want to use the QDataStream, you'll need to read it in as well. Check out the doc for more detail, but it looks like you can just grab the YAML string:

QDataStream in(&file);
QString str;
in >> str;

and then pass it to yaml-cpp:

std::stringstream stream; // remember to include <sstream>
stream << str; // or str.toStdString() - I'm not sure about how QString works
YAML::Parser parser(stream);
// etc.

The point of a std::stringstream is to transform your string containing YAML into a stream that the YAML parser can read.