xsltcache.tcl

Go to the documentation of this file.
00001 /*  xsltcache.tcl --*/
00002 /* */
00003 /*  Handles performing XSLT transformations,*/
00004 /*  caching documents and results.*/
00005 /* */
00006 /*  Copyright (c) 2005-2007 Steve Ball*/
00007 /*  http://www.packagedpress.com/staff/Steve.Ball*/
00008 /*  Copyright (c) 2002-2003 Zveno Pty Ltd*/
00009 /*  http://www.zveno.com/*/
00010 /* */
00011 /*  See the file "LICENSE" in this distribution for information on usage and*/
00012 /*  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00013 /* */
00014 /*  $Id: xsltcache.tcl,v 1.10 2005/11/04 06:41:56 balls Exp $*/
00015 
00016 package require xslt 3.2
00017 package require uri
00018 
00019 package provide xslt::cache 3.2
00020 
00021 namespace xslt::cache {
00022     namespace export transform transformdoc flush
00023     namespace export parse_depend
00024     namespace export 
00025 
00026     variable sources
00027     array  sources =  {}
00028     variable stylesheets
00029     array  stylesheets =  {}
00030     variable results
00031     array  results =  {}
00032 }
00033 
00034 /*  xslt::cache::transform --*/
00035 /* */
00036 /*  Perform an XSLT transformation.*/
00037 /* */
00038 /*  Arguments:*/
00039 /*  src Filename of source document*/
00040 /*  ssheet  Filename of stylesheet document*/
00041 /*  args    Configuration options, stylesheet parameters*/
00042 /* */
00043 /*  Results:*/
00044 /*  Result document token*/
00045 
00046 ret  xslt::cache::transform (type src , type ssheet , type args) {
00047     variable sources
00048     variable stylesheets
00049     variable results
00050 
00051     # Separate parameters from options
00052     set parameters {}
00053     set options {}
00054     foreach {key value} $args {
00055     switch -glob -- $key {
00056         -* {
00057         lappend options $key $value
00058         }
00059         default {
00060         lappend parameters $key $value
00061         }
00062     }
00063     }
00064 
00065     # Normalize the parameter list
00066     array set paramArray $parameters
00067     set parameters {}
00068     foreach name [lsort [array names paramArray]] {
00069     lappend parameters $name $paramArray($name)
00070     }
00071 
00072     set hash $src.$ssheet.$parameters
00073 
00074     array set opts {
00075     -xmlinclude 1
00076     }
00077     array set opts $options
00078 
00079     set readSource [ReadXML $src -xmlinclude $opts(-xmlinclude)]
00080 
00081     set readStylesheet 1
00082     if {[info exists stylesheets($ssheet)]} {
00083     if {[file mtime $ssheet] < $stylesheets($ssheet,time)} {
00084         set readStylesheet 0
00085     }
00086     }
00087     if {$readStylesheet} {
00088     catch {rename $stylesheets($ssheet) {}}
00089     ReadXML $ssheet -xmlinclude $opts(-xmlinclude)
00090 
00091     set stylesheets($ssheet) [xslt::compile $sources($ssheet)]
00092     set stylesheets($ssheet,time) [clock seconds]
00093     }
00094 
00095     if {$readSource || $readStylesheet || ![info exists results($hash)]} {
00096 
00097     set results($hash) [eval [list $stylesheets($ssheet)] transform [list $sources($src)] $parameters]
00098     set results($hash,time) [clock seconds]
00099     }
00100 
00101     return $results($hash)
00102 }
00103 
00104 /*  xslt::cache::loadstylesheet --*/
00105 /* */
00106 /*  Read, parse and compile an XSLT stylesheet.*/
00107 /* */
00108 /*  Arguments:*/
00109 /*  src Filename for the stylesheet document*/
00110 /*  args    options*/
00111 /* */
00112 /*  Results:*/
00113 /*  Returns compiled stylesheet token.  Adds reference to stylesheet to cache.*/
00114 
00115 ret  xslt::cache::loadstylesheet (type src , type args) {
00116     variable sources
00117     variable stylesheets
00118 
00119     array set options {
00120     -keepsource 0
00121     -xmlinclude 0
00122     }
00123     array set options $args
00124 
00125     eval ReadXML [list $src] [array get options -xmlinclude]
00126 
00127     set stylesheets($src) [xslt::compile $sources($src)]
00128     set stylesheets($src,time) [clock seconds]
00129 
00130     if {!$options(-keepsource)} {
00131     flush $src {}
00132     }
00133 
00134     # TODO: set command trace so that if the stylesheet is deleted
00135     # the cache is invalidated
00136 
00137     return $stylesheets($src)
00138 }
00139 
00140 /*  xslt::cache::ReadXML --*/
00141 /* */
00142 /*  Internal proc to manage parsing a document.*/
00143 /*  Used for both source and stylesheet documents.*/
00144 /* */
00145 /*  Arguments:*/
00146 /*  src Filename of source document*/
00147 /*  args    Configuration options*/
00148 /* */
00149 /*  Results:*/
00150 /*  Returns 1 if document was read.  Returns 0 if document is cached.*/
00151 
00152 ret  xslt::cache::ReadXML (type src , type args) {
00153     variable sources
00154     array set opts {
00155     -xmlinclude 1
00156     }
00157     array set opts $args
00158 
00159     set readSource 1
00160     if {[info exists sources($src)]} {
00161     if {[file mtime $src] < $sources($src,time)} {
00162         set readSource 0
00163     }
00164     }
00165     if {$readSource} {
00166     catch {dom::destroy $sources($src)}
00167     set ch [open $src]
00168     set sources($src) [dom::parse [read $ch] -baseuri file://$src]
00169     close $ch
00170     if {$opts(-xmlinclude)} {
00171         dom::xinclude $sources($src)
00172     }
00173     set sources($src,time) [clock seconds]
00174     }
00175 
00176     return $readSource
00177 }
00178 
00179 /*  xslt::cache::transformdoc --*/
00180 /* */
00181 /*  Perform an XSLT transformation on a DOM document.*/
00182 /* */
00183 /*  Arguments:*/
00184 /*  src DOM token of source document*/
00185 /*  ssheet  Filename of stylesheet document*/
00186 /*  args    Configuration options, stylesheet parameters*/
00187 /* */
00188 /*  Results:*/
00189 /*  Result document token*/
00190 
00191 ret  xslt::cache::transformdoc (type src , type ssheet , type args) {
00192     variable sources
00193     variable stylesheets
00194 
00195     # Separate parameters from options
00196     set parameters {}
00197     set options {}
00198     foreach {key value} $args {
00199     switch -glob -- $key {
00200         -* {
00201         lappend options $key $value
00202         }
00203         default {
00204         lappend parameters $key $value
00205         }
00206     }
00207     }
00208 
00209     # Normalize the parameter list
00210     array set paramArray $parameters
00211     set parameters {}
00212     foreach name [lsort [array names paramArray]] {
00213     lappend parameters $name $paramArray($name)
00214     }
00215 
00216     array set opts {
00217     -xmlinclude 1
00218     }
00219     array set opts $options
00220 
00221     set readStylesheet 1
00222     if {[info exists stylesheets($ssheet)]} {
00223     if {[file mtime $ssheet] < $stylesheets($ssheet,time)} {
00224         set readStylesheet 0
00225     }
00226     }
00227     if {$readStylesheet} {
00228     catch {rename $stylesheets($ssheet) {}}
00229     ReadXML $ssheet -xmlinclude $opts(-xmlinclude)
00230 
00231     set stylesheets($ssheet) [xslt::compile $sources($ssheet)]
00232     set stylesheets($ssheet,time) [clock seconds]
00233     }
00234 
00235     set result [eval [list $stylesheets($ssheet)] transform [list $src] $parameters]
00236 
00237     return $result
00238 }
00239 
00240 /*  ::xslt::cache::parse_depend --*/
00241 /* */
00242 /*  Parse a document while determining its dependencies.*/
00243 /* */
00244 /*  Arguments:*/
00245 /*  uri Document's URI*/
00246 /*  depVar  Global variable name for dependency document*/
00247 /* */
00248 /*  Results:*/
00249 /*  Returns parsed document token.*/
00250 /*  Document token for dependency document is stored in depVar.*/
00251 
00252 ret  xslt::cache::parse_depend (type uri , type depVar) {
00253     upvar #0 $depVar dep
00254 
00255     set dep [dom::create]
00256     dom::document createElement $dep dependencies
00257 
00258     array set uriParsed [uri::split $uri]
00259 
00260     switch -- $uriParsed(scheme) {
00261     file {
00262         set ch [open $uriParsed(path)]
00263         set doc [dom::parse [read $ch] -baseuri $uri -externalentitycommand [namespace code [list ParseDepend_Entity $depVar]]]
00264         close $ch
00265 
00266         ParseDepend_XInclude $doc $depVar
00267         ParseDepend_XSLT $doc $depVar
00268     }
00269     http {
00270         return -code error "URI scheme \"http\" not yet implemented"
00271     }
00272     dom {
00273         set doc $uriParsed(dom)
00274 
00275         # Can't determine external entities, but can find XInclude
00276         # and XSL stylesheet includes/imports.
00277         ParseDepend_XInclude $uriParsed(dom) $depVar
00278         ParseDepend_XSLT $uriParsed(dom) $depVar
00279     }
00280     default {
00281         return -code error "URI scheme \"$uriParsed(scheme)\" not supported"
00282     }
00283     }
00284 
00285     return $doc
00286 }
00287 
00288 /*  xslt::cache::ParseDepend_Entity --*/
00289 /* */
00290 /*  Callback for external entity inclusion.*/
00291 /* */
00292 /*  Arguments:*/
00293 /*  depVar  Global variable of dependency document*/
00294 /*  pubId   Public identifier*/
00295 /*  sysId   System identifier*/
00296 /* */
00297 /*  Results:*/
00298 /*  Dependency added to dependency document*/
00299 
00300 ret  xslt::cache::ParseDepend_Entity (type depVar , type pubId , type sysId) {
00301     upvar #0 $depVar dep
00302 
00303     dom::document createNode $dep /dependencies/external-entities/entity
00304 }
00305 
00306 /*  ::xslt::cache::flush --*/
00307 /* */
00308 /*  Flush the cache*/
00309 /* */
00310 /*  Arguments:*/
00311 /*  src source document filename*/
00312 /*  ssheet  stylesheet document filename*/
00313 /*  args    parameters*/
00314 /* */
00315 /*  Results:*/
00316 /*  Returns the empty string.*/
00317 /*  If all arguments are given then all entries corresponding*/
00318 /*  to that transformation are destroyed.*/
00319 /*  If the source and/or stylesheet are given then all*/
00320 /*  entries corresponding to those documents are destroyed.*/
00321 
00322 ret  xslt::cache::flush (type src , type ssheet , type args) {
00323     variable sources
00324     variable stylesheets
00325     variable results
00326 
00327     # Normalize parameter list
00328     array set paramArray $args
00329     set parameters {}
00330     foreach name [lsort [array names paramArray]] {
00331     lappend parameters $name $paramArray($name)
00332     }
00333 
00334     set hash $src.$ssheet.$parameters
00335 
00336     switch -glob [string length $src],[string length $ssheet],[llength $args] {
00337     0,0,* {
00338         # Special case: flush all
00339         unset sources
00340         array set sources {}
00341         unset stylesheets
00342         array set stylesheets {}
00343         unset results
00344         array set results {}
00345     }
00346 
00347     0,*,0 {
00348         # Flush all entries for the given stylesheet
00349         catch {rename $stylesheets($ssheet) {}}
00350         catch {unset stylesheets($ssheet)}
00351         catch {unset stylesheets($ssheet,time)}
00352 
00353         foreach entry [array names results *.$ssheet.*] {
00354         catch {dom::destroy $results($entry)}
00355         catch {unset results($entry)}
00356         catch {unset results($entry,time)}
00357         }
00358     }
00359 
00360     *,0,0 {
00361         # Flush all entries for the given source document
00362         catch {dom::destroy $sources($src)}
00363         catch {unset sources($src)}
00364         catch {unset sources($src,time)}
00365         foreach entry [array names results $src.*] {
00366         catch {dom::destroy $results($entry)}
00367         catch {unset results($entry)}
00368         catch {unset results($entry,time)}
00369         }
00370     }
00371 
00372     default {
00373         # Flush specific entry
00374         catch {dom::destroy $results($hash)}
00375         catch {unset results($hash)}
00376         catch {unset results($hash,time)}
00377     }
00378     }
00379 }
00380 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1