Added items about the change of XML format and additional TT based producers.
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Producer / XML / SQLFairy.pm
CommitLineData
0a689100 1package SQL::Translator::Producer::XML::SQLFairy;
2
3# -------------------------------------------------------------------
4a268a6c 4# $Id: SQLFairy.pm,v 1.13 2004-07-08 19:34:29 grommit Exp $
0a689100 5# -------------------------------------------------------------------
6# Copyright (C) 2003 Ken Y. Clark <kclark@cpan.org>,
7# darren chamberlain <darren@cpan.org>,
8# Chris Mungall <cjm@fruitfly.org>,
9# Mark Addison <mark.addison@itn.co.uk>.
10#
11# This program is free software; you can redistribute it and/or
12# modify it under the terms of the GNU General Public License as
13# published by the Free Software Foundation; version 2.
14#
15# This program is distributed in the hope that it will be useful, but
16# WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18# General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program; if not, write to the Free Software
22# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23# 02111-1307 USA
24# -------------------------------------------------------------------
25
26=pod
27
28=head1 NAME
29
a7d50b44 30SQL::Translator::Producer::XML::SQLFairy - SQLFairy's default XML format
0a689100 31
32=head1 SYNOPSIS
33
34 use SQL::Translator;
35
36 my $t = SQL::Translator->new(
37 from => 'MySQL',
a7d50b44 38 to => 'XML-SQLFairy',
0a689100 39 filename => 'schema.sql',
40 show_warnings => 1,
41 add_drop_table => 1,
42 );
43
44 print $t->translate;
45
b89a67a0 46=head1 DESCRIPTION
0a689100 47
b89a67a0 48Creates XML output of a schema, in SQLFairy format XML.
0a689100 49
b89a67a0 50The XML lives in the http://sqlfairy.sourceforge.net/sqlfairy.xml namespace.
51With a root element of <schema>.
0a689100 52
b89a67a0 53Objects in the schema are mapped to tags of the same name as the objects class.
0a689100 54
b89a67a0 55The attributes of the objects (e.g. $field->name) are mapped to attributes of
56the tag, except for sql, comments and action, which get mapped to child data
57elements.
0a689100 58
b89a67a0 59List valued attributes (such as the list of fields in an index)
60get mapped to a comma seperated list of values in the attribute.
0a689100 61
b89a67a0 62Child objects, such as a tables fields, get mapped to child tags wrapped in a
63set of container tags using the plural of their contained classes name.
0a689100 64
b89a67a0 65e.g.
0a689100 66
b89a67a0 67 <schema name="" database=""
68 xmlns="http://sqlfairy.sourceforge.net/sqlfairy.xml">
0a689100 69
b89a67a0 70 <table name="Story" order="1">
0a689100 71
b89a67a0 72 <fields>
73 <field name="created" data_type="datetime" size="0"
74 is_nullable="1" is_auto_increment="0" is_primary_key="0"
75 is_foreign_key="0" order="1">
76 <comments></comments>
77 </field>
78 <field name="id" data_type="BIGINT" size="20"
79 is_nullable="0" is_auto_increment="1" is_primary_key="1"
80 is_foreign_key="0" order="3">
81 <comments></comments>
82 </field>
83 ...
84 </fields>
85
86 <indices>
87 <index name="foobar" type="NORMAL" fields="foo,bar" options="" />
88 </indices>
89
90 </table>
91
92 <view name="email_list" fields="email" order="1">
93 <sql>SELECT email FROM Basic WHERE email IS NOT NULL</sql>
94 </view>
95
96 </schema>
97
98To see a complete example of the XML translate one of your schema :)
99
100 $ sqlt -f MySQL -t XML-SQLFairy schema.sql
101
102=head1 ARGS
0a689100 103
b89a67a0 104Doesn't take any extra arguments.
0a689100 105
4a268a6c 106=head1 LEGACY FORMAT
107
108The previous version of the SQLFairy XML allowed the attributes of the the
109schema objects to be written as either xml attributes or as data elements, in
110any combination. The old producer could produce attribute only or data element
111only versions. While this allowed for lots of flexibility in writing the XML
112the result is a great many possible XML formats, not so good for DTD writing,
113XPathing etc! So we have moved to a fixed version described above.
114
115This version of the producer will now only produce the new style XML.
116To convert your old format files simply pass them through the translator;
117
118 sqlt -f XML-SQLFairy -t XML-SQLFairy schema-old.xml > schema-new.xml
119
0a689100 120=cut
121
122use strict;
123use vars qw[ $VERSION @EXPORT_OK ];
4a268a6c 124$VERSION = sprintf "%d.%02d", q$Revision: 1.13 $ =~ /(\d+)\.(\d+)/;
0a689100 125
126use Exporter;
127use base qw(Exporter);
128@EXPORT_OK = qw(produce);
129
130use IO::Scalar;
131use SQL::Translator::Utils qw(header_comment debug);
f135f8f9 132BEGIN {
133 # Will someone fix XML::Writer already?
134 local $^W = 0;
135 require XML::Writer;
136 import XML::Writer;
137}
0a689100 138
139my $Namespace = 'http://sqlfairy.sourceforge.net/sqlfairy.xml';
b89a67a0 140my $Name = 'sqlf';
375f0be1 141my $PArgs = {};
0a689100 142
143sub produce {
144 my $translator = shift;
145 my $schema = $translator->schema;
146 $PArgs = $translator->producer_args;
147 my $io = IO::Scalar->new;
148 my $xml = XML::Writer->new(
149 OUTPUT => $io,
150 NAMESPACES => 1,
151 PREFIX_MAP => { $Namespace => $Name },
152 DATA_MODE => 1,
153 DATA_INDENT => 2,
154 );
155
156 $xml->xmlDecl('UTF-8');
157 $xml->comment(header_comment('', ''));
1caf2bb2 158 #$xml->startTag([ $Namespace => 'schema' ]);
159 xml_obj($xml, $schema,
160 tag => "schema", methods => [qw/name database/], end_tag => 0 );
0a689100 161
162 #
163 # Table
164 #
165 for my $table ( $schema->get_tables ) {
166 debug "Table:",$table->name;
d3422086 167 xml_obj($xml, $table,
168 tag => "table", methods => [qw/name order/], end_tag => 0 );
0a689100 169
170 #
171 # Fields
172 #
173 $xml->startTag( [ $Namespace => 'fields' ] );
174 for my $field ( $table->get_fields ) {
175 debug " Field:",$field->name;
d3422086 176 xml_obj($xml, $field,
177 tag =>"field",
178 end_tag => 1,
179 methods =>[qw/name data_type size is_nullable default_value
180 is_auto_increment is_primary_key is_foreign_key comments order
181 /],
182 );
0a689100 183 }
184 $xml->endTag( [ $Namespace => 'fields' ] );
185
186 #
187 # Indices
188 #
189 $xml->startTag( [ $Namespace => 'indices' ] );
190 for my $index ( $table->get_indices ) {
191 debug "Index:",$index->name;
d3422086 192 xml_obj($xml, $index,
193 tag => "index",
194 end_tag => 1,
195 methods =>[qw/ name type fields options/],
196 );
0a689100 197 }
198 $xml->endTag( [ $Namespace => 'indices' ] );
199
200 #
201 # Constraints
202 #
203 $xml->startTag( [ $Namespace => 'constraints' ] );
204 for my $index ( $table->get_constraints ) {
205 debug "Constraint:",$index->name;
d3422086 206 xml_obj($xml, $index,
207 tag => "constraint",
208 end_tag => 1,
209 methods =>[qw/
210 name type fields reference_table reference_fields
211 on_delete on_update match_type expression options deferrable
212 /],
213 );
0a689100 214 }
215 $xml->endTag( [ $Namespace => 'constraints' ] );
216
217 $xml->endTag( [ $Namespace => 'table' ] );
218 }
d3422086 219
1e3867bf 220 #
221 # Views
222 #
223 for my $foo ( $schema->get_views ) {
d3422086 224 xml_obj($xml, $foo, tag => "view",
1e3867bf 225 methods => [qw/name sql fields order/], end_tag => 1 );
226 }
d3422086 227
1e3867bf 228 #
229 # Tiggers
230 #
231 for my $foo ( $schema->get_triggers ) {
d3422086 232 xml_obj($xml, $foo, tag => "trigger",
233 methods => [qw/name database_event action on_table perform_action_when
234 fields order/], end_tag => 1 );
1e3867bf 235 }
0a689100 236
1e3867bf 237 #
238 # Procedures
239 #
240 for my $foo ( $schema->get_procedures ) {
d3422086 241 xml_obj($xml, $foo, tag => "procedure",
1e3867bf 242 methods => [qw/name sql parameters owner comments order/], end_tag=>1 );
243 }
d3422086 244
0a689100 245 $xml->endTag([ $Namespace => 'schema' ]);
246 $xml->end;
247
248 return $io;
249}
250
251# -------------------------------------------------------------------
1caf2bb2 252#
b89a67a0 253# Takes an XML Write, Schema::* object and list of method names
254# and writes the obect out as XML. All methods values are written as attributes
255# except for comments, sql and action which get written as child data elements.
256#
257# The attributes, tags are written in the same order as the method names are
258# passed.
259#
260# TODO
1caf2bb2 261# - Should the Namespace be passed in instead of global? Pass in the same
262# as Writer ie [ NS => TAGNAME ]
263#
0a689100 264sub xml_obj {
d3422086 265 my ($xml, $obj, %args) = @_;
266 my $tag = $args{'tag'} || '';
267 my $end_tag = $args{'end_tag'} || '';
d3422086 268 my @meths = @{ $args{'methods'} };
269 my $empty_tag = 0;
270
b89a67a0 271 # Use array to ensure consistant (ie not hash) ordering of attribs
272 # The order comes from the meths list passed in.
273 my @tags;
274 my @attr;
275 foreach ( grep { defined $obj->$_ } @meths ) {
276 my $what = m/^sql|comments|action$/ ? \@tags : \@attr;
277 my $val = $obj->$_;
0a689100 278 $val = ref $val eq 'ARRAY' ? join(',', @$val) : $val;
b89a67a0 279 push @$what, $_ => $val;
280 };
281 my $child_tags = @tags;
282 $end_tag && !$child_tags
283 ? $xml->emptyTag( [ $Namespace => $tag ], @attr )
284 : $xml->startTag( [ $Namespace => $tag ], @attr );
285 while ( my ($name,$val) = splice @tags,0,2 ) {
286 $xml->dataElement( [ $Namespace => $name ], $val );
0a689100 287 }
b89a67a0 288 $xml->endTag( [ $Namespace => $tag ] ) if $child_tags && $end_tag;
0a689100 289}
290
2911;
292
293# -------------------------------------------------------------------
294# The eyes of fire, the nostrils of air,
295# The mouth of water, the beard of earth.
296# William Blake
297# -------------------------------------------------------------------
298
299=pod
300
301=head1 AUTHORS
302
d3422086 303Ken Y. Clark E<lt>kclark@cpan.orgE<gt>,
304Darren Chamberlain E<lt>darren@cpan.orgE<gt>,
0a689100 305Mark Addison E<lt>mark.addison@itn.co.ukE<gt>.
306
307=head1 SEE ALSO
308
a7d50b44 309perl(1), SQL::Translator, SQL::Translator::Parser::XML::SQLFairy,
0a689100 310SQL::Translator::Schema, XML::Writer.
311
312=cut