#
# Copyright (c) 2015,2020 Christian Jaeger, copying@christianjaeger.ch
#
# This is free software, offered under either the same terms as perl 5
# or the terms of the Artistic License version 2 or the terms of the
# MIT License (Expat version). See the file COPYING.md that came
# bundled with this file.
#
=head1 NAME
PXML::Util - utility functions for PXML trees
=head1 SYNOPSIS
=head1 DESCRIPTION
=head1 NOTE
This is alpha software! Read the status section in the package README
or on the L
foobar5678
'; TEST { pxml_eager_map( t_data, sub { $_[0]->name_update(sub { $_[0] . "A" }) }, sub { ($_[0] // "-") . "." } )->string } '[][p]foo.[p][b|p]bar.[b|p]-.[b|p]5.[b|p]6.[b|p]7.[b|p]8.
'; TEST { pxml_deferred_map( t_data, sub { my ($e, $uplist, $inferior_map) = @_; $e->body_update( sub { my ($body) = @_; cons( uplist_show($uplist), $e->name eq "b" ? do { my $s = stream_mixed_flatten $body; cons(&$inferior_map(car $s), cdr $s ) } : &$inferior_map($body) ) } ); }, sub { my ($v, $uplist) = @_; uplist_show($uplist) . ($v // "-") . "." } )->string } '[][p]foo.[p][b|p]bar.5678
'; sub pxml_map_elements { @_ >= 2 and @_ <= 3 or fp_croak_arity "2-3"; my ($v, $name_to_mapper, $maybe_otherfn) = @_; pxml_eager_map( $v, sub { my ($e, $uplist) = @_; if (my ($mapper) = hash_perhaps_ref $name_to_mapper, $e->name) { &$mapper($e, $uplist) } else { $e } }, $maybe_otherfn ); } # A variant of pxml_map_elements that applies mapper functions to # their result until there's none left or the result matches the same # function again (the latter rule is so that mapper functions can # return the same element type that they match, i.e. modify elements # instead of replacing them) # (do you have a better name?) sub pxml_map_elements_exhaustively { @_ >= 2 and @_ <= 3 or fp_croak_arity "2-3"; my ($v, $name_to_mapper, $maybe_otherfn) = @_; pxml_eager_map( $v, sub { my ($e, $uplist) = @_; LP: { my $name = $e->name; if (my ($mapper) = hash_perhaps_ref $name_to_mapper, $name) { my $v = &$mapper($e, $uplist); if (is_pxml_element $v) { $e = $v; if ($e->name eq $name) { $e } else { redo LP } } else { $v } } else { $e } } }, $maybe_otherfn ); } sub t_exh { my ($map) = @_; &$map( P(A({ href => "fun" }, "hey"), B(CODE("boo")), B("fi")), { # a mapper does not go into an endless loop: a => sub { my ($e, $uplist) = @_; $e->attribute_set(href => "foo") }, # b mapper's output, if a, still goes through the above as # well in the 'exhaustively' test; also, return value does not # need to be an element. (XX NOTE that a list around an # element, even if the element is the only list value, will # stop exhaustive processing!) b => sub { my ($e, $uplist) = @_; if (is_pxml_element stream_mixed_flatten($e->body)->first) { A({ name => "x" }, $e->body) } else { $e->body } } } )->string } TEST { t_exh \&pxml_map_elements } ''; TEST { t_exh \&pxml_map_elements_exhaustively } ''; 1