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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (show annotations)
Wed May 7 03:11:28 2003 UTC (21 years ago) by joko
Branch: MAIN
Changes since 1.5: +32 -6 lines
updated pod: new section "References", added item to "Todo" section

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

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