Added parsing of field.extra
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Parser / XML / XMI.pm
index f62a911..b1e426c 100644 (file)
@@ -1,7 +1,7 @@
 package SQL::Translator::Parser::XML::XMI;
 
 # -------------------------------------------------------------------
-# $Id: XMI.pm,v 1.6 2003-09-16 16:29:49 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>,
 #
@@ -25,63 +25,12 @@ package SQL::Translator::Parser::XML::XMI;
 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.6 $ =~ /(\d+)\.(\d+)/;
+$VERSION = sprintf "%d.%02d", q$Revision: 1.10 $ =~ /(\d+)\.(\d+)/;
 $DEBUG   = 0 unless defined $DEBUG;
 
 use Data::Dumper;
@@ -93,7 +42,6 @@ use base qw/SQL::Translator::Parser/;  # Doesnt do anything at the mo!
 use SQL::Translator::Utils 'debug';
 use SQL::Translator::XMI::Parser;
 
-
 # SQLFairy Parser
 #-----------------------------------------------------------------------------
 
@@ -114,22 +62,23 @@ use SQL::Translator::XMI::Parser;
     }
 }
 
+my ($schema, $pargs);
+
 sub parse {
     my ( $translator, $data ) = @_;
     local $DEBUG  = $translator->debug;
-    my $schema    = $translator->schema;
-    my $pargs     = $translator->parser_args;
-    
-    eval {
-        
+    $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
     #   blindly do all the classes. e.g. Select a diag name to do.
-    
+
     my $classes = $xmip->get_classes(
         filter => sub {
             return unless $_->{name};
@@ -142,21 +91,28 @@ sub parse {
             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
        #
-       # TODO This is where we will applie different strategies for different UML
-       # data modeling profiles.
-       #
+       $pargs->{classes2schema}->($schema, $classes);
+
+    return 1;
+}
+
+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;
 
@@ -166,52 +122,100 @@ sub parse {
         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
-    
-    };
-    print "ERROR:$@" if $@;
-
-    return 1;
 }
 
 1;
 
+__END__
 
 =pod
 
+=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
+
+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.
+
+
 =head1 BUGS
 
 Seems to be slow. I think this is because the XMI files can get pretty
 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