/[cvs]/nfo/perl/libs/XML/XUpdate/XSLT.pm
ViewVC logotype

Diff of /nfo/perl/libs/XML/XUpdate/XSLT.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by joko, Wed Apr 30 02:36:32 2003 UTC revision 1.6 by joko, Wed May 7 03:11:28 2003 UTC
# Line 7  Line 7 
7  #    $Id$  #    $Id$
8  #  #
9  #    $Log$  #    $Log$
10    #    Revision 1.6  2003/05/07 03:11:28  joko
11    #    updated pod: new section "References", added item to "Todo" section
12    #
13    #    Revision 1.5  2003/05/06 14:24:06  joko
14    #    doesn't use Carp any more
15    #    updated pod
16    #    attempt to rewrite xml to make it more human readable using helper modules from CPAN (node indentation, etc.)
17    #
18    #    Revision 1.4  2003/05/01 23:40:32  joko
19    #    minor update: commented debugging part
20    #
21    #    Revision 1.3  2003/05/01 20:11:49  joko
22    #    * added pod from xupdate.pl
23    #    - extracted xml to external files
24    #
25  #    Revision 1.1  2003/04/30 02:36:32  joko  #    Revision 1.1  2003/04/30 02:36:32  joko
26  #    initial commit  #    initial commit
27  #  #
28  #  #
29  ###############################################################################  ###############################################################################
30    
31    =pod
32    
33    
34  =head1 NAME  =head1 NAME
35    
36  XML::XUpdate::XSLT - A perl module for updating xml documents using XUpdate via XSLT.    XML::XUpdate::XSLT - A perl module for updating xml documents using XUpdate via XSLT.
37    
38    
39    =head3 Overview
40    
41      This is not the same xupdate currently available from CPAN at
42      http://search.cpan.org/author/PAJAS/XML-XUpdate-LibXML-0.4.0/xupdate .
43      
44      Its intention - however - is identical:
45      xupdate - Process XUpdate commands against an XML document.
46    
47    
48    =head4 Their implementations differ:
49    
50        1. xupdate (by Petr Pajas) uses ...
51        XML::XUpdate::LibXML - Simple implementation of XUpdate format
52        
53        ... which is based on XML::LibXML which in turn is:
54        [...]
55        This module is an interface to the gnome libxml2 DOM parser (no SAX parser support yet),
56        and the DOM tree. It also provides an XML::XPath-like findnodes() interface, providing
57        access to the XPath API in libxml2.
58        [...]
59    
60        2. This xupdate attempts to implement the XUpdate specs using XSLT only.
61        
62    
63    =head4 Yet another xupdate - facts in short:
64    
65      S: It would be nice to have a pure perl thingy which does (almost) the same stuff....
66      
67      Q: Can we achieve compliance with its (XML::XUpdate::LibXML) API? (or just a subset ....)
68      
69      Q: Can we achieve the processing using CPAN's XML::XSLT?
70      S: Proposal: XML::XUpdate::XSLT!?
71      
72      Q: Can we mimic/use the interface of the - already established - 'xupdate' program???
73      
74      Q: Should we follow the CRUD path first?
75          (CRUD is the acronym for the datastore action primitives: Create, Retrieve, Update, Delete)
76      S?: Proposal: XML::XUpdate::XSLT::API uses XML::XUpdate::XSLT::CRUD
77    
78    
79    =head3 References
80    
81        - XUpdate:
82          Requirements: http://www.xmldb.org/xupdate/xupdate-req.html
83          Working Draft: http://www.xmldb.org/xupdate/xupdate-wd.html
84        - XML API:
85        - XML::XUpdate::LibXML: http://search.cpan.org/author/PAJAS/XML-XUpdate-LibXML-0.4.0/lib/XML/XUpdate/LibXML.pm
86        - XSL / XSLT:
87          http://www.w3.org/TR/xslt
88          http://www.xsl-rp.de/
89          http://xml.klute-thiemann.de/w3c-de/REC-xslt-20020318/
90          http://xmlxslt.sourceforge.net/
91        - misc pointers:
92          "Re: Modify XML documents": http://aspn.activestate.com/ASPN/Mail/Message/perl-xml/1265431
93          XSL Extensions: http://xmlsoft.org/XSLT/extensions.html
94          EXSLT: http://www.exslt.org/set/functions/difference/index.html
95          "how to insert element at required position in document tree?": http://p2p.wrox.com/archive/xslt/2001-06/98.asp
96          XML APIs for Databases: http://www.javaworld.com/javaworld/jw-01-2000/jw-01-dbxml.html
97    
98    
99    =head3 Todo
100    
101      o What about proper encoding? (ISO-8859-1 or UTF-8)
102      o Is it possible to create the required "xsl_template.xml" at runtime via XSL itself?
103      o Cache contents of external files (*.xml). Performance!
104      o Can exception / error-code handling be improved somehow?
105          Esp.: It would be interesting, if the XUpdate payload actually could be applied, or not...
106      o <xupdate:if>, etc.
107      
108    
109  =cut  =cut
110    
# Line 27  package XML::XUpdate::XSLT; Line 116  package XML::XUpdate::XSLT;
116  use strict;  use strict;
117  use warnings;  use warnings;
118    
 use XML::XSLT 0.41;  
 use Carp;  
119  use Data::Dumper;  use Data::Dumper;
120    use File::Basename;
121    use XML::XSLT 0.41;
122    use XML::XUpdate::Rewrite;
123    
124  # Namespace constants  # Namespace constants
125    
# Line 37  use constant NS_XUPDATE         => 'http Line 127  use constant NS_XUPDATE         => 'http
127    
128  use vars qw ( $VERSION );  use vars qw ( $VERSION );
129    
130  $VERSION = '0.02';  $VERSION = '0.01';
131    
132    
133  ######################################################################  ######################################################################
# Line 48  sub new { Line 138  sub new {
138    my $self = bless {}, $class;    my $self = bless {}, $class;
139    my $args = $self->__parse_args(@_);    my $args = $self->__parse_args(@_);
140        
141    $self->__init_default_macros();    $self->{DEBUG} = $args->{debug};
142      $self->{WARNINGS} = $args->{warnings};
143    
144  #=pod    $self->__init_default_stylesheets();
   $self->{XSLT_ENGINE} = XML::XSLT->new(  
     Source => $self->get_macro("xupdate2xsl"),  
     debug => $args->{debug},  
     warnings => $args->{warnings}  
   );  
 #=cut  
145    
   #print Dumper($self);  
146    return $self;    return $self;
147    
148  }  }
149    
150  sub get_macro {  sub get_stylesheet {
151    my $self = shift;    my $self = shift;
152    my $name = shift;    my $name = shift;
153    return $self->{MACROS}->{$name};    return $self->{XML}->{xsl}->{$name};
154    }
155    
156    sub set_stylesheet {
157      my $self = shift;
158      my $name = shift;
159      my $xml = shift;
160      my $options = shift;
161      if ($options->{encap}) {
162        my $template = $self->__slurp_file("xsl_template.xml");
163        # FIXME! What about the quirky? Is there a better one?
164        $template =~ s!<xsl:quirky_placeholder />!$xml!;
165        $xml = $template;
166      }
167      $self->{XML}->{xsl}->{$name} = $xml;
168  }  }
169    
170  sub open_document {  sub open_document {
# Line 85  sub open_xupdate { Line 183  sub open_xupdate {
183    
184  sub process {  sub process {
185    my $self = shift;    my $self = shift;
186    # first, translate xupdate to xsl    $self->_calculate();
187    $self->{XSLT_ENGINE}->open_xml( $self->{XML}->{xupdate} );    $self->_apply();
   $self->{XSLT_ENGINE}->process();  
   $self->{XML}->{XSL} = $self->{XSLT_ENGINE}->toString();  
188  }  }
189    
190  sub toString {  # First, translate the xupdate payload to xsl.
191    # FIXME: do DOM only! (don't use "->toString")
192    sub _calculate {
193    my $self = shift;    my $self = shift;
194    return $self->{XML}->{XSL};    $self->{XSLT_ENGINE_PREP} = XML::XSLT->new(
195        Source => $self->get_stylesheet("xupdate2xsl"),
196        debug => $self->{DEBUG},
197        warnings => $self->{WARNINGS}
198      );
199      $self->{XSLT_ENGINE_PREP}->open_xml( $self->{XML}->{xupdate} );
200      $self->{XSLT_ENGINE_PREP}->process();
201      $self->set_stylesheet( "_worker", $self->{XSLT_ENGINE_PREP}->toString(), { encap => 1 } );
202  }  }
203    
204    # After that, use this worker xsl to actually apply the changes to the original document.
205    # FIXME: do DOM only!
206    sub _apply {
207      my $self = shift;
208      
209      # debug - print the calculated xsl on STDERR
210      print STDERR $self->get_stylesheet("_worker"), "\n";
211      
212      #return;
213      $self->{XSLT_ENGINE_LIVE} = XML::XSLT->new(
214        Source => $self->get_stylesheet("_worker"),
215        debug => $self->{DEBUG},
216        warnings => $self->{WARNINGS}
217      );
218      $self->{XSLT_ENGINE_LIVE}->open_xml( $self->{XML}->{document} );
219      $self->{XSLT_ENGINE_LIVE}->process();
220      $self->{XML}->{result} = $self->{XSLT_ENGINE_LIVE}->toString();
221    }  
222      
223    sub toString {
224      my $self = shift;
225      
226      # use rest of argument list as hash of option values
227      my $options = {@_};
228      
229      # short circuit - just return what we have - don't modify anything
230      return $self->{XML}->{result} unless $options and $options->{rewrite};
231      
232      # Rewrite the xml document with certain engine to desired style.
233      # 'engine' defaults to "XMLParser" if not specified.
234      my $rewrite = XML::XUpdate::Rewrite->new( style => $options->{mode}, engine => $options->{using} );
235      $rewrite->set_document( $self->{XML}->{result} );
236      # TODO: Implement a configurable fallback here to return the un-rewritten payload if desired.
237      $rewrite->process() or die(__PACKAGE__ . ": Error while rewriting XML document.");
238      return $rewrite->get_document();
239    }
240    
241    
242  ######################################################################  ######################################################################
243  # AUXILIARY METHODS  # AUXILIARY METHODS
244    
245  # Argument parsing with backwards compatibility.  # Argument list parsing.
246    # ... from XML::XUpdate::LibXML (w/o backwards compatibility hook).
247    # Could this make up a Class::AutoFill::__read_arglist which transparently
248    # makes object attributes from constructor arguments in a configurable way?
249  sub __parse_args {  sub __parse_args {
250    my $self = shift;    my $self = shift;
251    my %args;    my %args;
252    
253    if(@_ % 2 ) {    if ( @_ % 2 ) {
254      $args{dummy} = shift;      $args{dummy} = shift;
255      %args = (%args, @_);      %args = (%args, @_);
256    } else {    } else {
# Line 116  sub __parse_args { Line 261  sub __parse_args {
261  }  }
262    
263    
264  sub __init_default_macros {  sub __init_default_stylesheets {
265    my $self = shift;    my $self = shift;
266    $self->{MACROS}->{xupdate2xsl} = qq(<?xml version="1.0" encoding="ISO-8859-1"?>    if (my $payload = $self->__slurp_file("xupdate2xsl.xml")) {
267          $self->{XML}->{xsl}->{xupdate2xsl} = $payload;
268    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">    }
269    }
270    
271    sub __slurp_file {
272      my $self = shift;
273      my $filename = shift;
274        
275        <!--    # does file exist?
276        Purpose of this XML Stylesheet is to implement a set of templates    if (! -e $filename) {
277        to translate XUpdate lingo into an intermediate xslt stylesheet      $filename = dirname(__FILE__) . "/$filename";
278        which actually performs the update to the original xml document.      if (! -e $filename) {
279        -->        die("File $filename does not exist.");
280              }
281        <xsl:output method="xml" />    }
     
       <!-- 1. This is the passthru logic (copy all untouched nodes). -->  
       <xsl:template name="passthru"><xsl:copy><xsl:apply-templates /></xsl:copy></xsl:template>  
       <!-- activate this -->  
       <xsl:template match="*"><xsl:call-template name="passthru" /></xsl:template>  
       <!-- override some builtin rules: see http://www.w3.org/TR/xslt#built-in-rule -->  
       <xsl:template match="comment()"><xsl:call-template name="passthru" /></xsl:template>  
     
       <!-- 2. This is the translation part: XUpdate becomes XSLT -->  
         
       <!-- This node "encapsulates" common infrastructure. -->  
       <xsl:template match="xupdate:modifications">  
     
           <!-- 1. This is the passthru logic (copy all untouched nodes). -->  
           <!-- in fact this is the xsl from above translated to be able to be generated by xsl itself! -->  
               <xsl:comment> 1. passthru logic </xsl:comment>  
               <xsl:element name="xsl:template">  
                   <xsl:attribute name="name">passthru</xsl:attribute>  
                   <xsl:element name="xsl:copy"><xsl:element name="xsl:apply-templates" /></xsl:element>  
               </xsl:element>  
               <xsl:element name="xsl:template">  
                   <xsl:attribute name="match">*</xsl:attribute>  
                   <xsl:element name="xsl:call-template"><xsl:attribute name="name">passthru</xsl:attribute></xsl:element>  
               </xsl:element>  
               <xsl:element name="xsl:template">  
                   <xsl:attribute name="match">comment()</xsl:attribute>  
                   <xsl:element name="xsl:call-template"><xsl:attribute name="name">passthru</xsl:attribute></xsl:element>  
               </xsl:element>  
     
           <!-- continue with all inline nodes -->  
               <xsl:apply-templates />  
     
       </xsl:template>  
     
       <!-- This node "encapsulates" infrastructure for handling the directives. -->  
       <xsl:template match="xupdate:insert-after">  
           <xsl:comment> 2. context finder </xsl:comment>  
           <xsl:apply-templates />  
       </xsl:template>  
     
       <!-- This node passes through all attributes and childnodes rewriting the tagname only. -->  
       <xsl:template match="xupdate:element">  
           <xsl:comment> 3. rewrite / vivify elements/attributes </xsl:comment>  
           <xsl:element name="xsl:element">  
               <xsl:copy-of select="@*"/>  
               <xsl:apply-templates />  
           </xsl:element>  
       </xsl:template>  
     
       <!-- This node passes through all attributes and childnodes rewriting the tagname only. -->  
       <xsl:template match="xupdate:attribute">  
           <xsl:element name="xsl:attribute">  
               <xsl:copy-of select="@*"/>  
               <xsl:apply-templates />  
           </xsl:element>  
       </xsl:template>  
     
   </xsl:stylesheet>  
282        
283    );    open(FH, "<" . $filename);
284      my @lines = <FH>;
285      my $content = join("", @lines);
286      close(FH);
287      return $content;
288  }  }
289    
290  1;  1;

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.6

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed