/[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.8 - (show annotations)
Fri Jun 6 04:01:52 2003 UTC (21 years, 5 months ago) by joko
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +5 -2 lines
just write to STDERR in debug mode

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

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