Trying to correct header for HTML.
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Parser / XML / XMI.pm
CommitLineData
1223c9b2 1package SQL::Translator::Parser::XML::XMI;
2
3# -------------------------------------------------------------------
538293f0 4# $Id: XMI.pm,v 1.7 2003-09-17 16:27:21 grommit Exp $
1223c9b2 5# -------------------------------------------------------------------
6# Copyright (C) 2003 Mark Addison <mark.addison@itn.co.uk>,
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public License as
10# published by the Free Software Foundation; version 2.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15# General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20# 02111-1307 USA
21# -------------------------------------------------------------------
22
23=head1 NAME
24
25SQL::Translator::Parser::XML::XMI - Parser to create Schema from UML
26Class diagrams stored in XMI format.
27
f8ec05fa 28=head1 SYNOPSIS
29
30 use SQL::Translator;
31 use SQL::Translator::Parser::XML::XMI;
32
33 my $translator = SQL::Translator->new(
34 from => 'XML-XMI',
35 to => 'MySQL',
36 filename => 'schema.xmi',
37 show_warnings => 1,
38 add_drop_table => 1,
39 );
40
41 print $obj->translate;
42
43=head1 DESCRIPTION
44
f42065cb 45Currently pulls out all the Classes as tables.
f8ec05fa 46
47Any attributes of the class will be used as fields. The datatype of the
48attribute must be a UML datatype and not an object, with the datatype's name
49being used to set the data_type value in the schema.
50
f8ec05fa 51=head2 XMI Format
52
f42065cb 53The parser has been built using XMI 1.2 generated by PoseidonUML 2beta, which
f8ec05fa 54says it uses UML 2. So the current conformance is down to Poseidon's idea
55of XMI!
56
f42065cb 57It should also parse XMI 1.0, such as you get from Rose, but this has had
58little testing!
59
f8ec05fa 60=head1 ARGS
61
62=over 4
63
64=item visibility
65
66 visibilty=public|protected|private
67
68What visibilty of stuff to translate. e.g when set to 'public' any private
69and package Classes will be ignored and not turned into tables. Applies
70to Classes and Attributes.
71
72If not set or false (the default) no checks will be made and everything is
73translated.
74
75=back
76
1223c9b2 77=cut
78
79# -------------------------------------------------------------------
80
81use strict;
82
83use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
538293f0 84$VERSION = sprintf "%d.%02d", q$Revision: 1.7 $ =~ /(\d+)\.(\d+)/;
1223c9b2 85$DEBUG = 0 unless defined $DEBUG;
86
87use Data::Dumper;
88use Exporter;
89use base qw(Exporter);
90@EXPORT_OK = qw(parse);
91
92use base qw/SQL::Translator::Parser/; # Doesnt do anything at the mo!
93use SQL::Translator::Utils 'debug';
f42065cb 94use SQL::Translator::XMI::Parser;
91ed9c32 95
91ed9c32 96
f42065cb 97# SQLFairy Parser
98#-----------------------------------------------------------------------------
91ed9c32 99
f42065cb 100# is_visible - Used to check visibility in filter subs
101{
102 my %vislevel = (
103 public => 1,
104 protected => 2,
105 private => 3,
106 );
5cb154e5 107
f42065cb 108 sub is_visible {
109 my ($nodevis, $vis) = @_;
110 $nodevis = ref $_[0] ? $_[0]->{visibility} : $_[0];
111 return 1 unless $vis;
112 return 1 if $vislevel{$vis} >= $vislevel{$nodevis};
113 return 0;
5cb154e5 114 }
5cb154e5 115}
91ed9c32 116
538293f0 117my ($schema, $pargs);
118
1223c9b2 119sub parse {
120 my ( $translator, $data ) = @_;
f42065cb 121 local $DEBUG = $translator->debug;
538293f0 122 $schema = $translator->schema;
123 $pargs = $translator->parser_args;
124
ef2d7798 125 debug "Visibility Level:$pargs->{visibility}" if $DEBUG;
126
f42065cb 127 my $xmip = SQL::Translator::XMI::Parser->new(xml => $data);
128
1223c9b2 129 # TODO
130 # - Options to set the initial context node so we don't just
131 # blindly do all the classes. e.g. Select a diag name to do.
538293f0 132
f42065cb 133 my $classes = $xmip->get_classes(
134 filter => sub {
135 return unless $_->{name};
136 return unless is_visible($_, $pargs->{visibility});
137 return 1;
138 },
139 filter_attributes => sub {
140 return unless $_->{name};
141 return unless is_visible($_, $pargs->{visibility});
142 return 1;
143 },
144 );
538293f0 145
f8ec05fa 146 debug "Found ".scalar(@$classes)." Classes: ".join(", ",
147 map {$_->{"name"}} @$classes) if $DEBUG;
f42065cb 148 debug "Classes:",Dumper($classes);
149 #print "Classes:",Dumper($classes),"\n";
f8ec05fa 150
151 #
152 # Turn the data from get_classes into a Schema
153 #
538293f0 154 profile_default($classes);
155
156
157 return 1;
158}
159
160sub profile_default {
161 my ($classes) = @_;
162
f8ec05fa 163 foreach my $class (@$classes) {
1223c9b2 164 # Add the table
f8ec05fa 165 debug "Adding class: $class->{name}" if $DEBUG;
166 my $table = $schema->add_table( name => $class->{name} )
1223c9b2 167 or die "Schema Error: ".$schema->error;
168
169 #
170 # Fields from Class attributes
171 #
f8ec05fa 172 foreach my $attr ( @{$class->{attributes}} ) {
173 my %data = (
174 name => $attr->{name},
175 data_type => $attr->{datatype},
176 is_primary_key => $attr->{stereotype} eq "PK" ? 1 : 0,
1223c9b2 177 #is_foreign_key => $stereotype eq "FK" ? 1 : 0,
178 );
f8ec05fa 179 $data{default_value} = $attr->{initialValue}
180 if exists $attr->{initialValue};
1223c9b2 181
182 debug "Adding field:",Dumper(\%data);
183 my $field = $table->add_field( %data ) or die $schema->error;
184
185 $table->primary_key( $field->name ) if $data{'is_primary_key'};
186 #
187 # TODO:
ef2d7798 188 # - We should be able to make the table obj spot this when
1223c9b2 189 # we use add_field.
190 #
191 }
192
193 } # Classes loop
538293f0 194}
1223c9b2 195
538293f0 196sub profile_rational {
197 my ($classes) = @_;
198
199 foreach my $class (@$classes) {
200 next unless $class->{stereotype} eq "Table";
201
202 # Add the table
203 debug "Adding class: $class->{name}" if $DEBUG;
204 my $table = $schema->add_table( name => $class->{name} )
205 or die "Schema Error: ".$schema->error;
206
207 #
208 # Fields from Class attributes
209 #
210 foreach my $attr ( @{$class->{attributes}} ) {
211 next unless $attr->{stereotype} eq "Column"
212 or $attr->{stereotype} eq "PK"
213 or $attr->{stereotype} eq "FK"
214 or $attr->{stereotype} eq "PFK";
215
216 my $ispk =
217 $attr->{stereotype} eq "PK" or $attr->{stereotype} eq "PFK"
218 ? 1 : 0;
219 my %data = (
220 name => $attr->{name},
221 data_type => $attr->{datatype},
222 is_primary_key => $ispk,
223 );
224 $data{default_value} = $attr->{initialValue}
225 if exists $attr->{initialValue};
226
227 my $field = $table->add_field( %data ) or die $schema->error;
228 $table->primary_key( $field->name ) if $data{'is_primary_key'};
229 }
230
231 #
232 # Constraints and indexes from Operations
233 #
234 foreach my $op ( @{$class->{operations}} ) {
235 next unless my $stereo = $op->{stereotype};
236 my @fields = map {$_->{name}} @{$op->{parameters}};
237 my %data = (
238 name => $op->{name},
239 type => "",
240 fields => [@fields],
241 );
242
243 # Work out type and any other data
244 if ( $stereo eq "Unique" ) {
245 $data{type} = "UNIQUE";
246 }
247 elsif ( $stereo eq "PK" ) {
248 $data{type} = "PRIMARY_KEY";
249 }
250 # TODO We need to work out the ref table
251 #elsif ( $stereo eq "FK" ) {
252 # $data{type} = "FOREIGN_KEY";
253 #}
254
255 # Add the constraint or index
256 if ( $data{type} ) {
257 $table->add_constraint( %data ) or die $schema->error;
258 }
259 elsif ( $stereo eq "Index" ) {
260 $data{type} = "NORMAL";
261 $table->add_index( %data ) or die $schema->error;
262 }
263
264
265 } # Ops loop
266
267 } # Classes loop
1223c9b2 268}
269
538293f0 2701; #---------------------------------------------------------------------------
1223c9b2 271
538293f0 272__END__
f8ec05fa 273
274=pod
1223c9b2 275
276=head1 BUGS
277
ef2d7798 278Seems to be slow. I think this is because the XMI files can get pretty
f42065cb 279big and complex, especially all the diagram info, and XPath needs to load the
280whole tree.
ef2d7798 281
1223c9b2 282=head1 TODO
283
ef2d7798 284B<field sizes> Don't think UML does this directly so may need to include
1223c9b2 285it in the datatype names.
286
ef2d7798 287B<table_visibility and field_visibility args> Seperate control over what is
288parsed, setting visibility arg will set both.
289
1223c9b2 290Everything else! Relations, fkeys, constraints, indexes, etc...
291
292=head1 AUTHOR
293
294Mark D. Addison E<lt>mark.addison@itn.co.ukE<gt>.
295
296=head1 SEE ALSO
297
298perl(1), SQL::Translator, XML::XPath, SQL::Translator::Producer::XML::SQLFairy,
299SQL::Translator::Schema.
300
301=cut
f8ec05fa 302
303