/[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.7 - (show annotations)
Tue May 13 09:32:22 2003 UTC (21 years ago) by joko
Branch: MAIN
Changes since 1.6: +5 -2 lines
minor update to pod

1 ##############################################################################
2 #
3 # Perl module: XML::XUpdate::XSLT
4 #
5 # By Andreas Motl, andreas.motl@ilo.de
6 #
7 # $Id: XSLT.pm,v 1.6 2003/05/07 03:11:28 joko Exp $
8 #
9 # $Log: XSLT.pm,v $
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
26 # initial commit
27 #
28 #
29 ###############################################################################
30
31 =pod
32
33
34 =head1 NAME
35
36 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 Conditional processing: <xupdate:if>, etc.
107
108
109 =cut
110
111
112 ######################################################################
113 package XML::XUpdate::XSLT;
114 ######################################################################
115
116 use strict;
117 use warnings;
118
119 use Data::Dumper;
120 use File::Basename;
121 use XML::XSLT 0.41;
122 use XML::XUpdate::Rewrite;
123
124 # Namespace constants
125
126 use constant NS_XUPDATE => 'http://www.xmldb.org/xupdate';
127
128 use vars qw ( $VERSION );
129
130 $VERSION = '0.01';
131
132
133 ######################################################################
134 # PUBLIC DEFINITIONS
135
136 sub new {
137 my $class = shift;
138 my $self = bless {}, $class;
139 my $args = $self->__parse_args(@_);
140
141 $self->{DEBUG} = $args->{debug};
142 $self->{WARNINGS} = $args->{warnings};
143
144 $self->__init_default_stylesheets();
145
146 return $self;
147
148 }
149
150 sub get_stylesheet {
151 my $self = shift;
152 my $name = shift;
153 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 {
171 my $self = shift;
172 my $xml = shift;
173 # FIXME: check for filename, filehandle and URL (etc.)
174 $self->{XML}->{document} = $xml;
175 }
176
177 sub open_xupdate {
178 my $self = shift;
179 my $xml = shift;
180 # FIXME: check for filename, filehandle and URL (etc.)
181 $self->{XML}->{xupdate} = $xml;
182 }
183
184 sub process {
185 my $self = shift;
186 $self->_calculate();
187 $self->_apply();
188 }
189
190 # First, translate the xupdate payload to xsl.
191 # FIXME: do DOM only! (don't use "->toString")
192 sub _calculate {
193 my $self = shift;
194 $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
244
245 # 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 {
250 my $self = shift;
251 my %args;
252
253 if ( @_ % 2 ) {
254 $args{dummy} = shift;
255 %args = (%args, @_);
256 } else {
257 %args = @_;
258 }
259
260 return \%args;
261 }
262
263
264 sub __init_default_stylesheets {
265 my $self = shift;
266 if (my $payload = $self->__slurp_file("xupdate2xsl.xml")) {
267 $self->{XML}->{xsl}->{xupdate2xsl} = $payload;
268 }
269 }
270
271 sub __slurp_file {
272 my $self = shift;
273 my $filename = shift;
274
275 # does file exist?
276 if (! -e $filename) {
277 $filename = dirname(__FILE__) . "/$filename";
278 if (! -e $filename) {
279 die("File $filename does not exist.");
280 }
281 }
282
283 open(FH, "<" . $filename);
284 my @lines = <FH>;
285 my $content = join("", @lines);
286 close(FH);
287 return $content;
288 }
289
290 1;
291 __END__

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