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.

Reply via email to