1 package SQL::Translator::Parser::XML::XMI;
3 # -------------------------------------------------------------------
4 # $Id: XMI.pm,v 1.1 2003-09-04 15:55:47 grommit Exp $
5 # -------------------------------------------------------------------
6 # Copyright (C) 2003 Mark Addison <mark.addison@itn.co.uk>,
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.
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.
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
21 # -------------------------------------------------------------------
25 SQL::Translator::Parser::XML::XMI - Parser to create Schema from UML
26 Class diagrams stored in XMI format.
30 # -------------------------------------------------------------------
34 use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
35 $VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
36 $DEBUG = 0 unless defined $DEBUG;
40 use base qw(Exporter);
41 @EXPORT_OK = qw(parse);
43 use base qw/SQL::Translator::Parser/; # Doesnt do anything at the mo!
44 use SQL::Translator::Utils 'debug';
46 use XML::XPath::XMLParser;
49 # Custom XPath functions
50 #-----------------------------------------------------------------------------
53 # Pass a nodeset. If the first node has an xmi.idref attrib then return
54 # the nodeset for that id
56 sub XML::XPath::Function::xmideref {
58 my ($node, @params) = @_;
60 die "xmideref() function takes one or no parameters\n";
63 my $nodeset = shift(@params);
64 return $nodeset unless $nodeset->size;
65 $node = $nodeset->get_node(1);
67 die "xmideref() needs an Element node."
68 unless $node->isa("XML::XPath::Node::Element");
70 my $id = $node->getAttribute("xmi.idref") or return $node;
71 return $node->getRootNode->find('//*[@xmi.id="'.$id.'"]');
74 sub XML::XPath::Function::hello {
75 return XML::XPath::Literal->new("Hello World");
81 #-----------------------------------------------------------------------------
84 my ( $translator, $data ) = @_;
85 local $DEBUG = $translator->debug;
86 my $schema = $translator->schema;
87 my $pargs = $translator->parser_args;
89 my $xp = XML::XPath->new(xml => $data);
91 $xp->set_namespace("UML", "org.omg.xmi.namespace.UML");
94 # - Options to set the initial context node so we don't just
95 # blindly do all the classes. e.g. Select a diag name to do.
99 # Work our way through the classes, creating tables. We only
100 # want class with xmi.id attributes and not the refs to them,
101 # which will have xmi.idref attributes.
103 my @nodes = $xp->findnodes('//UML:Class[@xmi.id]');
105 debug "Found ".scalar(@nodes)." Classes: ".join(", ",
106 map {$_->getAttribute("name")} @nodes);
108 for my $classnode (@nodes) {
109 # Only process classes with <<Table>> and name
110 next unless my $classname = $classnode->getAttribute("name");
111 my $stereotype = "".$classnode->find(
112 'xmideref(UML:ModelElement.stereotype/UML:Stereotype)/@name');
113 next unless $stereotype eq "Table";
116 debug "Adding class: $classname as table:$classname";
117 my $table = $schema->add_table(name=>$classname)
118 or die "Schema Error: ".$schema->error;
121 # Fields from Class attributes
123 # name data_type size default_value is_nullable
124 # is_auto_increment is_primary_key is_foreign_key comments
126 foreach my $attrnode ( $classnode->findnodes(
127 'UML:Classifier.feature/UML:Attribute[@xmi.id]',)
129 next unless my $fieldname = $attrnode->getAttribute("name");
130 my $stereotype = "".$attrnode->findvalue(
131 'xmideref(UML:ModelElement.stereotype/UML:Stereotype)/@name');
134 data_type => "".$attrnode->find(
135 'xmideref(UML:StructuralFeature.type/UML:DataType)/@name'),
136 is_primary_key => $stereotype eq "PK" ? 1 : 0,
137 #is_foreign_key => $stereotype eq "FK" ? 1 : 0,
139 if ( my @body = $attrnode->findnodes(
140 'UML:Attribute.initialValue/UML:Expression/@body')
142 $data{default_value} = $body[0]->getData;
145 debug "Adding field:",Dumper(\%data);
146 my $field = $table->add_field( %data ) or die $schema->error;
148 $table->primary_key( $field->name ) if $data{'is_primary_key'};
151 # - We should be able to make the table obj spot this when
163 # -------------------------------------------------------------------
170 use SQL::Translator::Parser::XML::XMI;
172 my $translator = SQL::Translator->new(
175 filename => 'schema.xmi',
180 print $obj->translate;
184 =head2 UML Data Modeling
186 To tell the parser which Classes are tables give them a <<Table>> stereotype.
188 Any attributes of the class will be used as fields. The datatype of the
189 attribute must be a UML datatype and not an object, with the datatype's name
190 being used to set the data_type value in the schema.
192 Primary keys are attributes marked with <<PK>> stereotype.
196 The parser has been built using XMI generated by PoseidonUML 2beta, which
197 says it uses UML 2. So the current conformance is down to Poseidon's idea
204 =item visibility TODO
206 visibilty=public|private|protected|package
208 What visibilty of stuff to translate. e.g when set to 'public' any private
209 Classes will be ignored and not turned into tables.
211 =item table_visibility TODO
213 =item field_visibility TODO
215 =item table_stereotype Def:Table TODO
217 What stereotype a class must have to turned into a table.
219 =item pkey_stereotype Def:PK TODO
227 Deal with field sizes. Don't think UML does this directly so may need to include
228 it in the datatype names.
230 Everything else! Relations, fkeys, constraints, indexes, etc...
234 Mark D. Addison E<lt>mark.addison@itn.co.ukE<gt>.
238 perl(1), SQL::Translator, XML::XPath, SQL::Translator::Producer::XML::SQLFairy,
239 SQL::Translator::Schema.