File Coverage

blib/lib/AtteanX/Parser/SPARQLXML/SAXHandler.pm
Criterion Covered Total %
statement 94 113 83.1
branch 34 48 70.8
condition 2 7 28.5
subroutine 13 13 100.0
pod 4 4 100.0
total 147 185 79.4


line stmt bran cond sub pod time code
1             # AtteanX::Parser::SPARQLXML::SAXHandler
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             AtteanX::Parser::SPARQLXML::SAXHandler - XML parser for SPARQL XML Results format
7              
8             =head1 VERSION
9              
10             This document describes AtteanX::Parser::SPARQLXML::SAXHandler version 0.032
11              
12             =head1 STATUS
13              
14             This module's API and functionality should be considered unstable.
15             In the future, this module may change in backwards-incompatible ways,
16             or be removed entirely.
17              
18             =head1 SYNOPSIS
19              
20             use AtteanX::Parser::SPARQLXML::SAXHandler;
21              
22             =head1 METHODS
23              
24             =over 4
25              
26             =cut
27              
28              
29             use v5.14;
30 4     4   56 use warnings;
  4         17  
31 4     4   32  
  4         10  
  4         99  
32             use Attean;
33 4     4   22 use Scalar::Util qw(refaddr);
  4         7  
  4         25  
34 4     4   27 use base qw(XML::SAX::Base);
  4         8  
  4         201  
35 4     4   29 use Attean;
  4         8  
  4         1207  
36 4     4   15657 use namespace::clean;
  4         17  
  4         38  
37 4     4   24  
  4         16  
  4         30  
38             my %strings;
39             my %tagstack;
40             my %results;
41             my %values;
42             my %bindings;
43             my %booleans;
44             my %variables;
45             my %has_head;
46             my %has_end;
47             my %result_count;
48             my %result_handlers;
49             my %config;
50             my %triples;
51              
52             my %expecting_string = map { $_ => 1 } qw(boolean bnode uri literal);
53              
54             =item C<< new ( [ \&handler ] ) >>
55              
56             Returns a new XML::SAX handler object. If C<< &handler >> is supplied, it will
57             be called with a variable bindings object as each is parsed, bypassing the
58             normal process of collecting the results for retrieval via an iterator object.
59              
60             =cut
61              
62             my $class = shift;
63             my $self = $class->SUPER::new();
64 3     3 1 37 if (@_) {
65 3         43 my $addr = refaddr( $self );
66 3 50       249 my $code = shift;
67 3         16 my $args = shift || {};
68 3         7 $result_handlers{ $addr } = $code;
69 3   50     16 $config{ $addr } = { %$args };
70 3         11 }
71 3         12 return $self;
72             }
73 3         9  
74             =begin private
75              
76             =item C<< start_element >>
77              
78             =cut
79              
80             my $self = shift;
81             my $el = shift;
82             my $tag = $el->{LocalName};
83 55     55 1 22097 my $addr = refaddr( $self );
84 55         87
85 55         86 unshift( @{ $tagstack{ $addr } }, [$tag, $el] );
86 55         129 if ($expecting_string{ $tag }) {
87             $strings{ $addr } = '';
88 55         71 }
  55         159  
89 55 100       147
90 15         30 if ($tag eq 'triple') {
91             push(@{ $triples{ $addr } }, {});
92             }
93 55 50       152 }
94 0         0  
  0         0  
95             =item C<< end_element >>
96              
97             =cut
98              
99             my $self = shift;
100             my $class = ref($self);
101             my $eel = shift;
102             my $addr = refaddr( $self );
103 55     55 1 6805 my $string = $strings{ $addr };
104 55         99 my $taginfo = shift( @{ $tagstack{ $addr } } );
105 55         76 my ($tag, $el) = @$taginfo;
106 55         118
107 55         100 if ($tag eq 'head') {
108 55         70 $has_head{ $addr } = 1;
  55         105  
109 55         112 if (my $code = $result_handlers{ $addr }) {
110             if ($config{ $addr }{ variables }) {
111 55 100       283 $code->( $variables{ $addr } );
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
112 3         9 }
113 3 50       14 }
114 3 50       17 } elsif ($tag eq 'sparql') {
115 0         0 $has_end{ $addr } = 1;
116             } elsif ($tag eq 'variable') {
117             push( @{ $variables{ $addr } }, $el->{Attributes}{'{}name'}{Value});
118             } elsif ($tag eq 'boolean') {
119 3         14 $booleans{ $addr } = ($string eq 'true') ? 1 : 0;
120             if ($string =~ /^(?:true|false)$/ and my $code = $result_handlers{ $addr }) {
121 11         16 $code->( Attean::Literal->$string() );
  11         51  
122             }
123 0 0       0 } elsif ($tag eq 'binding') {
124 0 0 0     0 my $name = $el->{Attributes}{'{}name'}{Value};
125 0         0 my $value = delete( $values{ $addr } );
126             $bindings{ $addr }{ $name } = $value;
127             } elsif ($tag eq 'result') {
128 15         34 my $result = delete( $bindings{ $addr } ) || {};
129 15         44 $result_count{ $addr }++;
130 15         59 my $vb = Attean::Result->new( bindings => $result );
131             if (my $code = $result_handlers{ $addr }) {
132 5   50     23 $code->( $vb );
133 5         14 } else {
134 5         106 push( @{ $results{ $addr } }, $vb );
135 5 50       258 }
136 5         27 } elsif ($tag eq 'bnode') {
137             $values{ $addr } = Attean::Blank->new( $string );
138 0         0 } elsif ($tag eq 'uri') {
  0         0  
139             $values{ $addr } = Attean::IRI->new( $string );
140             } elsif ($tag eq 'literal') {
141 2         63 my ($lang, $dt);
142             if (my $dtinf = $el->{Attributes}{'{}datatype'}) {
143 7         148 $dt = $dtinf->{Value};
144             $values{ $addr } = Attean::Literal->new( value => $string, datatype => $dt );
145 6         15 } elsif (my $langinf = $el->{Attributes}{'{http://www.w3.org/XML/1998/namespace}lang'}) {
146 6 100       31 $lang = $langinf->{Value};
    100          
147 3         7 $values{ $addr } = Attean::Literal->new( value => $string, language => $lang );
148 3         72 } else {
149             $values{ $addr } = Attean::Literal->new( value => $string );
150 2         5 }
151 2         40 } elsif ($tag eq 'subject') {
152             my $value = delete( $values{ $addr } );
153 1         25 $triples{ $addr }[-1]{$tag} = $value;
154             } elsif ($tag eq 'predicate') {
155             my $value = delete( $values{ $addr } );
156 0         0 $triples{ $addr }[-1]{$tag} = $value;
157 0         0 } elsif ($tag eq 'object') {
158             my $value = delete( $values{ $addr } );
159 0         0 $triples{ $addr }[-1]{$tag} = $value;
160 0         0 } elsif ($tag eq 'triple') {
161             my $data = pop(@{ $triples{ $addr } });
162 0         0 my $t = Attean::Triple->new( %{ $data } );
163 0         0 $values{ $addr } = $t;
164             }
165 0         0 }
  0         0  
166 0         0  
  0         0  
167 0         0 =item C<< characters >>
168              
169             =cut
170              
171             my $self = shift;
172             my $data = shift;
173             my $addr = refaddr( $self );
174            
175             my $tag = $self->_current_tag;
176 76     76 1 8017 if ($expecting_string{ $tag }) {
177 76         97 my $chars = $data->{Data};
178 76         164 $strings{ $addr } .= $chars;
179             }
180 76         166 }
181 76 100       209  
182 15         33 my $self = shift;
183 15         38 my $addr = refaddr( $self );
184             return $tagstack{ $addr }[0][0];
185             }
186              
187             my $self = shift;
188 76     76   98 my $addr = refaddr( $self );
189 76         129 delete $strings{ $addr };
190 76         167 delete $results{ $addr };
191             delete $tagstack{ $addr };
192             delete $values{ $addr };
193             delete $bindings{ $addr };
194 3     3   820 delete $booleans{ $addr };
195 3         12 delete $variables{ $addr };
196 3         9 delete $has_head{ $addr };
197 3         9 delete $has_end{ $addr };
198 3         6 delete $result_count{ $addr };
199 3         6 delete $result_handlers{ $addr };
200 3         5 delete $config{ $addr };
201 3         6 }
202 3         10  
203 3         5  
204 3         7 1;
205 3         7  
206 3         8  
207 3         42 =end private
208              
209             =back
210              
211             =head1 BUGS
212              
213             Please report any bugs or feature requests to through the GitHub web interface
214             at L<https://github.com/kasei/perlrdf/issues>.
215              
216             =head1 AUTHOR
217              
218             Gregory Todd Williams C<< <gwilliams@cpan.org> >>
219              
220             =head1 COPYRIGHT
221              
222             Copyright (c) 2014--2022 Gregory Todd Williams. This
223             program is free software; you can redistribute it and/or modify it under
224             the same terms as Perl itself.
225              
226             =cut