/[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.4 by joko, Thu May 1 23:40:32 2003 UTC
# Line 7  Line 7 
7  #    $Id$  #    $Id$
8  #  #
9  #    $Log$  #    $Log$
10    #    Revision 1.4  2003/05/01 23:40:32  joko
11    #    minor update: commented debugging part
12    #
13    #    Revision 1.3  2003/05/01 20:11:49  joko
14    #    * added pod from xupdate.pl
15    #    - extracted xml to external files
16    #
17  #    Revision 1.1  2003/04/30 02:36:32  joko  #    Revision 1.1  2003/04/30 02:36:32  joko
18  #    initial commit  #    initial commit
19  #  #
20  #  #
21  ###############################################################################  ###############################################################################
22    
23    =pod
24    
25    
26  =head1 NAME  =head1 NAME
27    
28  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.
29    
30    
31    =head3 Overview
32    
33      This is not the same xupdate currently available from CPAN at
34      http://search.cpan.org/author/PAJAS/XML-XUpdate-LibXML-0.4.0/xupdate .
35      
36      Its intention - however - is identical:
37      xupdate - Process XUpdate commands against an XML document.
38    
39    
40    =head3 Their implementations differ:
41    
42        1. xupdate (by Petr Pajas) uses ...
43        XML::XUpdate::LibXML - Simple implementation of XUpdate format
44        
45        ... which is based on XML::LibXML which in turn is:
46        [...]
47        This module is an interface to the gnome libxml2 DOM parser (no SAX parser support yet),
48        and the DOM tree. It also provides an XML::XPath-like findnodes() interface, providing
49        access to the XPath API in libxml2.
50        [...]
51    
52        2. This xupdate attempts to implement the XUpdate specs using XSLT only.
53        
54    
55    =head3 Yet another xupdate - facts in short:
56    
57      S: It would be nice to have a pure perl thingy which does (almost) the same stuff....
58      
59      Q: Can we achieve compliance with its (XML::XUpdate::LibXML) API? (or just a subset ....)
60      
61      Q: Can we achieve the processing using CPAN's XML::XSLT?
62      S: Proposal: XML::XUpdate::XSLT!?
63      
64      Q: Can we mimic/use the interface of the - already established - 'xupdate' program???
65      
66      Q: Should we follow the CRUD path first? (CRUD means: Create, Retrieve, Update, Delete)
67      S?: Proposal: XML::XUpdate::XSLT::API uses XML::XUpdate::XSLT::CRUD
68    
69    
70    =head4 Todo
71    
72      o What about proper encoding? (ISO-8859-1 or UTF-8)
73      o Is it possible to create the required "xsl_template.xml" at runtime via XSL itself?
74      o Cache contents of external files (*.xml). Performance!
75      
76    
77  =cut  =cut
78    
79    
# Line 29  use warnings; Line 86  use warnings;
86    
87  use XML::XSLT 0.41;  use XML::XSLT 0.41;
88  use Carp;  use Carp;
89    use File::Basename;
90  use Data::Dumper;  use Data::Dumper;
91    
92  # Namespace constants  # Namespace constants
# Line 37  use constant NS_XUPDATE         => 'http Line 95  use constant NS_XUPDATE         => 'http
95    
96  use vars qw ( $VERSION );  use vars qw ( $VERSION );
97    
98  $VERSION = '0.02';  $VERSION = '0.01';
99    
100    
101  ######################################################################  ######################################################################
# Line 48  sub new { Line 106  sub new {
106    my $self = bless {}, $class;    my $self = bless {}, $class;
107    my $args = $self->__parse_args(@_);    my $args = $self->__parse_args(@_);
108        
109    $self->__init_default_macros();    $self->{DEBUG} = $args->{debug};
110      $self->{WARNINGS} = $args->{warnings};
111    
112  #=pod    $self->__init_default_stylesheets();
   $self->{XSLT_ENGINE} = XML::XSLT->new(  
     Source => $self->get_macro("xupdate2xsl"),  
     debug => $args->{debug},  
     warnings => $args->{warnings}  
   );  
 #=cut  
113    
   #print Dumper($self);  
114    return $self;    return $self;
115    
116  }  }
117    
118  sub get_macro {  sub get_stylesheet {
119    my $self = shift;    my $self = shift;
120    my $name = shift;    my $name = shift;
121    return $self->{MACROS}->{$name};    return $self->{XML}->{xsl}->{$name};
122    }
123    
124    sub set_stylesheet {
125      my $self = shift;
126      my $name = shift;
127      my $xml = shift;
128      my $options = shift;
129      if ($options->{encap}) {
130        my $template = $self->__slurp_file("xsl_template.xml");
131        # FIXME! What about the quirky? Is there a better one?
132        $template =~ s!<xsl:quirky_placeholder />!$xml!;
133        $xml = $template;
134      }
135      $self->{XML}->{xsl}->{$name} = $xml;
136  }  }
137    
138  sub open_document {  sub open_document {
# Line 85  sub open_xupdate { Line 151  sub open_xupdate {
151    
152  sub process {  sub process {
153    my $self = shift;    my $self = shift;
154    # first, translate xupdate to xsl    $self->_calculate();
155    $self->{XSLT_ENGINE}->open_xml( $self->{XML}->{xupdate} );    $self->_apply();
   $self->{XSLT_ENGINE}->process();  
   $self->{XML}->{XSL} = $self->{XSLT_ENGINE}->toString();  
156  }  }
157    
158    # First, translate the xupdate payload to xsl.
159    # FIXME: do DOM only!
160    sub _calculate {
161      my $self = shift;
162      $self->{XSLT_ENGINE_PREP} = XML::XSLT->new(
163        Source => $self->get_stylesheet("xupdate2xsl"),
164        debug => $self->{DEBUG},
165        warnings => $self->{WARNINGS}
166      );
167      $self->{XSLT_ENGINE_PREP}->open_xml( $self->{XML}->{xupdate} );
168      $self->{XSLT_ENGINE_PREP}->process();
169      $self->set_stylesheet( "_worker", $self->{XSLT_ENGINE_PREP}->toString(), { encap => 1 } );
170    }
171    
172    # After that, use this worker xsl to actually apply the changes to the original document.
173    # FIXME: do DOM only!
174    sub _apply {
175      my $self = shift;
176      
177      # debug - print the calculated xsl on STDERR
178      #print STDERR $self->get_stylesheet("_worker"), "\n";
179      
180      #return;
181      $self->{XSLT_ENGINE_LIVE} = XML::XSLT->new(
182        Source => $self->get_stylesheet("_worker"),
183        debug => $self->{DEBUG},
184        warnings => $self->{WARNINGS}
185      );
186      $self->{XSLT_ENGINE_LIVE}->open_xml( $self->{XML}->{document} );
187      $self->{XSLT_ENGINE_LIVE}->process();
188      $self->{XML}->{result} = $self->{XSLT_ENGINE_LIVE}->toString();
189    }  
190      
191  sub toString {  sub toString {
192    my $self = shift;    my $self = shift;
193    return $self->{XML}->{XSL};    return $self->{XML}->{result};
194  }  }
195    
196    
197  ######################################################################  ######################################################################
198  # AUXILIARY METHODS  # AUXILIARY METHODS
199    
200  # Argument parsing with backwards compatibility.  # Argument parsing (with backwards compatibility hook).
201  sub __parse_args {  sub __parse_args {
202    my $self = shift;    my $self = shift;
203    my %args;    my %args;
# Line 116  sub __parse_args { Line 213  sub __parse_args {
213  }  }
214    
215    
216  sub __init_default_macros {  sub __init_default_stylesheets {
217    my $self = shift;    my $self = shift;
218    $self->{MACROS}->{xupdate2xsl} = qq(<?xml version="1.0" encoding="ISO-8859-1"?>    if (my $payload = $self->__slurp_file("xupdate2xsl.xml")) {
219          $self->{XML}->{xsl}->{xupdate2xsl} = $payload;
220    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">    }
221    }
222    
223    sub __slurp_file {
224      my $self = shift;
225      my $filename = shift;
226        
227        <!--    # does file exist?
228        Purpose of this XML Stylesheet is to implement a set of templates    if (! -e $filename) {
229        to translate XUpdate lingo into an intermediate xslt stylesheet      $filename = dirname(__FILE__) . "/$filename";
230        which actually performs the update to the original xml document.      if (! -e $filename) {
231        -->        croak("File $filename does not exist.");
232              }
233        <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>  
234        
235    );    open(FH, "<" . $filename);
236      my @lines = <FH>;
237      my $content = join("", @lines);
238      close(FH);
239      return $content;
240  }  }
241    
242  1;  1;

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

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