File: | C4/XSLT.pm |
Coverage: | 23.3% |
line | stmt | bran | cond | sub | time | code |
---|---|---|---|---|---|---|
1 | package C4::XSLT; | |||||
2 | # Copyright (C) 2006 LibLime | |||||
3 | # <jmf at liblime dot com> | |||||
4 | # Parts Copyright Katrin Fischer 2011 | |||||
5 | # Parts Copyright ByWater Solutions 2011 | |||||
6 | # | |||||
7 | # This file is part of Koha. | |||||
8 | # | |||||
9 | # Koha is free software; you can redistribute it and/or modify it under the | |||||
10 | # terms of the GNU General Public License as published by the Free Software | |||||
11 | # Foundation; either version 2 of the License, or (at your option) any later | |||||
12 | # version. | |||||
13 | # | |||||
14 | # Koha is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
15 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
16 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
17 | # | |||||
18 | # You should have received a copy of the GNU General Public License along | |||||
19 | # with Koha; if not, write to the Free Software Foundation, Inc., | |||||
20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||||
21 | ||||||
22 | 6 6 6 | 19430 17 165 | use strict; | |||
23 | 6 6 6 | 27 9 297 | use warnings; | |||
24 | ||||||
25 | 6 6 6 | 220 23 63 | use C4::Context; | |||
26 | 6 6 6 | 202 40 1174 | use C4::Branch; | |||
27 | 6 6 6 | 182 38 1638 | use C4::Items; | |||
28 | 6 6 6 | 53 151 2839 | use C4::Koha; | |||
29 | 6 6 6 | 52 21 3179 | use C4::Biblio; | |||
30 | 6 6 6 | 343 28 1970 | use C4::Circulation; | |||
31 | 6 6 6 | 48 24 2496 | use C4::Reserves; | |||
32 | 6 6 6 | 42 22 554 | use Encode; | |||
33 | 6 6 6 | 8338 109812 150 | use XML::LibXML; | |||
34 | 6 6 6 | 25021 97954 309 | use XML::LibXSLT; | |||
35 | ||||||
36 | 6 6 6 | 76 42 525 | use vars qw($VERSION @ISA @EXPORT); | |||
37 | ||||||
38 | BEGIN { | |||||
39 | 6 | 76 | require Exporter; | |||
40 | 6 | 35 | $VERSION = 0.03; | |||
41 | 6 | 87 | @ISA = qw(Exporter); | |||
42 | 6 | 10936 | @EXPORT = qw( | |||
43 | &XSLTParse4Display | |||||
44 | ); | |||||
45 | } | |||||
46 | ||||||
47 - 57 | =head1 NAME C4::XSLT - Functions for displaying XSLT-generated content =head1 FUNCTIONS =head2 transformMARCXML4XSLT Replaces codes with authorized values in a MARC::Record object =cut | |||||
58 | ||||||
59 | sub transformMARCXML4XSLT { | |||||
60 | 0 | my ($biblionumber, $record) = @_; | ||||
61 | 0 | my $frameworkcode = GetFrameworkCode($biblionumber) || ''; | ||||
62 | 0 | my $tagslib = &GetMarcStructure(1,$frameworkcode); | ||||
63 | 0 | my @fields; | ||||
64 | # FIXME: wish there was a better way to handle exceptions | |||||
65 | 0 | eval { | ||||
66 | 0 | @fields = $record->fields(); | ||||
67 | }; | |||||
68 | 0 0 0 | if ($@) { warn "PROBLEM WITH RECORD"; next; } | ||||
69 | 0 | my $av = getAuthorisedValues4MARCSubfields($frameworkcode); | ||||
70 | 0 | foreach my $tag ( keys %$av ) { | ||||
71 | 0 | foreach my $field ( $record->field( $tag ) ) { | ||||
72 | 0 | if ( $av->{ $tag } ) { | ||||
73 | 0 | my @new_subfields = (); | ||||
74 | 0 | for my $subfield ( $field->subfields() ) { | ||||
75 | 0 | my ( $letter, $value ) = @$subfield; | ||||
76 | 0 | $value = GetAuthorisedValueDesc( $tag, $letter, $value, '', $tagslib ) | ||||
77 | if $av->{ $tag }->{ $letter }; | |||||
78 | 0 | push( @new_subfields, $letter, $value ); | ||||
79 | } | |||||
80 | 0 | $field ->replace_with( MARC::Field->new( | ||||
81 | $tag, | |||||
82 | $field->indicator(1), | |||||
83 | $field->indicator(2), | |||||
84 | @new_subfields | |||||
85 | ) ); | |||||
86 | } | |||||
87 | } | |||||
88 | } | |||||
89 | 0 | return $record; | ||||
90 | } | |||||
91 | ||||||
92 - 96 | =head2 getAuthorisedValues4MARCSubfields Returns a ref of hash of ref of hash for tag -> letter controled by authorised values =cut | |||||
97 | ||||||
98 | # Cache for tagfield-tagsubfield to decode per framework. | |||||
99 | # Should be preferably be placed in Koha-core... | |||||
100 | my %authval_per_framework; | |||||
101 | ||||||
102 | sub getAuthorisedValues4MARCSubfields { | |||||
103 | 0 | my ($frameworkcode) = @_; | ||||
104 | 0 | unless ( $authval_per_framework{ $frameworkcode } ) { | ||||
105 | 0 | my $dbh = C4::Context->dbh; | ||||
106 | 0 | my $sth = $dbh->prepare("SELECT DISTINCT tagfield, tagsubfield | ||||
107 | FROM marc_subfield_structure | |||||
108 | WHERE authorised_value IS NOT NULL | |||||
109 | AND authorised_value!='' | |||||
110 | AND frameworkcode=?"); | |||||
111 | 0 | $sth->execute( $frameworkcode ); | ||||
112 | 0 | my $av = { }; | ||||
113 | 0 | while ( my ( $tag, $letter ) = $sth->fetchrow() ) { | ||||
114 | 0 | $av->{ $tag }->{ $letter } = 1; | ||||
115 | } | |||||
116 | 0 | $authval_per_framework{ $frameworkcode } = $av; | ||||
117 | } | |||||
118 | 0 | return $authval_per_framework{ $frameworkcode }; | ||||
119 | } | |||||
120 | ||||||
121 | my $stylesheet; | |||||
122 | ||||||
123 | sub XSLTParse4Display { | |||||
124 | 0 | my ( $biblionumber, $orig_record, $xsl_suffix, $interface, $fixamps, $hidden_items ) = @_; | ||||
125 | 0 | $interface = 'opac' unless $interface; | ||||
126 | # grab the XML, run it through our stylesheet, push it out to the browser | |||||
127 | 0 | my $record = transformMARCXML4XSLT($biblionumber, $orig_record); | ||||
128 | #return $record->as_formatted(); | |||||
129 | 0 | my $itemsxml = buildKohaItemsNamespace($biblionumber, $hidden_items); | ||||
130 | 0 | my $xmlrecord = $record->as_xml(C4::Context->preference('marcflavour')); | ||||
131 | 0 | my $sysxml = "<sysprefs>\n"; | ||||
132 | 0 | foreach my $syspref ( qw/ hidelostitems OPACURLOpenInNewWindow | ||||
133 | DisplayOPACiconsXSLT URLLinkText viewISBD | |||||
134 | OPACBaseURL TraceCompleteSubfields | |||||
135 | UseAuthoritiesForTracings TraceSubjectSubdivisions | |||||
136 | Display856uAsImage OPACDisplay856uAsImage | |||||
137 | UseControlNumber | |||||
138 | AlternateHoldingsField AlternateHoldingsSeparator / ) | |||||
139 | { | |||||
140 | 0 | my $sp = C4::Context->preference( $syspref ); | ||||
141 | 0 | next unless defined($sp); | ||||
142 | 0 | $sysxml .= "<syspref name=\"$syspref\">$sp</syspref>\n"; | ||||
143 | } | |||||
144 | 0 | $sysxml .= "</sysprefs>\n"; | ||||
145 | 0 | $xmlrecord =~ s/\<\/record\>/$itemsxml$sysxml\<\/record\>/; | ||||
146 | 0 | if ($fixamps) { # We need to correct the ampersand entities that Zebra outputs | ||||
147 | 0 | $xmlrecord =~ s/\&amp;/\&/g; | ||||
148 | } | |||||
149 | 0 | $xmlrecord =~ s/\& /\&\; /; | ||||
150 | 0 | $xmlrecord =~ s/\&\;amp\; /\&\; /; | ||||
151 | ||||||
152 | 0 | my $parser = XML::LibXML->new(); | ||||
153 | # don't die when you find &, >, etc | |||||
154 | 0 | $parser->recover_silently(0); | ||||
155 | 0 | my $source = $parser->parse_string($xmlrecord); | ||||
156 | 0 | unless ( $stylesheet ) { | ||||
157 | 0 | my $xslt = XML::LibXSLT->new(); | ||||
158 | 0 | my $xslfile; | ||||
159 | 0 | if ($interface eq 'intranet') { | ||||
160 | 0 | $xslfile = C4::Context->config('intrahtdocs') . | ||||
161 | '/' . C4::Context->preference("template") . | |||||
162 | '/' . C4::Templates::_current_language() . | |||||
163 | '/xslt/' . | |||||
164 | C4::Context->preference('marcflavour') . | |||||
165 | "slim2intranet$xsl_suffix.xsl"; | |||||
166 | } else { | |||||
167 | 0 | $xslfile = C4::Context->config('opachtdocs') . | ||||
168 | '/' . C4::Context->preference("opacthemes") . | |||||
169 | '/' . C4::Templates::_current_language() . | |||||
170 | '/xslt/' . | |||||
171 | C4::Context->preference('marcflavour') . | |||||
172 | "slim2OPAC$xsl_suffix.xsl"; | |||||
173 | } | |||||
174 | 0 | my $style_doc = $parser->parse_file($xslfile); | ||||
175 | 0 | $stylesheet = $xslt->parse_stylesheet($style_doc); | ||||
176 | } | |||||
177 | 0 | my $results = $stylesheet->transform($source); | ||||
178 | 0 | my $newxmlrecord = $stylesheet->output_string($results); | ||||
179 | 0 | return $newxmlrecord; | ||||
180 | } | |||||
181 | ||||||
182 | sub buildKohaItemsNamespace { | |||||
183 | 0 | my ($biblionumber, $hidden_items) = @_; | ||||
184 | ||||||
185 | 0 | my @items = C4::Items::GetItemsInfo($biblionumber); | ||||
186 | 0 | if ($hidden_items && @$hidden_items) { | ||||
187 | 0 0 | my %hi = map {$_ => 1} @$hidden_items; | ||||
188 | 0 0 | @items = grep { !$hi{$_->{itemnumber}} } @items; | ||||
189 | } | |||||
190 | 0 | my $branches = GetBranches(); | ||||
191 | 0 | my $itemtypes = GetItemTypes(); | ||||
192 | 0 | my $xml = ''; | ||||
193 | 0 | for my $item (@items) { | ||||
194 | 0 | my $status; | ||||
195 | ||||||
196 | 0 | my ( $transfertwhen, $transfertfrom, $transfertto ) = C4::Circulation::GetTransfers($item->{itemnumber}); | ||||
197 | ||||||
198 | 0 | my ( $reservestatus, $reserveitem, undef ) = C4::Reserves::CheckReserves($item->{itemnumber}); | ||||
199 | ||||||
200 | 0 | if ( $itemtypes->{ $item->{itype} }->{notforloan} || $item->{notforloan} || $item->{onloan} || $item->{wthdrawn} || $item->{itemlost} || $item->{damaged} || | ||||
201 | (defined $transfertwhen && $transfertwhen ne '') || $item->{itemnotforloan} || (defined $reservestatus && $reservestatus eq "Waiting") ){ | |||||
202 | 0 | if ( $item->{notforloan} < 0) { | ||||
203 | 0 | $status = "On order"; | ||||
204 | } | |||||
205 | 0 | if ( $item->{itemnotforloan} > 0 || $item->{notforloan} > 0 || $itemtypes->{ $item->{itype} }->{notforloan} == 1 ) { | ||||
206 | 0 | $status = "reference"; | ||||
207 | } | |||||
208 | 0 | if ($item->{onloan}) { | ||||
209 | 0 | $status = "Checked out"; | ||||
210 | } | |||||
211 | 0 | if ( $item->{wthdrawn}) { | ||||
212 | 0 | $status = "Withdrawn"; | ||||
213 | } | |||||
214 | 0 | if ($item->{itemlost}) { | ||||
215 | 0 | $status = "Lost"; | ||||
216 | } | |||||
217 | 0 | if ($item->{damaged}) { | ||||
218 | 0 | $status = "Damaged"; | ||||
219 | } | |||||
220 | 0 | if (defined $transfertwhen && $transfertwhen ne '') { | ||||
221 | 0 | $status = 'In transit'; | ||||
222 | } | |||||
223 | 0 | if (defined $reservestatus && $reservestatus eq "Waiting") { | ||||
224 | 0 | $status = 'Waiting'; | ||||
225 | } | |||||
226 | } else { | |||||
227 | 0 | $status = "available"; | ||||
228 | } | |||||
229 | 0 | my $homebranch = $item->{homebranch}? xml_escape($branches->{$item->{homebranch}}->{'branchname'}):''; | ||||
230 | 0 | my $itemcallnumber = xml_escape($item->{itemcallnumber}); | ||||
231 | 0 | $xml.= "<item><homebranch>$homebranch</homebranch>". | ||||
232 | "<status>$status</status>". | |||||
233 | "<itemcallnumber>".$itemcallnumber."</itemcallnumber>" | |||||
234 | . "</item>"; | |||||
235 | ||||||
236 | } | |||||
237 | 0 | $xml = "<items xmlns=\"http://www.koha-community.org/items\">".$xml."</items>"; | ||||
238 | 0 | return $xml; | ||||
239 | } | |||||
240 | ||||||
241 | ||||||
242 | ||||||
243 | 1; |