From: Mark Addison Date: Thu, 4 Sep 2003 15:55:48 +0000 (+0000) Subject: Initial version of XMI parser. X-Git-Tag: v0.04~195 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=1223c9b2b1cdbcd1bb1794196cccca0339fef381;p=dbsrgits%2FSQL-Translator.git Initial version of XMI parser. --- diff --git a/MANIFEST b/MANIFEST index 3969952..5dfcbc6 100644 --- a/MANIFEST +++ b/MANIFEST @@ -22,6 +22,7 @@ lib/SQL/Translator/Parser/Sybase.pm lib/SQL/Translator/Parser/xSV.pm lib/SQL/Translator/Parser/XML.pm lib/SQL/Translator/Parser/XML/SQLFairy.pm +lib/SQL/Translator/Parser/XML/XMI.pm lib/SQL/Translator/Producer.pm lib/SQL/Translator/Producer/ClassDBI.pm lib/SQL/Translator/Producer/Diagram.pm @@ -61,6 +62,7 @@ t/15oracle-parser.t t/16xml-parser.t t/17sqlfxml-producer.t t/18ttschema-producer.t +t/21xml-xmi-parser.t t/data/Excel/t.xls t/data/mysql/Apache-Session-MySQL.sql t/data/mysql/BGEP-RE-create.sql @@ -74,3 +76,5 @@ t/data/mysql/entire_syntax.sql t/data/pgsql/entire_syntax.sql t/data/sybase/create.sql t/data/xml/schema-basic-attribs.xml +t/data/xmi/Foo.poseidon2.xmi +t/data/xmi/Foo.poseidon2.zuml diff --git a/lib/SQL/Translator/Parser/XML/XMI.pm b/lib/SQL/Translator/Parser/XML/XMI.pm new file mode 100644 index 0000000..695e0c4 --- /dev/null +++ b/lib/SQL/Translator/Parser/XML/XMI.pm @@ -0,0 +1,241 @@ +package SQL::Translator::Parser::XML::XMI; + +# ------------------------------------------------------------------- +# $Id: XMI.pm,v 1.1 2003-09-04 15:55:47 grommit Exp $ +# ------------------------------------------------------------------- +# Copyright (C) 2003 Mark Addison , +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; version 2. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA +# ------------------------------------------------------------------- + +=head1 NAME + +SQL::Translator::Parser::XML::XMI - Parser to create Schema from UML +Class diagrams stored in XMI format. + +=cut + +# ------------------------------------------------------------------- + +use strict; + +use vars qw[ $DEBUG $VERSION @EXPORT_OK ]; +$VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/; +$DEBUG = 0 unless defined $DEBUG; + +use Data::Dumper; +use Exporter; +use base qw(Exporter); +@EXPORT_OK = qw(parse); + +use base qw/SQL::Translator::Parser/; # Doesnt do anything at the mo! +use SQL::Translator::Utils 'debug'; +use XML::XPath; +use XML::XPath::XMLParser; + + +# Custom XPath functions +#----------------------------------------------------------------------------- + +# +# Pass a nodeset. If the first node has an xmi.idref attrib then return +# the nodeset for that id +# +sub XML::XPath::Function::xmideref { + my $self = shift; + my ($node, @params) = @_; + if (@params > 1) { + die "xmideref() function takes one or no parameters\n"; + } + elsif (@params) { + my $nodeset = shift(@params); + return $nodeset unless $nodeset->size; + $node = $nodeset->get_node(1); + } + die "xmideref() needs an Element node." + unless $node->isa("XML::XPath::Node::Element"); + + my $id = $node->getAttribute("xmi.idref") or return $node; + return $node->getRootNode->find('//*[@xmi.id="'.$id.'"]'); +} + +sub XML::XPath::Function::hello { + return XML::XPath::Literal->new("Hello World"); +} + + + +# Parser +#----------------------------------------------------------------------------- + +sub parse { + my ( $translator, $data ) = @_; + local $DEBUG = $translator->debug; + my $schema = $translator->schema; + my $pargs = $translator->parser_args; + + my $xp = XML::XPath->new(xml => $data); + + $xp->set_namespace("UML", "org.omg.xmi.namespace.UML"); + # + # 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. + # + + # + # Work our way through the classes, creating tables. We only + # want class with xmi.id attributes and not the refs to them, + # which will have xmi.idref attributes. + # + my @nodes = $xp->findnodes('//UML:Class[@xmi.id]'); + + debug "Found ".scalar(@nodes)." Classes: ".join(", ", + map {$_->getAttribute("name")} @nodes); + + for my $classnode (@nodes) { + # Only process classes with <> and name + next unless my $classname = $classnode->getAttribute("name"); + my $stereotype = "".$classnode->find( + 'xmideref(UML:ModelElement.stereotype/UML:Stereotype)/@name'); + next unless $stereotype eq "Table"; + + # Add the table + debug "Adding class: $classname as table:$classname"; + my $table = $schema->add_table(name=>$classname) + or die "Schema Error: ".$schema->error; + + # + # Fields from Class attributes + # + # name data_type size default_value is_nullable + # is_auto_increment is_primary_key is_foreign_key comments + # + foreach my $attrnode ( $classnode->findnodes( + 'UML:Classifier.feature/UML:Attribute[@xmi.id]',) + ) { + next unless my $fieldname = $attrnode->getAttribute("name"); + my $stereotype = "".$attrnode->findvalue( + 'xmideref(UML:ModelElement.stereotype/UML:Stereotype)/@name'); + my %data = ( + name => $fieldname, + data_type => "".$attrnode->find( + 'xmideref(UML:StructuralFeature.type/UML:DataType)/@name'), + is_primary_key => $stereotype eq "PK" ? 1 : 0, + #is_foreign_key => $stereotype eq "FK" ? 1 : 0, + ); + if ( my @body = $attrnode->findnodes( + 'UML:Attribute.initialValue/UML:Expression/@body') + ) { + $data{default_value} = $body[0]->getData; + } + + 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 + + return 1; +} + +1; + +# ------------------------------------------------------------------- + +=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 + +=head2 UML Data Modeling + +To tell the parser which Classes are tables give them a <
> stereotype. + +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. + +Primary keys are attributes marked with <> stereotype. + +=head2 XMI Format + +The parser has been built using XMI generated by PoseidonUML 2beta, which +says it uses UML 2. So the current conformance is down to Poseidon's idea +of XMI! + +=head1 ARGS + +=over 4 + +=item visibility TODO + + visibilty=public|private|protected|package + +What visibilty of stuff to translate. e.g when set to 'public' any private +Classes will be ignored and not turned into tables. + +=item table_visibility TODO + +=item field_visibility TODO + +=item table_stereotype Def:Table TODO + +What stereotype a class must have to turned into a table. + +=item pkey_stereotype Def:PK TODO + +=back + +=head1 BUGS + +=head1 TODO + +Deal with field sizes. Don't think UML does this directly so may need to include +it in the datatype names. + +Everything else! Relations, fkeys, constraints, indexes, etc... + +=head1 AUTHOR + +Mark D. Addison Emark.addison@itn.co.ukE. + +=head1 SEE ALSO + +perl(1), SQL::Translator, XML::XPath, SQL::Translator::Producer::XML::SQLFairy, +SQL::Translator::Schema. + +=cut diff --git a/t/21xml-xmi-parser.t b/t/21xml-xmi-parser.t new file mode 100644 index 0000000..c0bdab2 --- /dev/null +++ b/t/21xml-xmi-parser.t @@ -0,0 +1,192 @@ +#!/usr/bin/perl -w +# vim:filetype=perl + +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +# +# basic.t +# ------- +# Tests that; +# + +use strict; +use Test::More; +use Test::Exception; + +use strict; +use Data::Dumper; +my %opt; +BEGIN { map { $opt{$_}=1 if s/^-// } @ARGV; } +use constant DEBUG => (exists $opt{d} ? 1 : 0); +local $SIG{__WARN__} = sub { diag "[warn] ", @_; }; + +use FindBin qw/$Bin/; + +# Usefull test subs for the schema objs +#============================================================================= + +my %ATTRIBUTES; +$ATTRIBUTES{field} = [qw/ +name +data_type +default_value +size +is_primary_key +is_unique +is_nullable +is_foreign_key +is_auto_increment +/]; + +sub test_field { + my ($fld,$test) = @_; + die "test_field needs a least a name!" unless $test->{name}; + my $name = $test->{name}; + + foreach my $attr ( @{$ATTRIBUTES{field}} ) { + if ( exists $test->{$attr} ) { + my $ans = $test->{$attr}; + if ( $attr =~ m/^is_/ ) { + if ($ans) { ok $fld->$attr, " $name - $attr true"; } + else { ok !$fld->$attr, " $name - $attr false"; } + } + else { + is $fld->$attr, $ans, " $name - $attr = '" + .(defined $ans ? $ans : "NULL" )."'"; + } + } + else { + ok !$fld->$attr, "$name - $attr not set"; + } + } +} + +sub test_table { + my $tbl = shift; + my %arg = @_; + my $name = $arg{name} || die "Need a table name to test."; + my @fldnames = map { $_->{name} } @{$arg{fields}}; + is_deeply( [ map {$_->name} $tbl->get_fields ], + [ map {$_->{name}} @{$arg{fields}} ], + "Table $name\'s fields" ); + foreach ( @{$arg{fields}} ) { + my $name = $_->{name} || die "Need a field name to test."; + test_field( $tbl->get_field($name), $_ ); + } +} + +# Testing 1,2,3,.. +#============================================================================= + +plan tests => 85; + +use SQL::Translator; +use SQL::Translator::Schema::Constants; + +my $testschema = "$Bin/data/xmi/Foo.poseidon2.xmi"; +# Parse the test XML schema +my $obj; +$obj = SQL::Translator->new( + debug => DEBUG, + show_warnings => 1, + add_drop_table => 1, +); +die "Can't find test schema $testschema" unless -e $testschema; +my $sql = $obj->translate( + from => 'XML-XMI', + to => 'MySQL', + filename => $testschema, +); +print $sql if DEBUG; +#print "Debug: translator", Dumper($obj) if DEBUG; +#print "Debug: schema", Dumper($obj->schema) if DEBUG; + +# +# Test the schema objs generted from the XML +# +my $scma = $obj->schema; +my @tblnames = map {$_->name} $scma->get_tables; +is_deeply( \@tblnames, [qw/Foo PrivateFoo Recording Track/], "tables"); + +# +# Foo +# +test_table( $scma->get_table("Foo"), + name => "Foo", + fields => [ + { + name => "fooid", + data_type => "int", + default_value => undef, + is_nullable => 1, + is_primary_key => 1, + }, + { + name => "name", + data_type => "varchar", + default_value => "", + is_nullable => 1, + } ], +); + +# +# Recording +# +test_table( $scma->get_table("Recording"), + name => "Recording", + fields => [ + { + name => "recordingid", + data_type => "int", + default_value => undef, + is_nullable => 1, + is_primary_key => 1, + }, + { + name => "title", + data_type => "varchar", + is_nullable => 1, + }, + { + name => "type", + data_type => "varchar", + is_nullable => 1, + }, + ], +); + +# +# Track +# +test_table( $scma->get_table("Track"), + name => "Track", + fields => [ + { + name => "trackid", + data_type => "int", + default_value => undef, + is_nullable => 1, + is_primary_key => 1, + }, + { + name => "recordingid", + data_type => "int", + default_value => undef, + is_nullable => 1, + is_primary_key => 0, + #is_foreign_key => 1, + }, + { + name => "number", + data_type => "int", + default_value => "1", + is_nullable => 1, + }, + { + name => "name", + data_type => "varchar", + is_nullable => 1, + }, + ], +); diff --git a/t/data/xmi/Foo.poseidon2.xmi b/t/data/xmi/Foo.poseidon2.xmi new file mode 100644 index 0000000..82c6aed --- /dev/null +++ b/t/data/xmi/Foo.poseidon2.xmi @@ -0,0 +1,3030 @@ + + + + + Netbeans XMI Writer + 1.0 + + + + + + + + + + + + + + + + + + + + + + <p> + +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Class + + + Class + + + + + <p> +No &lt;&lt;Table&gt;&gt; so the parser should ignore it. +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Attribute + + + Attribute + + + + + + + + + + + + + + + 0.0 + 0.0 + + + 670.0 + 401.0 + + + 0.0 + 0.0 + + + + + + + + 50.0 + 120.0 + + + 130.0 + 103.0 + + + + + + + + + + + + + + + + + 1.0 + 1.0 + + + 128.0 + 36.0 + + + + + + + + 28.8809 + 2.0 + + + 70.2383 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + 20.4883 + 0.0 + + + 29.2617 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 29.2617 + 15.0 + + + + + + + + + + 52.75 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + + + 53.8164 + 19.0 + + + 20.3672 + 15.0 + + + + + + + + + + 1.0 + 37.0 + + + 128.0 + 1.0 + + + + + + + + 1.0 + 38.0 + + + 128.0 + 39.0 + + + + + + + + 2.0 + 2.0 + + + 124.0 + 35.0 + + + + + + + + 2.0 + 2.0 + + + 120.0 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 54.2378 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + 20.4883 + 0.0 + + + 13.2612 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 13.2612 + 15.0 + + + + + + + + + + 36.7495 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + + + 54.2378 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 62.9819 + 0.0 + + + 27.6611 + 15.0 + + + + + + + + 90.6431 + 0.0 + + + 3.4805 + 15.0 + + + + + + + + 94.1235 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + + + 2.0 + 18.0 + + + 120.0 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 8.7441 + 0.0 + + + 29.2993 + 15.0 + + + + + + + + 38.0435 + 0.0 + + + 3.4805 + 15.0 + + + + + + + + 41.5239 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + + + + + + + + + + + 1.0 + 77.0 + + + 128.0 + 1.0 + + + + + + + + 1.0 + 78.0 + + + 128.0 + 24.0 + + + + + + + + 2.0 + 2.0 + + + 124.0 + 20.0 + + + + + + + + + + + + 50.0 + 390.0 + + + 100.0 + 71.0 + + + + + + + + + + + + + + + 1.0 + 1.0 + + + 98.0 + 19.0 + + + + + + + + 30.8162 + 2.0 + + + 36.3677 + 15.0 + + + + + + + + + + 1.0 + 20.0 + + + 98.0 + 1.0 + + + + + + + + 1.0 + 21.0 + + + 98.0 + 24.0 + + + + + + + + 2.0 + 2.0 + + + 94.0 + 20.0 + + + + + + + + + + 1.0 + 45.0 + + + 98.0 + 1.0 + + + + + + + + 1.0 + 46.0 + + + 98.0 + 24.0 + + + + + + + + 2.0 + 2.0 + + + 94.0 + 20.0 + + + + + + + + + + + + 50.0 + 260.0 + + + 100.0 + 88.0 + + + + + + + + + + + + + + + 1.0 + 1.0 + + + 98.0 + 36.0 + + + + + + + + 13.8809 + 2.0 + + + 70.2383 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + 20.4883 + 0.0 + + + 29.2617 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 29.2617 + 15.0 + + + + + + + + + + 52.75 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + + + 19.2065 + 19.0 + + + 59.5869 + 15.0 + + + + + + + + + + 1.0 + 37.0 + + + 98.0 + 1.0 + + + + + + + + 1.0 + 38.0 + + + 98.0 + 24.0 + + + + + + + + 2.0 + 2.0 + + + 94.0 + 20.0 + + + + + + + + + + 1.0 + 62.0 + + + 98.0 + 1.0 + + + + + + + + 1.0 + 63.0 + + + 98.0 + 24.0 + + + + + + + + 2.0 + 2.0 + + + 94.0 + 20.0 + + + + + + + + + + + + 220.0 + 160.0 + + + 171.9961 + 129.0 + + + + + + + + + + + + + + + + 1.0 + 1.0 + + + 169.9961 + 36.0 + + + + + + + + 49.8789 + 2.0 + + + 70.2383 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + 20.4883 + 0.0 + + + 29.2617 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 29.2617 + 15.0 + + + + + + + + + + 52.75 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + + + 56.3674 + 19.0 + + + 57.2612 + 15.0 + + + + + + + + + + 1.0 + 37.0 + + + 169.9961 + 1.0 + + + + + + + + 1.0 + 38.0 + + + 169.9961 + 55.0 + + + + + + + + 2.0 + 2.0 + + + 165.9961 + 51.0 + + + + + + + + 2.0 + 2.0 + + + 161.9961 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 54.2378 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + 20.4883 + 0.0 + + + 13.2612 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 13.2612 + 15.0 + + + + + + + + + + 36.7495 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + + + 54.2378 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 62.9819 + 0.0 + + + 61.4131 + 15.0 + + + + + + + + 124.395 + 0.0 + + + 3.4805 + 15.0 + + + + + + + + 127.8755 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + + + 2.0 + 18.0 + + + 161.9961 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 8.7441 + 0.0 + + + 20.7163 + 15.0 + + + + + + + + 29.4604 + 0.0 + + + 3.4805 + 15.0 + + + + + + + + 32.9409 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + + + + + + + 2.0 + 34.0 + + + 161.9961 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 8.7441 + 0.0 + + + 22.9131 + 15.0 + + + + + + + + 31.6572 + 0.0 + + + 3.4805 + 15.0 + + + + + + + + 35.1377 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + + + + + + + + + + + 1.0 + 93.0 + + + 169.9961 + 1.0 + + + + + + + + 1.0 + 94.0 + + + 169.9961 + 24.0 + + + + + + + + 2.0 + 2.0 + + + 165.9961 + 20.0 + + + + + + + + + + + + 60.0 + 129.0 + + + + + + + + 171.9961 + 90.0 + + + + + + + + + + 220.0 + 320.0 + + + 100.0 + 71.0 + + + + + + + + + + + + 1.0 + 1.0 + + + 98.0 + 19.0 + + + + + + + + 40.7205 + 2.0 + + + 16.5591 + 15.0 + + + + + + + + + + 1.0 + 20.0 + + + 98.0 + 1.0 + + + + + + + + 1.0 + 21.0 + + + 98.0 + 24.0 + + + + + + + + 2.0 + 2.0 + + + 94.0 + 20.0 + + + + + + + + + + 1.0 + 45.0 + + + 98.0 + 1.0 + + + + + + + + 1.0 + 46.0 + + + 98.0 + 24.0 + + + + + + + + 2.0 + 2.0 + + + 94.0 + 20.0 + + + + + + + + + + + + 60.0 + 0.0 + + + + + + + + + + 0.0 + 0.0 + + + + 280.0 + 320.0 + + + 0.0 + 0.0 + + + 0.0 + 0.0 + + + 280.0 + 289.0 + + + 0.0 + 0.0 + + + 0.0 + 0.0 + + + + + + + + + + + + + 0.0 + 0.0 + + + 0.0 + 0.0 + + + + + + + + + + + + + + 480.0 + 220.0 + + + 180.0 + 140.0 + + + + + + + + + + + + + + + + 1.0 + 1.0 + + + 178.0 + 36.0 + + + + + + + + 53.8809 + 2.0 + + + 70.2383 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + 20.4883 + 0.0 + + + 29.2617 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 29.2617 + 15.0 + + + + + + + + + + 52.75 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + + + 73.064 + 19.0 + + + 31.8721 + 15.0 + + + + + + + + + + 1.0 + 37.0 + + + 178.0 + 1.0 + + + + + + + + 1.0 + 38.0 + + + 178.0 + 71.0 + + + + + + + + 2.0 + 2.0 + + + 174.0 + 67.0 + + + + + + + + 2.0 + 2.0 + + + 170.0 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 54.2378 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + 20.4883 + 0.0 + + + 13.2612 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 13.2612 + 15.0 + + + + + + + + + + 36.7495 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + + + 54.2378 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 62.9819 + 0.0 + + + 36.8564 + 15.0 + + + + + + + + 99.8384 + 0.0 + + + 3.4805 + 15.0 + + + + + + + + 103.3188 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + + + 2.0 + 18.0 + + + 170.0 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 54.0552 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + 20.4883 + 0.0 + + + 13.0786 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 13.0786 + 15.0 + + + + + + + + + + 36.5669 + 0.0 + + + 17.4883 + 15.0 + + + + + + + + + + 54.0552 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 62.7993 + 0.0 + + + 61.4131 + 15.0 + + + + + + + + 124.2124 + 0.0 + + + 3.4805 + 15.0 + + + + + + + + 127.6929 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + + + 2.0 + 34.0 + + + 170.0 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 8.7441 + 0.0 + + + 41.4756 + 15.0 + + + + + + + + 50.2197 + 0.0 + + + 3.4805 + 15.0 + + + + + + + + 53.7002 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 14.1206 + 15.0 + + + + + + + + + + + + 67.8208 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 76.5649 + 0.0 + + + 6.9556 + 15.0 + + + + + + + + + + 2.0 + 50.0 + + + 170.0 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 8.7441 + 15.0 + + + + + + + + 8.7441 + 0.0 + + + 29.2993 + 15.0 + + + + + + + + 38.0435 + 0.0 + + + 3.4805 + 15.0 + + + + + + + + 41.5239 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + + + + + 0.0 + 0.0 + + + 39.3057 + 15.0 + + + + + + + + + + + + + + + + + + 1.0 + 109.0 + + + 178.0 + 1.0 + + + + + + + + 1.0 + 110.0 + + + 178.0 + 24.0 + + + + + + + + 2.0 + 2.0 + + + 174.0 + 20.0 + + + + + + + + + + + + 0.0 + 30.0 + + + + + + + + + + 0.0 + 0.0 + + + + 391.9961 + 250.0 + + + 0.0 + 0.0 + + + 0.0 + 0.0 + + + 480.0 + 250.0 + + + 0.0 + 0.0 + + + 0.0 + 0.0 + + + + + + + + + + + + + 391.9961 + 250.0 + + + 0.0 + 0.0 + + + + + + + + + + + + 12.9904 + 3.5305 + + + 51.3101 + 15.0 + + + + + + + + 12.9904 + -22.5 + + + 6.9556 + 15.0 + + + + + + + + + + 480.0 + 250.0 + + + 0.0 + 0.0 + + + + + + + + + + + + -39.7438 + -21.5331 + + + 26.7534 + 15.0 + + + + + + + + -32.2082 + 7.5 + + + 19.2178 + 15.0 + + + + + + + + + + 398.0808 + 260.0 + + + 75.8345 + 15.0 + + + + + + + + 0.0 + 0.0 + + + 75.8345 + 15.0 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/t/data/xmi/Foo.poseidon2.zuml b/t/data/xmi/Foo.poseidon2.zuml new file mode 100644 index 0000000..af8cc3f Binary files /dev/null and b/t/data/xmi/Foo.poseidon2.zuml differ