foreach (@$elements) { $_->{ delete $_->{name} } = delete $_->{value}; $_ = { $class->_reformat( Array::AsHash->new( { array => [%$_] } ) )->get_array }; }
Just because that's exactly what I needed for the problem at hand doesn't make me feel any better.
That’s very dense. Putting a new key/value pair in the hash at the same time as extracting it from the self-same hash is a real stumbler. The other statement is a lot less terrible, but reading a multiply nested multi-line expression is never fun. And it’s all in situ modifications. And all on $_
. Just using an actual variable name and linearising things a bit helps a heap:
foreach ( @$elements ) {
my $elt = Array::AsHash->new( { array => [ %$_ ] } );
my @kv = $elt->delete( 'name', 'value' );
$elt->put( @kv );
$_ = { $class->_reformat( $elt )->get_array };
}
The real train wreck is in flattening a hash only to pass it to Array::AsHash so the flat array can be treated like a hash by a method that will return something we can get as a flat list from which eventually a hash will be constructed… err, can busywork ever be more obviously such? I’d take a long hard look at why _reformat
method couldn’t take a hash directly (even if only to pass it into Array::AsHash implicitly…), and why there is not get_hash
method. Just to see the difference:
for my $elt ( @$elements ) {
my ( $name, $value ) = delete @{ $elt }{ 'name', 'value' };
$elt->{ $name } = $value;
$elt = $class->_reformat( $elt )->get_hash;
}
Compare with your original code.
Re:Why did you write it this way?
Ovid on 2008-02-22T12:09:27
I agree your code is clearer and it's certainly something I need to seriously rethink. It's part of Bermuda and I've been struggling with the YAML and JSON implementation. Basically, I've found that since we (the BBC) primarily need this for our XML representation, I've focused much energy on this. We'd like to take the same island file which maps an object to XML and use the same island to produce multiple serializations in XML, YAML, and JSON. Unfortunately, it's not extremely clear how to transform XML to the latter two formats since they don't have a natural representation of 'attributes'.
This confusion is getting reflected in my code as I continually struggle to make this work.
Also, I've noticed that your code and mine both contain the same bug, but that's only because you copied my logic without knowing the underlying data structure. An element might look like this:
{
attributes => { foo => 'bar' },
name => 'attributes',
value => 'huh?',
}Oops.
As I continue to refactor my code, I recognize that elements and attributes are virtually identical in how they're handled internally and my failure to pay attention to this up front is causing problems. For example, I thought that merely flattening the data structure would suffice for YAML and JSON, but it doesn't work when attributes and elements have the same name:
<card name="primary">
<name>John Q. Public</name>
</card>Re:Why did you write it this way?
Aristotle on 2008-02-22T12:30:56
A general serialisation of XML to JSON is a fool’s errand. It has come up numerous times in the Atom camp, and every time the discussion goes nowhere. You can of course define a full mapping of XML to JSON, but the result is nothing at all like how you’d express the same data if you were writing JSON by hand – you get one or two extra layers of indirection along every step of the way.
The only approach that yields usable results is to define a first-class serialisation of your domain model to JSON.
If you want specify both the XML and the JSON serialisation of a model using the same schema, then you’ll have to impose restrictions on the models your schema can express so that both serialisations are reduced to a common denominator. Then you won’t be able to specify arbitrary XML or JSON grammars with your schema language. (Then again, I already doubt you can handle all of XML. Processing instructions, anyone?)
But you can’t have it both ways, I’m afraid. That’s just how it is.