Skip Menu |

This queue is for tickets about the XML-Twig CPAN distribution.

Report information
The Basics
Id: 127945
Status: open
Priority: 0/
Queue: XML-Twig

People
Owner: MIROD [...] cpan.org
Requestors: chrispitude [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 3.52
Fixed in: (no value)



Subject: Allow handlers to stack
It would be nice to allow handlers to "stack" when there are collisions. There are many times where the handlers intersect due to orthogonal but overlapping work that needs to be done. For example, both handlers should be invoked for <orange/> here: 'apple|orange|pear' => sub { $_->set_att('fruit', 1); }, 'red|orange|yellow' => sub { $_->set_att('color', 2); },
Subject: stack_handlers.pl
#!/usr/bin/perl use strict; use warnings; use XML::Twig; my $xml = <<EOF; <stuff> <apple/> <orange/> <pear/> <red/> <yellow/> </stuff> EOF my $twig=XML::Twig->new ( keep_encoding => 1, pi => 'drop', comments => 'keep' ); $twig->setTwigHandlers({ 'apple|orange|pear' => sub { $_->set_att('fruit', 1); }, 'red|orange|yellow' => sub { $_->set_att('color', 2); }, }); $twig->parse($xml); $twig->print(pretty_print => 'indented');
Subject: Re: [rt.cpan.org #127945] Allow handlers to stack
Date: Thu, 6 Dec 2018 20:47:20 +0100
To: bug-XML-Twig [...] rt.cpan.org
From: mirod <xmltwig [...] gmail.com>
On 06/12/2018 19:53, chrispitude@gmail.com via RT wrote: Show quoted text
> Thu Dec 06 13:53:27 2018: Request 127945 was acted upon. > Transaction: Ticket created by chrispitude@gmail.com > Queue: XML-Twig > Subject: Allow handlers to stack > Broken in: 3.52 > Severity: Wishlist > Owner: MIROD > Requestors: chrispitude@gmail.com > Status: new > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=127945 > > > > It would be nice to allow handlers to "stack" when there are collisions. There are many times where the handlers intersect due to orthogonal but overlapping work that needs to be done. > > For example, both handlers should be invoked for <orange/> here: > > 'apple|orange|pear' => sub { $_->set_att('fruit', 1); }, > 'red|orange|yellow' => sub { $_->set_att('color', 2); },
Handlers do stack, as long as they return a true value... except in this case. In this case, since the triggers include '|', they are expanded, and in effect the code is equivalent to this: apple => sub { $_->set_att('fruit', 1); }, orange => sub { $_->set_att('fruit', 1); }, pear => sub { $_->set_att('fruit', 1); }, red => sub { $_->set_att('color', 2); }, orange => sub { $_->set_att('color', 2); }, yellow => sub { $_->set_att('color', 2); } Since the second "orange" handler has the exact same trigger as the first one, it replaces it. This is by design, so you can replace a handler. Changing this would require quite a bit of rework of the internals of the module, a (small) speed penalty for everyone, and likely a convoluted way to tell the module to add the handler and not to replace it. One (ugly?) way to get this to work without changing the module is to have the second "orange" trigger be different from the first one, while still triggering for all the orange elements, by doing something like this: 'red|orange[!@dummy]|yellow' => sub { $_->set_att('color', 2); } Here there is no overlap, both handlers are kept, and trigger for all orange elements (I am assuming no orange element will ever have a "dummy" attribute).
Thinking out loud here... would it be possible to allow a special marker character to add uniqueness (+ in proof-of-concept below, but anything would work)? 'apple|orange|pear' => sub { $_->set_att('fruit', 1); }, 'red|orange+|yellow' => sub { $_->set_att('color', 2); }, 'order|orange++|orifice' => sub { $_->set_att('beginswithor', 3); }, The marker adds uniqueness when looking to replace handlers, but it would not come into play in determining the match. This is along the lines of the workaround you described, except the idea is to have a technique that (1) is more readable and (2) does not interfere with the handler ordering (tag name only, tag name with attributes, etc.). The burden is on the user to know if they want to replace orange, orange+, or orange++ when redefining a handler, which is completely fair. And this change would not affect the behavior of any existing scripts.