Thanks Chris, I'd come to a similar conclusion lying in bed last night. I'm actually going to turn things inside out - have a traversal object which can (optionally) create a data structure as a side-effect of running the traversal. The traversal will keep references (as needed) into the appropriate structures.
As for what I'm doing this for... the XML interaction is only one kind of traversal. The data structure is used internally to control a testing activity. The in-memory structure is the primary focus, with traversals for a variety of purposes. So, I wasn't looking at XML modules as the primary focus. Many operations will not involve XML at all. - read/write a structure from/to an external form - XML is used for initial definition of new structures, for dumping/editing to create new structures or modify existing ones - database is used for storage of defined structures - XML was also used for a previous test suite, so there will be at least one traversal that converts an alternate XML format - a text file (probably again XML, but maybe not) will be used for ephemeral structures, or huge ones that we don't want to put into the db - execute a test driver structure - does a read traversal of the execution structure and a create traversal of the result structure - generate a comparison - read traversal of two result structures (can be either an actual execution result or a expected result template) - generate a report - traverse a comparison - merge traversals for filtering - e.g. a performance comparison will skip over data result values and only stream the performance stats values One of the test execution types will be a "replay a series of activities extracted from the activity log files". In some cases, those extractions will be huge, and only used for a single series of test runs (sometimes even only for a single test run - the extraction might be done internally within the test run) and that would not be stored in the db. It also might not fit into memory as a single data structure, hence the desire for a streaming traversal that doesn't retain the entire structure. If XML does not support a streaming method of processing, I will definitely have to use a different format for the text file used for temporary/huge structures. (I was tempted to do that anyhow - I like readability in my text files and I find XML has too much control mixed in with the context to be easily read.) John Macdonald Morgan Stanley | Technology & Data 75 Queen Street | Suite 5400 Montreal, QC H3C2N6 Phone: +1 514 687-2615 john-421.macdon...@morganstanley.com -----Original Message----- From: perig...@gmail.com [mailto:perig...@gmail.com] On Behalf Of Chris Prather Sent: Friday, July 09, 2010 5:38 AM To: Macdonald, John (Enterprise Data) Cc: moose@perl.org Subject: Re: FW: removing a role in Moose This came up very recently in #moose as well. >> I see the doc about apply_all_roles to apply a role to an instance, but is >> there a way of removing or replacing a role? Not easily, the concept is a dangerous one to begin with. Once composed a role is *part of* a Class's definition. Further it makes promises about the interface that a class provides. While I can think of a half dozen ways to try to perform such a trick, none of them make sense when you realize that Moose has several other features that could provide a valid solution in nearly all cases. In this case, I would recommend delegation. >> I'm setting up a hierarchical data structure, with a class that defines the >> general aspects of the data structure and sub-classes for the component >> sub-structures. There will be methods for traversing the hierarchy. >> >> I want to have it possible for a particular node in the structure be in >> various states that can be altered dynamically. Here's an example of the >> sort of thing I want to do: >> >> my $tree = Class->create_from_XML( file=>$file, duration=>$duration ); >> >> The duration parameter would be one of qw( fill lazy stream ). >> >> >> - With 'fill', the XML file would be read and parsed and the entire >> structure created. >> >> >> - With 'lazy' or 'stream', the XML file would be opened and read >> far enough to create the top level class element only. >> >> >> The class would have methods for traversing the data structure. When a node >> was created with 'lazy' or 'stream', it would not actually be complete >> initially, but the first traversal method applied to it would cause the next >> level of nodes to be created. (For 'stream', when the traversal is finished >> with a particular node, the node is no longer retained.) >> >> What I was thinking of doing was to have traversal roles to define the >> traversal methods, and have a traverse_from_XML role (and similar roles for >> creation from other sources) that gets applied to the node initially, but >> then when the traversal actually hits the node, the methods in this role >> would read further into the XML input file, and then change the node so that >> it no longer had the traverse_from_XML role, but instead a >> traverse_loaded_node role would be applied to it. When the node traversal >> was complete, the child contents would be deleted and the node would be >> re-roled into a traverse_completed role that failed if a further traversal >> was attempted before the parent node had finished being traversed. I think a delegate would achieve the same result. If you have a set of Traversal objects that all perform a common interface (which can be a role) then you can simply swap the traversal object during your streaming. Something similar to the following should do the trick. package XML::Traversal; use Moose::Role; requires 'traverse'; package XML::Loader; use Moose; has traversal_engine => ( does => 'XML::Traversal', is => 'ro', writer => '_swap_traversal_engine', handles => 'XML::Traversal', default => sub { XML::TraversalEngine::XML->new($self) } ); sub _swap_to_node_traversal { $self->traversal_engine(XML::TraversalEngine::Node->new($self)) } sub _swap_to_terminal_traversal { $self->traversal_engine(XML::TraversalEngine::Termial->new($self)) } package XML::TraversalEngine::Terminal; use Moose; with qw(XML::Traversal); sub traverse { confess 'Already Have Terminal Traversal.' } >> However, when I read about method conflicts, I suspect that this whole >> approach is not going to work and that I need to accomplish my goal in a >> different way. >> >> Do you have any suggestions? I am curious as to what you're working on and if PRANG, XML::Toolkit, or XML::Rabbit might be of use. I know XML::Toolkit the best of these three and while it doesn't have lazy/stream parsing in the way you define it here, I can see how to implement something like that with some subclassing to set up a system similar to this. I suspect PRANG could work the same way. -Chris -------------------------------------------------------------------------- NOTICE: If received in error, please destroy, and notify sender. Sender does not intend to waive confidentiality or privilege. Use of this email is prohibited when received in error. We may monitor and store emails to the extent permitted by applicable law.