File Coverage

blib/lib/XML/XForms/Generator/Model.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package XML::XForms::Generator::Model;
2             ######################################################################
3             ## ##
4             ## Package: Model.pm ##
5             ## Author: D. Hageman ##
6             ## ##
7             ## Description: ##
8             ## ##
9             ## Perl object to assist in the generation of XML compliant with ##
10             ## the W3's XForms specification. ##
11             ## ##
12             ######################################################################
13              
14             ##==================================================================##
15             ## Libraries and Variables ##
16             ##==================================================================##
17              
18             require 5.006;
19             require Exporter;
20              
21 5     5   4442 use strict;
  5         11  
  5         309  
22 5     5   29 use warnings;
  5         10  
  5         126  
23              
24 5     5   38 use Carp;
  5         10  
  5         405  
25 5     5   2359 use XML::LibXML;
  0            
  0            
26             use XML::XForms::Generator::Common;
27              
28             our @ISA = qw( Exporter XML::LibXML::Element );
29              
30             our @EXPORT = qw( xforms_model );
31              
32             our $VERSION = "0.70";
33              
34             ##==================================================================##
35             ## Constructor(s)/Deconstructor(s) ##
36             ##==================================================================##
37              
38             ##----------------------------------------------##
39             ## new ##
40             ##----------------------------------------------##
41             ## XForms::Model default contstructor. ##
42             ##----------------------------------------------##
43             sub new
44             {
45             ## Pull in what type of an object we will be.
46             my $type = shift;
47             ## Pull in any arguments provided to the constructor.
48             my $attributes = shift;
49             my @children = @_;
50             ## The object we are generating is going to be a child class of
51             ## XML::LibXML's DOM objects.
52             my $self = XML::LibXML::Element->new( 'model' );
53             ## Determine what exact class we will be blessing this instance into.
54             my $class = ref( $type ) || $type;
55             ## Bless the class for it is good [tm].
56             bless( $self, $class );
57             ## We need to set our namespace on our model element and activate it.
58             $self->setNamespace( $XFORMS_NAMESPACE{xforms}, "xforms", 1 );
59             ## Determine if we have an 'id' attribute and set it if we do.
60             __xforms_attribute( $self, $attributes );
61             __xforms_children( $self, @children );
62             ## Send it back to the caller all happy like.
63             return( $self );
64             }
65              
66             ##----------------------------------------------##
67             ## DESTROY ##
68             ##----------------------------------------------##
69             ## XForms::Model default deconstructor. ##
70             ##----------------------------------------------##
71             sub DESTROY
72             {
73             ## This is mainly a placeholder to keep things like mod_perl happy.
74             return;
75             }
76              
77             ##==================================================================##
78             ## Method(s) ##
79             ##==================================================================##
80              
81             ## Loop through all of the extension elements building convience methods
82             ## as we go along.
83             no strict 'refs';
84              
85             foreach my $element ( @XFORMS_MODEL_ELEMENT )
86             {
87             ## We need to temporarily remove the namespace prefix for our work.
88             $element =~ s/^xforms://g;
89              
90             ##----------------------------------------------##
91             ## appendCHILDENAME ##
92             ##----------------------------------------------##
93             ## Method generation for the common child ##
94             ## elements of the model element. ##
95             ##----------------------------------------------##
96             *{ "append" . ucfirst( $element ) } =
97             sub {
98              
99             my( $self, $attributes, @children ) = @_;
100              
101             my $node = XML::LibXML::Element->new( $element );
102              
103             $self->appendChild( $node );
104              
105             $node->setNamespace( $XFORMS_NAMESPACE{xforms}, "xforms", 1 );
106              
107             __xforms_attribute( $node, $attributes );
108             __xforms_children( $node, @children );
109              
110             return( $node );
111             };
112              
113             ##----------------------------------------------##
114             ## getCHILDENAME ##
115             ##----------------------------------------------##
116             ## Method generation for the retrieval of ##
117             ## common model elements. ##
118             ##----------------------------------------------##
119             *{ "get" . ucfirst( $element ) } =
120             sub {
121              
122             my $self = shift;
123            
124             my @nodes =
125             $self->getChildrenByTagName( "xforms:$element" );
126            
127             return( @nodes );
128             };
129             }
130              
131             use strict 'refs';
132              
133             ##----------------------------------------------##
134             ## bindControl ##
135             ##----------------------------------------------##
136             ## Method used to associate a control with a ##
137             ## model's instance data. ##
138             ##----------------------------------------------##
139             sub bindControl ($$$$)
140             {
141             my( $self, $control, $bind, $value ) = @_;
142              
143             my( $instance ) = $self->getInstance();
144              
145             if( !defined( $instance ) )
146             {
147             croak( qq|Error: Model element requires an instance child |,
148             qq|element before controls can be bound to it.| );
149             }
150              
151             ## We really want the child element of the instance node.
152             $instance = $instance->firstChild;
153              
154             if( ( defined( $bind ) ) &&
155             ( ref( $bind ) ) &&
156             ( $bind->isa( "XML::LibXML::Node" ) ) )
157             {
158             ## The first case exists when we are giving a prebuilt
159             ## binding node.
160             my @attributes = $bind->attributes;
161             my @children = $bind->childNodes;
162              
163             my $attributes = {};
164              
165             foreach( @attributes )
166             {
167             $attributes->{$_->nodeName} = $_->getValue();
168             }
169            
170             ## We need to ensure we grab a copy of the nodeset and id attributes
171             ## here because appendBind is destructive.
172             $bind = $attributes->{nodeset};
173             my $id = $attributes->{id};
174            
175             ## We don't attach the node that was passed in, but rather
176             ## we create another using it. This allows us to do some
177             ## error/consistancy checking.
178             $self->appendBind( $attributes, @children );
179            
180             ## The second case is when we are just given a XPath to
181             ## to the instance data.
182             $bind =~ s/^\/+//g;
183             $bind =~ s/\/+/\//g;
184            
185             ## We need to set the 'bind' attribute on the node.
186             $control->setAttribute( 'bind', $id);
187             $control->removeAttribute( 'ref' );
188            
189             }
190             elsif( defined( $bind ) )
191             {
192             ## The second case is when we are just given a XPath to
193             ## to the instance data.
194             $bind =~ s/^\/+//g;
195             $bind =~ s/\/+/\//g;
196              
197             ## We need to set the 'ref' attribute on the node.
198             $control->setAttribute( 'ref', $bind );
199             $control->removeAttribute( 'bind' );
200             }
201             else
202             {
203             ## The last case is the hope that the control element
204             ## already contains an 'ref' element.
205             $bind = $control->getAttribute( "ref" );
206              
207             if( !defined( $bind ) )
208             {
209             croak( qq|Error: A binding expression must already exist on |,
210             qq|the control element or one must be supplied | );
211             }
212              
213             ## Clean the binding expression ...
214             $bind =~ s/^\/+//g;
215             $bind =~ s/\/+/\//g;
216            
217             ## We will reset it to ensure that the clean version is used.
218             $control->setAttribute( 'ref', $bind );
219             $control->removeAttribute( 'bind' );
220             }
221              
222             ## Break up the XPath statement into chunks.
223             my @path = split( /\//, $bind );
224              
225             ## Loop through each of the @path statements to ensure and build
226             ## the XPath to the instance data.
227             for( my $search = 0; $search < scalar( @path ); $search++ )
228             {
229             my( $node ) = $instance->getChildrenByTagName( $path[ $search ] );
230              
231             ## Check to see if the node is already defined.
232             if( !defined( $node ) )
233             {
234             my $element = XML::LibXML::Element->new( $path[ $search ] );
235             $instance = $instance->appendChild( $element );
236             }
237             else
238             {
239             $instance = $node;
240             }
241             }
242            
243             ## Look to see if any nodes exist under the current node.
244             if( $instance->hasChildNodes() )
245             {
246             $instance->removeChildNodes();
247             }
248              
249             ## Check to see if the value is text or a node.
250             if( ( ref( $value ) ) && ( $value->isa( "XML::LibXML::Node" ) ) )
251             {
252             $instance->appendChild( $value );
253             }
254             else
255             {
256             my $text = XML::LibXML::Text->new( $value );
257             $instance->appendChild( $text );
258             ## The below causes a segfault. Need to figure that one out.
259             ##$instance->appendText( $value );
260             }
261            
262             ## I want to make sure that we properly associate this control
263             ## with the proper model.
264             $control->setAttribute( 'model', $self->getAttribute( "id" ) );
265              
266             return( $instance );
267             }
268              
269             ##----------------------------------------------##
270             ## setInstanceData ##
271             ##----------------------------------------------##
272             ## Convience method for setting instance data ##
273             ## in the model element. ##
274             ##----------------------------------------------##
275             sub setInstanceData ($$$)
276             {
277             my( $self, $bind, $value ) = @_;
278              
279             ## We make sure that $value is defined purely for the removal of
280             ## perl warning messages.
281             if( !defined( $value ) )
282             {
283             $value = "";
284             }
285              
286             my( $instance ) = $self->getInstance();
287              
288             if( !defined( $instance ) )
289             {
290             croak( qq|Error: Model element requires an instance child |,
291             qq|element before controls can be bound to it.| );
292             }
293              
294             ## We really want the child element of the instance node.
295             $instance = $instance->firstChild;
296              
297             ## Clean up our binding expression a bit ...
298             $bind =~ s/^\/+//g;
299             $bind =~ s/\/+/\//g;
300              
301             ## Break up the XPath statement into chunks.
302             my @path = split( /\//, $bind );
303              
304             ## Loop through each of the @path statements to ensure and build
305             ## the XPath to the instance data.
306             for( my $search = 0; $search < scalar( @path ); $search++ )
307             {
308             my( $node ) = $instance->getChildrenByTagName( $path[ $search ] );
309              
310             ## Check to see if the node is already defined.
311             if( !defined( $node ) )
312             {
313             my $element = XML::LibXML::Element->new( $path[ $search ] );
314             $instance = $instance->appendChild( $element );
315             }
316             else
317             {
318             $instance = $node;
319             }
320             }
321            
322             ## Look to see if any nodes exist under the current node.
323             if( $instance->hasChildNodes() )
324             {
325             $instance->removeChildNodes();
326             }
327              
328             ## Check to see if the value is text or a node.
329             if( ( ref( $value ) ) &&
330             ( ref( $value ) ne "ARRAY" ) &&
331             ( ref( $value ) ne "HASH" ) &&
332             ( ref( $value ) ne "SCALAR" ) &&
333             ( ref( $value ) ne "CODE" ) &&
334             ( ref( $value ) ne "REF" ) &&
335             ( ref( $value ) ne "LVALUE" ) &&
336             ( ref( $value ) ne "GLOB" ) &&
337             ( $value->isa( "XML::LibXML::Node" ) ) )
338             {
339             $instance->appendChild( $value );
340             }
341             else
342             {
343             my $text = XML::LibXML::Text->new( $value );
344             $instance->appendChild( $text );
345             ## The below causes a segfault. Need to figure that one out.
346             ##$instance->appendText( $value );
347             }
348              
349             return( $instance );
350             }
351              
352             ##==================================================================##
353             ## Function(s) ##
354             ##==================================================================##
355              
356             ##----------------------------------------------##
357             ## xforms_model ##
358             ##----------------------------------------------##
359             ## Alias for the default constructor. ##
360             ##----------------------------------------------##
361             sub xforms_model
362             {
363             return( XML::XForms::Generator::Model->new( @_ ) );
364             }
365              
366             ##==================================================================##
367             ## Internal Function(s) ##
368             ##==================================================================##
369              
370             ##
371             ## None.
372             ##
373              
374             ##==================================================================##
375             ## End of Code ##
376             ##==================================================================##
377             1;
378              
379             ##==================================================================##
380             ## Plain Old Documentation (POD) ##
381             ##==================================================================##
382              
383             __END__