File Coverage

lib/Apache/Solr/XML.pm
Criterion Covered Total %
statement 63 157 40.1
branch 24 48 50.0
condition 2 36 5.5
subroutine 14 26 53.8
pod 3 5 60.0
total 106 272 38.9


line stmt bran cond sub pod time code
1             # Copyrights 2012-2022 by [Mark Overmeer].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.03.
5             # This code is part of distribution Apache-Solr. Meta-POD processed with
6             # OODoc into POD and HTML manual-pages. See README.md
7             # Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
8              
9             package Apache::Solr::XML;
10 5     5   3517 use vars '$VERSION';
  5         19  
  5         253  
11             $VERSION = '1.07';
12              
13 5     5   24 use base 'Apache::Solr';
  5         11  
  5         984  
14              
15 5     5   30 use warnings;
  5         7  
  5         138  
16 5     5   21 use strict;
  5         21  
  5         127  
17              
18 5     5   51 use Log::Report qw(solr);
  5         6  
  5         34  
19              
20 5     5   2829 use Apache::Solr::Result ();
  5         8  
  5         104  
21 5     5   1648 use XML::LibXML::Simple ();
  5         117175  
  5         112  
22 5     5   28 use HTTP::Message ();
  5         8  
  5         86  
23 5     5   23 use HTTP::Request ();
  5         8  
  5         87  
24 5     5   19 use Scalar::Util qw(blessed);
  5         9  
  5         211  
25              
26 5     5   25 use Data::Dumper;
  5         8  
  5         7952  
27             $Data::Dumper::Indent = 1;
28             $Data::Dumper::Quotekeys = 0;
29              
30             # See the XML::LibXML::Simple manual page
31             my @xml_decode_config =
32             ( ForceArray => []
33             , ContentKey => '_'
34             , KeyAttr => []
35             );
36             sub _cleanup_parsed($);
37              
38              
39             sub init($)
40 4     4 0 10 { my ($self, $args) = @_;
41 4   50     26 $args->{format} ||= 'XML';
42              
43 4         23 $self->SUPER::init($args);
44              
45 4         37 $self->{ASX_simple} = XML::LibXML::Simple->new(@xml_decode_config);
46 4         196 $self;
47             }
48              
49             #---------------
50 10     10 1 3246 sub xmlsimple() {shift->{ASX_simple}}
51              
52             #--------------------------
53              
54             sub _select($$)
55 0     0   0 { my ($self, $args, $params) = @_;
56 0         0 my @params = @$params;
57              
58             # select can be called automatically, more than once. We do not
59             # want to add 'wt' each call.
60 0         0 my %params = @params;
61 0 0       0 unshift @params, wt => 'xml' unless $params{wt};
62              
63 0         0 my $endpoint = $self->endpoint('select', params => \@params);
64 0         0 my $result = Apache::Solr::Result->new(%$args,
65             params => \@params , endpoint => $endpoint, core => $self);
66 0         0 $self->request($endpoint, $result);
67 0         0 $result;
68             }
69              
70             sub _extract($$$)
71 0     0   0 { my ($self, $params, $data, $ct) = @_;
72 0         0 my @params = (wt => 'xml', @$params);
73 0         0 my $endpoint = $self->endpoint('update/extract', params => \@params);
74 0         0 my $result = Apache::Solr::Result->new(params => \@params
75             , endpoint => $endpoint, core => $self);
76 0         0 $self->request($endpoint, $result, $data, $ct);
77 0         0 $result;
78             }
79              
80             sub _add($$$)
81 0     0   0 { my ($self, $docs, $attrs, $params) = @_;
82 0   0     0 $attrs ||= {};
83 0   0     0 $params ||= {};
84              
85 0         0 my $doc = XML::LibXML::Document->new('1.0', 'UTF-8');
86 0         0 my $add = $doc->createElement('add');
87 0         0 $add->setAttribute($_ => $attrs->{$_}) for sort keys %$attrs;
88              
89             $add->addChild($self->_doc2xml($doc, $_))
90 0         0 for @$docs;
91              
92 0         0 $doc->setDocumentElement($add);
93              
94 0         0 my @params = (wt => 'xml', %$params);
95 0         0 my $endpoint = $self->endpoint('update', params => \@params);
96 0         0 my $result = Apache::Solr::Result->new(params => \@params
97             , endpoint => $endpoint, core => $self);
98 0         0 $self->request($endpoint, $result, $doc);
99 0         0 $result;
100             }
101              
102             sub _doc2xml($$$)
103 0     0   0 { my ($self, $doc, $this) = @_;
104              
105 0         0 my $node = $doc->createElement('doc');
106 0   0     0 my $boost = $this->boost || 1.0;
107 0 0       0 $node->setAttribute(boost => $boost) if $boost != 1.0;
108              
109 0         0 foreach my $field ($this->fields)
110 0         0 { my $fnode = $doc->createElement('field');
111 0         0 $fnode->setAttribute(name => $field->{name});
112              
113 0   0     0 my $boost = $field->{boost} || 1.0;
114 0 0 0     0 $fnode->setAttribute(boost => $boost)
115             if $boost < 0.9999 || $boost > 1.0001;
116              
117             $fnode->setAttribute(update => $field->{update})
118 0 0       0 if defined $field->{update};
119              
120 0         0 $fnode->appendText($field->{content});
121 0         0 $node->addChild($fnode);
122             }
123 0         0 $node;
124             }
125              
126 0     0   0 sub _commit($) { my ($s, $attr) = @_; $s->simpleUpdate(commit => $attr) }
  0         0  
127 0     0   0 sub _optimize($) { my ($s, $attr) = @_; $s->simpleUpdate(optimize => $attr) }
  0         0  
128 0     0   0 sub _delete($$) { my $self = shift; $self->simpleUpdate(delete => @_) }
  0         0  
129 0     0   0 sub _rollback() { shift->simpleUpdate('rollback') }
130              
131             sub _terms($)
132 0     0   0 { my ($self, $terms) = @_;
133              
134 0         0 my @params = (wt => 'xml', @$terms);
135 0         0 my $endpoint = $self->endpoint('terms', params => \@params);
136 0         0 my $result = Apache::Solr::Result->new(params => \@params
137             , endpoint => $endpoint, core => $self);
138              
139 0         0 $self->request($endpoint, $result);
140              
141 0   0     0 my $table = $result->decoded->{terms} || {};
142 0         0 while(my ($field, $terms) = each %$table)
143             { my @terms = map [ $_ => $terms->{$_} ]
144 0         0 , sort {$terms->{$b} <=> $terms->{$a}}
  0         0  
145             keys %$terms;
146 0         0 $result->terms($field => \@terms);
147             }
148              
149 0         0 $result;
150             }
151              
152             #--------------------------
153              
154             sub request($$;$$)
155 0     0 0 0 { my ($self, $url, $result, $body, $body_ct) = @_;
156              
157 0 0 0     0 if(blessed $body && $body->isa('XML::LibXML::Document'))
158 0   0     0 { $body_ct ||= 'text/xml; charset=utf-8';
159 0         0 $body = \$body->toString;
160             }
161              
162 0         0 my $resp = $self->SUPER::request($url, $result, $body, $body_ct);
163 0         0 my $ct = $resp->content_type;
164             #warn $resp->as_string;
165 0 0       0 $ct =~ m/xml/i or return $result;
166              
167 0   0     0 my $dec = $self->xmlsimple->XMLin(
168             $resp->decoded_content || $resp->content,
169             parseropts => {huge => 1},
170             );
171              
172             #warn Dumper $dec;
173 0         0 $result->decoded(_cleanup_parsed $dec);
174 0         0 $result;
175             }
176              
177             sub _cleanup_parsed($)
178 92     92   19230 { my $data = shift;
179              
180 92 100       149 if(!ref $data) { return $data }
  17 100       29  
    50          
    0          
181             elsif(ref $data eq 'HASH')
182 68         183 { my %d = %$data; # start with shallow copy
183              
184             # Hash
185 68 100       122 if(my $lst = delete $d{lst})
186 23 100       43 { foreach (ref $lst eq 'ARRAY' ? @$lst : $lst)
187 34         39 { my $name = delete $_->{name};
188 34         60 $d{$name} = $_;
189             }
190             }
191              
192             # Array
193 68 100       105 if(my $arr = delete $d{arr})
194 3 50       5 { foreach (ref $arr eq 'ARRAY' ? @$arr : $arr)
195 6         8 { my $name = delete $_->{name};
196 6         11 my ($type, $values) = %$_;
197 6 100       10 $values = [$values] if ref $values ne 'ARRAY';
198 6         11 $d{$name} = $values;
199             }
200             }
201              
202             # XXX haven't found a clear list of what can be expected here
203 68         70 foreach my $type (qw/int long float double bool date str text/)
204 544 100       713 { my $items = delete $d{$type} or next;
205 30 100       53 foreach (ref $items eq 'ARRAY' ? @$items : $items)
206             { my ($name, $value)
207 82 100       186 = ref $_ eq 'HASH' ? ($_->{name}, $_->{_}) : ('', $_);
208 82 100 33     99 $value = $value eq 'true' || $_->{_} eq 1
209             if $type eq 'bool';
210 82         144 $d{$name} = $value;
211             }
212             }
213              
214 68         121 foreach my $key (keys %d)
215 186 100       321 { $d{$key} = _cleanup_parsed($d{$key}) if ref $d{$key};
216             }
217 68         197 return \%d;
218             }
219             elsif(ref $data eq 'ARRAY')
220 7         12 { return [ map _cleanup_parsed($_), @$data ];
221             }
222             elsif(ref $data eq 'DateTime')
223 0           { return $data;
224             }
225 0   0       else {panic ref $data || $data}
226             }
227              
228              
229             sub simpleUpdate($$;$)
230 0     0 1   { my ($self, $command, $attrs, $content) = @_;
231 0   0       $attrs ||= {};
232 0           my @params = (wt => 'xml', commit => delete $attrs->{commit});
233 0           my $endpoint = $self->endpoint('update', params => \@params);
234 0           my $result = Apache::Solr::Result->new(params => \@params
235             , endpoint => $endpoint, core => $self);
236              
237 0           my $doc = $self->simpleDocument($command, $attrs, $content);
238 0           $self->request($endpoint, $result, $doc);
239 0           $result;
240             }
241              
242              
243             sub simpleDocument($;$$)
244 0     0 1   { my ($self, $command, $attrs, $content) = @_;
245 0           my $doc = XML::LibXML::Document->new('1.0', 'UTF-8');
246 0           my $top = $doc->createElement($command);
247 0           $doc->setDocumentElement($top);
248              
249 0   0       $attrs ||= {};
250 0           $top->setAttribute($_ => $attrs->{$_}) for sort keys %$attrs;
251              
252 0 0 0       if(!defined $content) {}
    0          
253             elsif(ref $content eq 'HASH' || ref $content eq 'ARRAY')
254 0 0         { my @c = ref $content eq 'HASH' ? %$content : @$content;
255 0           while(@c)
256 0           { my ($name, $values) = (shift @c, shift @c);
257 0 0         foreach my $value (ref $values eq 'ARRAY' ? @$values : $values)
258 0           { my $node = $doc->createElement($name);
259 0           $node->appendText($value);
260 0           $top->addChild($node);
261             }
262             }
263             }
264             else
265 0           { $top->appendText($content);
266             }
267 0           $doc;
268             }
269              
270             1;