Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

Re^2: Keeping Order with YAML::XS

by walkingthecow (Friar)
on Jul 29, 2013 at 05:46 UTC ( #1046775=note: print w/replies, xml ) Need Help??

in reply to Re: Keeping Order with YAML::XS
in thread Keeping Order with YAML::XS

I can load a file without issues, and it creates what I am expecting. The issue comes when trying to dump it back. Here's an example:

path: /export/home/frank options: - param: i value: 1001 - param: f - param: x value: eyes arguments: - value: test
Here's the Perl code:

Perl Code
#!/usr/bin/env perl use strict; use warnings; use YAML::XS qw(LoadFile DumpFile); use Data::Dumper; my $data = LoadFile('test.yaml'); print Dumper($data); DumpFile('out.yaml', $data);
And here's the output yaml (out.yaml) that it creates:

--- arguments: - value: test options: - param: i value: 1001 - param: f - param: x value: eyes path: /export/home/frank
Notice that in the input file the syntax was in such a way that it was an ordered sequence (from what I am understanding of YAML anyway). Yet, in the output it is no longer ordered at all. I am trying to figure out from a Perl data structure how to make an ordered YAML file like what is the input.

Replies are listed 'Best First'.
Re^3: Keeping Order with YAML::XS
by Loops (Curate) on Jul 29, 2013 at 06:20 UTC
    Why do you say that the input is creating what you're expecting? The in.yaml you give above produces:
    { arguments => [{ value => "test" }], options => [ { param => "i", value => 1001 }, { param => "f" }, { param => "x", value => "eyes" }, ], path => "/export/home/frank", }

    IE. the top level items (arguments,options,path) are in a hash, which is an unordered set in Perl. You've lost your ordering on input, not on output. Unless you're talking about the options? In which case both formats are equivalent, at least to the YAML::XS loader which creates the same data structures in both cases.

    In what external context does the yaml produced by YAML::XS cause a problem? Because both formats generate the same data structures in Perl and therefore should be interchangeable without issue.

      Ahhh, yes! But, here's the thing. How do I create a data structure that is ordered. I mean, I realize that hashes are unordered, but I'd like to create an ordered YAML sequence from a data structure. The problem is, an ordered YAML sequence looks the same Perl hash structure wise (from input) as an unordered YAML on output. I need the YAML to be ordered, and my issue is creating the data structure that makes that.

        I would think that using a pure Perl YAML encoder together with Tie::IxHash should keep the order of the keys. See AM's reply below, that doesn't seem to work :-(

        If your data structure is reasonably fixed, you might even get through by using a text template and filling in the values. Usually that means having a machine-readable data schema to generate the template first.

        The ordered data structure you're dreaming of is an array. It is an ordered sequence and there is an example of it in the data structure created when parsing either YAML format of the data in question. If you want to create an ordered sequence in the YAML output, use a Perl array.

        From YAML spec 1.2:

        # Ordered maps are represented as # A sequence of mappings, with # each mapping having one key --- !!omap - Mark McGwire: 65 - Sammy Sosa: 63 - Ken Griffy: 58

        Which produces this Perl data structure

        [ { "Mark McGwire" => 65 }, { "Sammy Sosa" => 63 }, { "Ken Griffy" => 58 }, ]

        So lets duplicate that with your data

        [ { path => "/export/home/frank" }, { options => [ { param => "i", value => 1001 }, { param => "f" }, { param => "x", value => "eyes" }, {}, { param => "b", value => "toes" }, { param => "p" }, ], }, { arguments => [{ value => "test" }] }, ]
        Which produces the format suggested by the YAML spec:
        --- - path: /export/home/frank - options: - param: i value: '1001' - param: f - param: x value: eyes - {} - param: b value: toes - param: p - arguments: - value: test

        So we see how to create ordered mappings in both YAML and in Perl. YAML::XS is doing exactly the right thing because Perl hashes are not ordered, therefore it outputs them as unordered mappings. So the real question is which Perl data structure you're going to use to represent Ordered Mappings, because Perl hashes can't do that job and arrays of individual hashes aren't convenient.

        Several people have suggested Tie::IxHash and this is a very good choice. But since YAML::XS sees it as just a regular hash, it outputs in unordered YAML notation. You will have to preprocess your data structures to convert IxHash's into arrays of individual mappings and reverse the process when loading.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1046775]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2017-04-30 20:40 GMT
Find Nodes?
    Voting Booth?
    I'm a fool:

    Results (542 votes). Check out past polls.