File Coverage

lib/HTML/Object/DOM/XPathResult.pm
Criterion Covered Total %
statement 27 70 38.5
branch 0 20 0.0
condition n/a
subroutine 9 20 45.0
pod 11 11 100.0
total 47 121 38.8


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## HTML Object - ~/lib/HTML/Object/DOM/XPathResult.pm
3             ## Version v0.2.0
4             ## Copyright(c) 2022 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest <jack@deguest.jp>
6             ## Created 2022/01/01
7             ## Modified 2022/09/18
8             ## All rights reserved
9             ##
10             ##
11             ## This program is free software; you can redistribute it and/or modify it
12             ## under the same terms as Perl itself.
13             ##----------------------------------------------------------------------------
14             package HTML::Object::DOM::XPathResult;
15             BEGIN
16             {
17 1     1   1053 use strict;
  1         4  
  1         32  
18 1     1   4 use warnings;
  1         2  
  1         30  
19 1     1   7 use parent qw( Module::Generic );
  1         2  
  1         4  
20 1     1   60 use vars qw( @EXPORT %EXPORT_TAGS $VERSION );
  1         3  
  1         74  
21 1     1   7 use HTML::Object::Exception;
  1         3  
  1         8  
22             use constant {
23             # A result set containing whatever type naturally results from evaluation of the expression. Note that if the result is a node-set then UNORDERED_NODE_ITERATOR_TYPE is always the resulting type.
24 1         224 ANY_TYPE => 0,
25             # A result containing a single number. This is useful for example, in an XPath expression using the count() function.
26             NUMBER_TYPE => 1,
27             # A result containing a single string.
28             STRING_TYPE => 2,
29             # A result containing a single boolean value. This is useful for example, in an XPath expression using the not() function.
30             BOOLEAN_TYPE => 3,
31             # A result node-set containing all the nodes matching the expression. The nodes may not necessarily be in the same order that they appear in the document.
32             UNORDERED_NODE_ITERATOR_TYPE => 4,
33             # A result node-set containing all the nodes matching the expression. The nodes in the result set are in the same order that they appear in the document.
34             ORDERED_NODE_ITERATOR_TYPE => 5,
35             # A result node-set containing snapshots of all the nodes matching the expression. The nodes may not necessarily be in the same order that they appear in the document.
36             UNORDERED_NODE_SNAPSHOT_TYPE => 6,
37             # A result node-set containing snapshots of all the nodes matching the expression. The nodes in the result set are in the same order that they appear in the document.
38             ORDERED_NODE_SNAPSHOT_TYPE => 7,
39             # A result node-set containing any single node that matches the expression. The node is not necessarily the first node in the document that matches the expression.
40             ANY_UNORDERED_NODE_TYPE => 8,
41             # A result node-set containing the first node in the document that matches the expression.
42             FIRST_ORDERED_NODE_TYPE => 9,
43 1     1   325 };
  1         3  
44 1     1   7 our @EXPORT = qw(
45             ANY_TYPE NUMBER_TYPE STRING_TYPE BOOLEAN_TYPE
46             UNORDERED_NODE_ITERATOR_TYPE ORDERED_NODE_ITERATOR_TYPE
47             UNORDERED_NODE_SNAPSHOT_TYPE ORDERED_NODE_SNAPSHOT_TYPE
48             ANY_UNORDERED_NODE_TYPE FIRST_ORDERED_NODE_TYPE
49             );
50 1         5 our %EXPORT_TAGS = (
51             all => [qw(
52             ANY_TYPE NUMBER_TYPE STRING_TYPE BOOLEAN_TYPE
53             UNORDERED_NODE_ITERATOR_TYPE ORDERED_NODE_ITERATOR_TYPE
54             UNORDERED_NODE_SNAPSHOT_TYPE ORDERED_NODE_SNAPSHOT_TYPE
55             ANY_UNORDERED_NODE_TYPE FIRST_ORDERED_NODE_TYPE
56             )]
57             );
58 1         19 our $VERSION = 'v0.2.0';
59             };
60              
61 1     1   6 use strict;
  1         3  
  1         30  
62 1     1   6 use warnings;
  1         2  
  1         662  
63              
64             sub init
65             {
66 0     0 1   my $self = shift( @_ );
67 0           $self->{result} = undef;
68             # Any type, by default
69 0           $self->{resulttype} = 0;
70 0           $self->{_init_strict_use_sub} = 1;
71 0 0         $self->SUPER::init( @_ ) || return( $self->pass_error );
72 0           $self->{_pos} = 0;
73 0           return( $self );
74             }
75              
76             # Note: property booleanValue read-only
77             sub booleanValue
78             {
79 0     0 1   my $self = shift( @_ );
80 0           my $res = $self->result;
81 0 0         return( $self->error({
82             message => 'Result is not a boolean',
83             class => 'HTML::Object::TypeError',
84             }) ) if( !$self->_is_a( $res => 'HTML::Object::XPath::Boolean' ) );
85 0           return( $res );
86             }
87              
88             # Note: property invalidIteratorState read-only
89 0     0 1   sub invalidIteratorState : lvalue { return( shift->_set_get_property( 'invaliditeratorstate', @_ ) ); }
90              
91             sub iterateNext
92             {
93 0     0 1   my $self = shift( @_ );
94 0           my $res = $self->result;
95 0 0         return( $self->error({
96             message => 'Result is not a NodeSet',
97             class => 'HTML::Object::TypeError',
98             }) ) if( !$self->_is_a( $res => 'HTML::Object::XPath::NodeSet' ) );
99 0 0         return if( $self->{_pos} >= $res->size );
100 0           my $node = $res->index( $self->{_pos} );
101 0           $self->{_pos}++;
102 0           return( $node );
103             }
104              
105             # Note: property numberValue read-only
106             sub numberValue
107             {
108 0     0 1   my $self = shift( @_ );
109 0           my $res = $self->result;
110 0 0         return( $self->error({
111             message => 'Result is not a number',
112             class => 'HTML::Object::TypeError',
113             }) ) if( !$self->_is_a( $res => 'HTML::Object::XPath::Number' ) );
114 0           return( $res );
115             }
116              
117             # Note: method to store the result, which is an object of various class, so we use _set_get
118 0     0 1   sub result { return( shift->_set_get( 'result', @_ ) ); }
119              
120             # Note: property resultType read-only
121 0     0 1   sub resultType : lvalue { return( shift->_set_get_number( 'resulttype', @_ ) ); }
122              
123             # Note: property singleNodeValue read-only
124             sub singleNodeValue
125             {
126 0     0 1   my $self = shift( @_ );
127 0           my $res = $self->result;
128 0 0         return( $self->error({
129             message => 'Result is not a node (HTML::Object::DOM::Node)',
130             class => 'HTML::Object::TypeError',
131             }) ) if( !$self->_is_a( $res => 'HTML::Object::DOM::Node' ) );
132 0           return( $res );
133             }
134              
135             sub snapshotItem
136             {
137 0     0 1   my $self = shift( @_ );
138 0           my $res = $self->result;
139 0 0         if( $self->_is_a( $res => 'HTML::Object::XPath::NodeSet' ) )
140             {
141 0           return( $res->[ $self->{_pos} ] );
142             }
143             else
144             {
145 0           return( $res );
146             }
147             }
148              
149             # Note: property snapshotLength read-only
150             sub snapshotLength
151             {
152 0     0 1   my $self = shift( @_ );
153 0           my $res = $self->result;
154 0 0         if( $self->_is_a( $res => 'HTML::Object::XPath::NodeSet' ) )
155             {
156 0           return( $res->size );
157             }
158             else
159             {
160 0 0         return( ref( $res ) ? 1 : 0 );
161             }
162             }
163              
164             # Note: property stringValue read-only
165             sub stringValue
166             {
167 0     0 1   my $self = shift( @_ );
168 0           my $res = $self->result;
169 0 0         return( $self->error({
170             message => 'Result is not a string (HTML::Object::XPath::Literal)',
171             class => 'HTML::Object::TypeError',
172             }) ) if( !$self->_is_a( $res => 'HTML::Object::XPath::Literal' ) );
173 0           return( $res );
174             }
175              
176             1;
177             # NOTE: POD
178             __END__
179              
180             =encoding utf-8
181              
182             =head1 NAME
183              
184             HTML::Object::DOM::XPathResult - HTML Object DOM XPath Result Class
185              
186             =head1 SYNOPSIS
187              
188             use HTML::Object::DOM::XPathResult;
189             my $result = HTML::Object::DOM::XPathResult->new ||
190             die( HTML::Object::DOM::XPathResult->error, "\n" );
191              
192             =head1 VERSION
193              
194             v0.2.0
195              
196             =head1 DESCRIPTION
197              
198             The C<XPathResult> interface represents the results generated by evaluating an XPath expression within the context of a given L<node|HTML::Object::DOM::Node>.
199              
200             The method you can access vary depending on the type of results returned. The XPath evaluation can return a L<boolean|HTML::Object::XPath::Boolean>, a L<number|HTML::Object::XPath::Number>, a L<string|HTML::Object::XPath::Literal>, or a L<node set|HTML::Object::XPath::NodeSet>
201              
202             =head1 PROPERTIES
203              
204             All properties are read-only, but you can change their returned value by changing the value of L</result>, which contains the result from the XPath search.
205              
206             =head2 booleanValue
207              
208             A boolean representing the value of the result if resultType is C<BOOLEAN_TYPE>, i.e. if the result is a boolean.
209              
210             Example:
211              
212             <div>XPath example</div>
213             <p>Text is 'XPath example': <output></output></p>
214              
215             my $xpath = "//div/text() = 'XPath example'";
216             my $result = $doc->evaluate( $xpath, $doc );
217             $doc->querySelector( 'output' )->textContent = $result->booleanValue;
218              
219             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/booleanValue>
220              
221             =head2 invalidIteratorState
222              
223             This always return C<undef> under perl, but you can change the value of this boolean to whatever boolean value you want.
224              
225             Normally, under JavaScript, this signifies that the iterator has become invalid. It is true if resultType is UNORDERED_NODE_ITERATOR_TYPE or ORDERED_NODE_ITERATOR_TYPE and the document has been modified since this result was returned.
226              
227             Example:
228              
229             <div>XPath example</div>
230             <p>Iterator state: <output></output></p>
231              
232             my $xpath = '//div';
233             my $result = $doc->evaluate( $xpath, $doc );
234             # Invalidates the iterator state
235             $doc->querySelector( 'div' )->remove();
236             $doc->querySelector( 'output' )->textContent = $result->invalidIteratorState ? 'invalid' : 'valid';
237              
238             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/invalidIteratorState>
239              
240             =head2 numberValue
241              
242             A number representing the value of the result if resultType is C<NUMBER_TYPE>, i.e. if the result is a number.
243              
244             Example:
245              
246             <div>XPath example</div>
247             <div>Number of &lt;div&gt;s: <output></output></div>
248              
249             my $xpath = 'count(//div)';
250             my $result = $doc->evaluate( $xpath, $doc );
251             $doc->querySelector( 'output' )->textContent = $result->numberValue;
252              
253             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/numberValue>
254              
255             =head2 result
256              
257             Sets or gets the resulting object from the XPath search. This could be a L<node|HTML::Object::DOM::Node>, a L<boolean|HTML::Object::XPath::Boolean>, a L<number|HTML::Object::XPath::Number>, a L<string|HTML::Object::XPath::Literal>, or a L<set of nodes|HTML::Object::XPath::NodeSet>
258              
259             =head2 resultType
260              
261             A number code representing the type of the result, as defined by the type constants. See L</CONSTANTS>
262              
263             Example:
264              
265             <div>XPath example</div>
266             <div>Is XPath result a node set: <output></output></div>
267              
268             use HTML::Object::DOM::XPathResult;
269             # or
270             use HTML::Object::DOM qw( :xpath );
271             my $xpath = '//div';
272             my $result = $doc->evaluate( $xpath, $doc );
273             $doc->querySelector( 'output' )->textContent =
274             $result->resultType >= UNORDERED_NODE_ITERATOR_TYPE &&
275             $result->resultType <= FIRST_ORDERED_NODE_TYPE;
276              
277             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/resultType>
278              
279             =head2 singleNodeValue
280              
281             A Node representing the value of the single node result, which may be C<undef>. This is set when the result is a single L<node|HTML::Object::DOM::Node>.
282              
283             Example:
284              
285             <div>XPath example</div>
286             <div>Tag name of the element having the text content 'XPath example': <output></output></div>
287              
288             my $xpath = q{//*[text()='XPath example']};
289             my $result = $doc->evaluate( $xpath, $doc );
290             $doc->querySelector( 'output' )->textContent = $result->singleNodeValue->localName;
291              
292             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/singleNodeValue>
293              
294             =head2 snapshotLength
295              
296             The number of nodes in the result snapshot. As a divergence from the standard, this also applies to the number of elements in the L<NodeSet|HTML::Object::XPath::NodeSet> returned.
297              
298             Example:
299              
300             <div>XPath example</div>
301             <div>Number of matched nodes: <output></output></div>
302              
303             my $xpath = '//div';
304             my $result = $doc->evaluate( $xpath, $doc );
305             $doc->querySelector( 'output' )->textContent = $result->snapshotLength;
306              
307             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/snapshotLength>
308              
309             =head2 stringValue
310              
311             A string representing the value of the result if resultType is C<STRING_TYPE>, i.e. when the result is a string.
312              
313             Example:
314              
315             <div>XPath example</div>
316             <div>Text content of the &lt;div&gt; above: <output></output></div>
317              
318             my $xpath = '//div/text()';
319             my $result = $doc->evaluate( $xpath, $doc );
320             $doc->querySelector( 'output' )->textContent = $result->stringValue;
321              
322             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/stringValue>
323              
324             =head1 METHODS
325              
326             =head2 iterateNext
327              
328             If the result is a L<node set|HTML::Object::XPath::NodeSet>, this method iterates over it and returns the next node from it or C<undef> if there are no more nodes.
329              
330             Example:
331              
332             <div>XPath example</div>
333             <div>Tag names of the matched nodes: <output></output></div>
334              
335             use Module::Generic::Array;
336             my $xpath = '//div';
337             my $result = $doc->evaluate( $xpath, $doc );
338             my $node;
339             my $tagNames = Module::Generic::Array->new;
340             while( $node = $result->iterateNext() )
341             {
342             $tagNames->push( $node->localName );
343             }
344             $doc->querySelector( 'output' )->textContent = $tagNames->join( ', ' );
345              
346             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/iterateNext>
347              
348             =head2 snapshotItem
349              
350             Returns an item of the snapshot collection or C<undef> in case the index is not within the range of nodes.
351              
352             Normally, under JavaScript, unlike the iterator result, the snapshot does not become invalid, but may not correspond to the current document if it is mutated.
353              
354             Example:
355              
356             <div>XPath example</div>
357             <div>Tag names of the matched nodes: <output></output></div>
358              
359             use Module::Generic::Array;
360             my $xpath = '//div';
361             my $result = $doc->evaluate( $xpath, $doc );
362             my $node;
363             my $tagNames = Module::Generic::Array->new;
364             for( my $i = 0; $i < $result->snapshotLength; $i++ )
365             {
366             my $node = $result->snapshotItem( $i );
367             $tagNames->push( $node->localName );
368             }
369             $doc->querySelector( 'output' )->textContent = $tagNames->join( ', ' );
370              
371             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/snapshotItem>
372              
373             =head1 CONSTANTS
374              
375             The following constants are exported by default:
376              
377             =over 4
378              
379             =item ANY_TYPE (0)
380              
381             A result set containing whatever type naturally results from evaluation of the expression. Note that if the result is a node-set then C<UNORDERED_NODE_ITERATOR_TYPE> is always the resulting type.
382              
383             =item NUMBER_TYPE (1)
384              
385             A result containing a single number. This is useful for example, in an XPath expression using the count() function.
386              
387             =item STRING_TYPE (2)
388              
389             A result containing a single string.
390              
391             =item BOOLEAN_TYPE (3)
392              
393             A result containing a single boolean value. This is useful for example, in an XPath expression using the not() function.
394              
395             =item UNORDERED_NODE_ITERATOR_TYPE (4)
396              
397             A result node-set containing all the nodes matching the expression. The nodes may not necessarily be in the same order that they appear in the document.
398              
399             =item ORDERED_NODE_ITERATOR_TYPE (5)
400              
401             A result node-set containing all the nodes matching the expression. The nodes in the result set are in the same order that they appear in the document.
402              
403             =item UNORDERED_NODE_SNAPSHOT_TYPE (6)
404              
405             A result node-set containing snapshots of all the nodes matching the expression. The nodes may not necessarily be in the same order that they appear in the document.
406              
407             =item ORDERED_NODE_SNAPSHOT_TYPE (7)
408              
409             A result node-set containing snapshots of all the nodes matching the expression. The nodes in the result set are in the same order that they appear in the document.
410              
411             =item ANY_UNORDERED_NODE_TYPE (8)
412              
413             A result node-set containing any single node that matches the expression. The node is not necessarily the first node in the document that matches the expression.
414              
415             =item FIRST_ORDERED_NODE_TYPE (9)
416              
417             A result node-set containing the first node in the document that matches the expression.
418              
419             =back
420              
421             =head1 AUTHOR
422              
423             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
424              
425             =head1 SEE ALSO
426              
427             L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/XPathResult>, L<W3C specifications|https://dom.spec.whatwg.org/#interface-xpathresult>
428              
429             =head1 COPYRIGHT & LICENSE
430              
431             Copyright(c) 2022 DEGUEST Pte. Ltd.
432              
433             All rights reserved
434              
435             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
436              
437             =cut