Birju Vachhani
Birju Vachhani

Reputation: 6373

How to write a map to a YAML file in Dart

I have a map of key value pairs in Dart. I want to convert it to YAML and write into a file.

I tried using YAML package from dart library but it only provides methods to load YAML data from a file. Nothing is mentioned on how to write it back to the YAML file.

Here is an example:

void main() {
  var map = {
    "name": "abc",
    "type": "unknown",
    "internal":{
      "name": "xyz"
    }
  };
  print(map);
}

Expected output: example.yaml

name: abc
type: unknown
internal:
  name: xyz

How to convert the dart map to YAML and write it to a file?

Upvotes: 6

Views: 1895

Answers (3)

Isaac Skelton
Isaac Skelton

Reputation: 186

It's a bit late of a response but for anyone else looking at this question I have written this class. It may not be perfect but it works for what I'm doing and I haven't found anything wrong with it yet. Might make it a package eventually after writing tests.

class YamlWriter {
  /// The amount of spaces for each level.
  final int spaces;

  /// Initialize the writer with the amount of [spaces] per level.
  YamlWriter({
    this.spaces = 2,
  });

  /// Write a dart structure to a YAML string. [yaml] should be a [Map] or [List].
  String write(dynamic yaml) {
    return _writeInternal(yaml).trim();
  }

  /// Write a dart structure to a YAML string. [yaml] should be a [Map] or [List].
  String _writeInternal(dynamic yaml, { int indent = 0 }) {
    String str = '';

    if (yaml is List) {
      str += _writeList(yaml, indent: indent);
    } else if (yaml is Map) {
      str += _writeMap(yaml, indent: indent);
    } else if (yaml is String) {
      str += "\"${yaml.replaceAll("\"", "\\\"")}\"";
    } else {
      str += yaml.toString();
    }


    return str;
  }

  /// Write a list to a YAML string.
  /// Pass the list in as [yaml] and indent it to the [indent] level.
  String _writeList(List yaml, { int indent = 0 }) {
    String str = '\n';

    for (var item in yaml) {
      str += "${_indent(indent)}- ${_writeInternal(item, indent: indent + 1)}\n";
    }

    return str;
  }

  /// Write a map to a YAML string.
  /// Pass the map in as [yaml] and indent it to the [indent] level.
  String _writeMap(Map yaml, { int indent = 0 }) {
    String str = '\n';

    for (var key in yaml.keys) {
      var value = yaml[key];
      str += "${_indent(indent)}${key.toString()}: ${_writeInternal(value, indent: indent + 1)}\n";
    }

    return str;
  }

  /// Create an indented string for the level with the spaces config.
  /// [indent] is the level of indent whereas [spaces] is the
  /// amount of spaces that the string should be indented by.
  String _indent(int indent) {
    return ''.padLeft(indent * spaces, ' ');
  }
}

Usage:

final writer = YamlWriter();
String yaml = writer.write({
  'string': 'Foo',
  'int': 1,
  'double': 3.14,
  'boolean': true,
  'list': [
    'Item One',
    'Item Two',
    true,
    'Item Four',
  ],
  'map': {
    'foo': 'bar',
    'list': ['Foo', 'Bar'],
  },
});

File file = File('/path/to/file.yaml');
file.createSync();
file.writeAsStringSync(yaml);

Output:

string: "Foo"
int: 1
double: 3.14
boolean: true
list: 
  - "Item One"
  - "Item Two"
  - true
  - "Item Four"

map: 
  foo: "bar"
  list: 
    - "Foo"
    - "Bar"

Upvotes: 6

Paul Mundt
Paul Mundt

Reputation: 509

I ran into the same issue and ended up hacking together a simple writer:

  // Save the updated configuration settings to the config file
  void saveConfig() {
    var file = _configFile;

    // truncate existing configuration
    file.writeAsStringSync('');

    // Write out new YAML document from JSON map
    final config = configToJson();
    config.forEach((key, value) {
      if (value is Map) {
        file.writeAsStringSync('\n$key:\n', mode: FileMode.writeOnlyAppend);
        value.forEach((subkey, subvalue) {
          file.writeAsStringSync('  $subkey: $subvalue\n',
              mode: FileMode.writeOnlyAppend);
        });
      } else {
        file.writeAsStringSync('$key: $value\n',
            mode: FileMode.writeOnlyAppend);
      }
    });
  }

Upvotes: 0

Kevin Moore
Kevin Moore

Reputation: 6171

package:yaml does not have YAML writing features. You may have to look for another package that does that – or write your own.

As as stopgap, remember JSON is valid YAML, so you can always write out JSON to a .yaml file and it should work with any YAML parser.

Upvotes: 2

Related Questions