How can I execute a given function for each element of a complex data structure in Perl?

I want to decode all HTML entities in a complex data structure. Basically I'm looking for the "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);
        }
    }
}

      

+1


source to share


3 answers


Data :: Rmap seems to do this too. Does anyone have experience with this module?



+2


source


I think it should be done, 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 that the last part is not very good.

+3


source


To execute a subroutine for each element of an arbitrary complex data structure, check the Visitor Design Pattern. Basically, your data structure is an object that knows what elements it still needs to process and applies its subroutine to them. There is also a little Iterator pattern, because you figured out how

I have an example in the Netscape :: Bookmarks module . This data structure is deeply nested by several different types of objects. By using the visitor template, most of the complexity went away.

Alternatively, you can check my Object :: Iterate . It has a function imap

that works with objects instead of lists. I stole an idea __next__

from Python and applied it to Perl.

+3


source







All Articles