views:

126

answers:

3

I want to decode all the HTML entities in a complicated data structure. Basically I'm looking for a "super map()" function. Here's what I have so far:

sub _html_decode {
    my $self = shift;
    my $ref = shift;

    if (ref($ref) eq "HASH") {
        $self->_html_decode_hash($ref)
    }
    if (ref($ref) eq "ARRAY") {
        $self->_html_decode_array($ref);
    }

}

sub _html_decode_array {
    my $self = shift;
    my $ref = shift;

    unless (@$ref) {return;}

    foreach (0 .. (scalar(@$ref) - 1)) {
        if (ref($ref->[$_]) eq "HASH") {
            $self->_html_decode_hash($ref->[$_]);
        }
        if (ref($ref->[$_]) eq "ARRAY") {
            $self->_html_decode_array($ref->[$_]);
        }
        else {
            $ref->[$_] = decode_entities($ref->[$_]);
        }
    }
}

sub _html_decode_hash {
    my $self = shift;
    my $ref = shift;

    unless (%$ref) {return;}

    while (my ($k, $v) = each %$ref) {
        if (ref($v) eq "HASH") {
            $self->_html_decode_hash($v);
        }
        if (ref($v) eq "ARRAY") {
            $self->_html_decode_array($v)
        }
        else {
            $ref->{$k} = decode_entities($v);
        }
    }
}
+3  A: 

I think this should do, but I haven't tested it.

sub _html_decode {
    my ($self, $ref) = @_;

    if (ref($ref) eq "HASH") {
        for my $value (values %{$ref}) {
            $self->_html_decode($value);
        }
    }
    elsif (ref($ref) eq "ARRAY") {
        for my $value (@{$ref}) {
            $self->_html_decode($value);
        }
    }
    else {
        $_[1] = decode_entities($_[1]);
    }
}

I admit the last part isn't pretty though.

Leon Timmermans
+3  A: 

To execute a subroutine on every element of an arbitrary complex data structure, check out the Visitor design pattern. Basically, your data structure is an object that knows what elements it still needs to process and it applies your subroutine to them. There is also a bit of the Iterator pattern there because you figure out how to

I have an example in my Netscape::Bookmarks module. That data structure is deeply nested with several different sorts of objects. By using the Visitor pattern, most of the complexity went away.

Besides that, you might want to check out my Object::Iterate module. It has an imap function that works with objects instead of lists. I stole the idea of __next__ from Python and applied it to Perl.

brian d foy
+2  A: 

Data::Rmap seems to do this as well. Does anyone have any experience with this module?

Horace Loeb
No experience with it, but it sounds like the best solution to the problem.
Leon Timmermans
Yes. I've used this module and highly recommend it as a first choice for this kind of problem.
dreftymac