How can I execute a given function on every elemen

2019-07-23 13:46发布

问题:

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);
        }
    }
}

回答1:

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.



回答2:

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.



回答3:

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