package SQL::Translator::Parser::XML::XMI;
# -------------------------------------------------------------------
-# $Id: XMI.pm,v 1.7 2003-09-17 16:27:21 grommit Exp $
+# $Id: XMI.pm,v 1.10 2003-10-03 13:17:28 grommit Exp $
# -------------------------------------------------------------------
# Copyright (C) 2003 Mark Addison <mark.addison@itn.co.uk>,
#
SQL::Translator::Parser::XML::XMI - Parser to create Schema from UML
Class diagrams stored in XMI format.
-=head1 SYNOPSIS
-
- use SQL::Translator;
- use SQL::Translator::Parser::XML::XMI;
-
- my $translator = SQL::Translator->new(
- from => 'XML-XMI',
- to => 'MySQL',
- filename => 'schema.xmi',
- show_warnings => 1,
- add_drop_table => 1,
- );
-
- print $obj->translate;
-
-=head1 DESCRIPTION
-
-Currently pulls out all the Classes as tables.
-
-Any attributes of the class will be used as fields. The datatype of the
-attribute must be a UML datatype and not an object, with the datatype's name
-being used to set the data_type value in the schema.
-
-=head2 XMI Format
-
-The parser has been built using XMI 1.2 generated by PoseidonUML 2beta, which
-says it uses UML 2. So the current conformance is down to Poseidon's idea
-of XMI!
-
-It should also parse XMI 1.0, such as you get from Rose, but this has had
-little testing!
-
-=head1 ARGS
-
-=over 4
-
-=item visibility
-
- visibilty=public|protected|private
-
-What visibilty of stuff to translate. e.g when set to 'public' any private
-and package Classes will be ignored and not turned into tables. Applies
-to Classes and Attributes.
-
-If not set or false (the default) no checks will be made and everything is
-translated.
-
-=back
-
=cut
-# -------------------------------------------------------------------
-
use strict;
use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
-$VERSION = sprintf "%d.%02d", q$Revision: 1.7 $ =~ /(\d+)\.(\d+)/;
+$VERSION = sprintf "%d.%02d", q$Revision: 1.10 $ =~ /(\d+)\.(\d+)/;
$DEBUG = 0 unless defined $DEBUG;
use Data::Dumper;
use SQL::Translator::Utils 'debug';
use SQL::Translator::XMI::Parser;
-
# SQLFairy Parser
#-----------------------------------------------------------------------------
local $DEBUG = $translator->debug;
$schema = $translator->schema;
$pargs = $translator->parser_args;
+ $pargs->{classes2schema} ||= \&classes2schema;
debug "Visibility Level:$pargs->{visibility}" if $DEBUG;
- my $xmip = SQL::Translator::XMI::Parser->new(xml => $data);
+ my $xmip = SQL::Translator::XMI::Parser->new(xml => $data);
# TODO
# - Options to set the initial context node so we don't just
return 1;
},
);
-
debug "Found ".scalar(@$classes)." Classes: ".join(", ",
map {$_->{"name"}} @$classes) if $DEBUG;
- debug "Classes:",Dumper($classes);
- #print "Classes:",Dumper($classes),"\n";
+ debug "Model:",Dumper($xmip->{model}) if $DEBUG;
#
# Turn the data from get_classes into a Schema
#
- profile_default($classes);
-
+ $pargs->{classes2schema}->($schema, $classes);
return 1;
}
-sub profile_default {
- my ($classes) = @_;
+1;
+
+# Default conversion sub. Makes all classes into tables using all their
+# attributes.
+sub classes2schema {
+ my ($schema, $classes) = @_;
foreach my $class (@$classes) {
# Add the table
- debug "Adding class: $class->{name}" if $DEBUG;
+ debug "Adding class: $class->{name}";
my $table = $schema->add_table( name => $class->{name} )
or die "Schema Error: ".$schema->error;
foreach my $attr ( @{$class->{attributes}} ) {
my %data = (
name => $attr->{name},
- data_type => $attr->{datatype},
is_primary_key => $attr->{stereotype} eq "PK" ? 1 : 0,
#is_foreign_key => $stereotype eq "FK" ? 1 : 0,
);
$data{default_value} = $attr->{initialValue}
if exists $attr->{initialValue};
+ $data{data_type} = $attr->{_map_taggedValues}{dataType}{dataValue}
+ || $attr->{dataType}{name};
+ $data{size} = $attr->{_map_taggedValues}{size}{dataValue};
+ $data{is_nullable}=$attr->{_map_taggedValues}{nullable}{dataValue};
- debug "Adding field:",Dumper(\%data);
my $field = $table->add_field( %data ) or die $schema->error;
-
$table->primary_key( $field->name ) if $data{'is_primary_key'};
- #
- # TODO:
- # - We should be able to make the table obj spot this when
- # we use add_field.
- #
}
} # Classes loop
}
-sub profile_rational {
- my ($classes) = @_;
+1;
- foreach my $class (@$classes) {
- next unless $class->{stereotype} eq "Table";
+__END__
- # Add the table
- debug "Adding class: $class->{name}" if $DEBUG;
- my $table = $schema->add_table( name => $class->{name} )
- or die "Schema Error: ".$schema->error;
+=pod
- #
- # Fields from Class attributes
- #
- foreach my $attr ( @{$class->{attributes}} ) {
- next unless $attr->{stereotype} eq "Column"
- or $attr->{stereotype} eq "PK"
- or $attr->{stereotype} eq "FK"
- or $attr->{stereotype} eq "PFK";
-
- my $ispk =
- $attr->{stereotype} eq "PK" or $attr->{stereotype} eq "PFK"
- ? 1 : 0;
- my %data = (
- name => $attr->{name},
- data_type => $attr->{datatype},
- is_primary_key => $ispk,
- );
- $data{default_value} = $attr->{initialValue}
- if exists $attr->{initialValue};
+=head1 SYNOPSIS
- my $field = $table->add_field( %data ) or die $schema->error;
- $table->primary_key( $field->name ) if $data{'is_primary_key'};
- }
-
- #
- # Constraints and indexes from Operations
- #
- foreach my $op ( @{$class->{operations}} ) {
- next unless my $stereo = $op->{stereotype};
- my @fields = map {$_->{name}} @{$op->{parameters}};
- my %data = (
- name => $op->{name},
- type => "",
- fields => [@fields],
- );
-
- # Work out type and any other data
- if ( $stereo eq "Unique" ) {
- $data{type} = "UNIQUE";
- }
- elsif ( $stereo eq "PK" ) {
- $data{type} = "PRIMARY_KEY";
- }
- # TODO We need to work out the ref table
- #elsif ( $stereo eq "FK" ) {
- # $data{type} = "FOREIGN_KEY";
- #}
-
- # Add the constraint or index
- if ( $data{type} ) {
- $table->add_constraint( %data ) or die $schema->error;
- }
- elsif ( $stereo eq "Index" ) {
- $data{type} = "NORMAL";
- $table->add_index( %data ) or die $schema->error;
- }
-
-
- } # Ops loop
+ use SQL::Translator;
+ use SQL::Translator::Parser::XML::XMI;
- } # Classes loop
-}
+ my $translator = SQL::Translator->new(
+ from => 'XML-XMI',
+ to => 'MySQL',
+ filename => 'schema.xmi',
+ show_warnings => 1,
+ add_drop_table => 1,
+ );
+
+ print $obj->translate;
-1; #---------------------------------------------------------------------------
+=head1 DESCRIPTION
-__END__
+Translates XMI (UML models in XML format) into Schema. This basic parser
+will just pull out all the classes as tables with fields from their attributes.
+
+For more detail you will need to use a UML profile for data modelling. These are
+supported by sub parsers. See their docs for details.
+
+=over 4
+
+=item XML::XMI::Rational
+
+The Rational Software UML Data Modeling Profile
+
+=back
+
+=head1 ARGS
+
+=over 4
+
+=item visibility
+
+ visibilty=public|protected|private
+
+What visibilty of stuff to translate. e.g when set to 'public' any private
+and package Classes will be ignored and not turned into tables. Applies
+to Classes and Attributes.
+
+If not set or false (the default) no checks will be made and everything is
+translated.
+
+=back
+
+=head1 XMI Format
+
+Uses either XMI v1.0 or v1.2. The version to use is detected automatically
+from the <XMI> tag in the source file.
+
+The parser has been built using XMI 1.2 generated by PoseidonUML 2, which
+says it uses UML 2. So the current conformance is down to Poseidon's idea
+of XMI! 1.0 support is based on a Rose file, is less complete and has little
+testing.
-=pod
=head1 BUGS
big and complex, especially all the diagram info, and XPath needs to load the
whole tree.
-=head1 TODO
-
-B<field sizes> Don't think UML does this directly so may need to include
-it in the datatype names.
+Deleting the diagrams from an XMI1.2 file (make a backup!) will really speed
+things up. Remove <UML:Diagram> tags and all their contents.
-B<table_visibility and field_visibility args> Seperate control over what is
-parsed, setting visibility arg will set both.
+=head1 TODO
-Everything else! Relations, fkeys, constraints, indexes, etc...
+More profiles.
=head1 AUTHOR