2 role SQL::Translator::Producer::XML {
3 use MooseX::Types::Moose qw(HashRef);
5 #use SQL::Translator::Utils qw(header_comment debug);
7 # Will someone fix XML::Writer already?
13 # Which schema object attributes (methods) to write as xml elements rather than
14 # as attributes. e.g. <comments>blah, blah...</comments>
15 my @MAP_AS_ELEMENTS = qw/sql comments action extra/;
17 my $Namespace = 'http://sqlfairy.sourceforge.net/sqlfairy.xml';
23 my $translator = $self->translator;
24 my $schema = $translator->schema;
25 $no_comments = $translator->no_comments;
26 # $PArgs = $translator->producer_args;
27 my $newlines = defined $PArgs->{newlines} ? $PArgs->{newlines} : 1;
28 my $indent = defined $PArgs->{indent} ? $PArgs->{indent} : 2;
29 my $io = IO::Scalar->new;
31 # Setup the XML::Writer and set the namespace
33 $prefix = $Name if $PArgs->{add_prefix};
34 $prefix = $PArgs->{prefix} if $PArgs->{prefix};
35 my $xml = XML::Writer->new(
38 PREFIX_MAP => { $Namespace => $prefix },
39 DATA_MODE => $newlines,
40 DATA_INDENT => $indent,
44 $xml->xmlDecl('UTF-8');
46 # $xml->comment(header_comment('', ''))
47 # unless $no_comments;
49 xml_obj($xml, $schema,
50 { tag => "schema", methods => [qw/name database /], end_tag => 0 });
51 # tag => "schema", methods => [qw/name database extra/], end_tag => 0 );
56 $xml->startTag( [ $Namespace => "tables" ] );
57 for my $table ( $schema->get_tables ) {
58 # debug "Table:",$table->name;
61 methods => [qw/name order/],
62 # methods => [qw/name order extra/],
69 xml_obj_children( $xml, $table,
72 name data_type size is_nullable default_value is_auto_increment
73 is_primary_key is_foreign_key comments order
75 # is_primary_key is_foreign_key extra comments order
81 xml_obj_children( $xml, $table,
83 collection_tag => "indices",
84 methods => [qw/name type fields options/], }
85 # methods => [qw/name type fields options extra/],
91 xml_obj_children( $xml, $table,
92 { tag => 'constraint',
94 # name type fields reference_table reference_fields
95 # on_delete on_update match_type expression options deferrable
98 methods => [qw/name type expression options deferrable/], }
104 xml_obj_children( $xml, $table,
106 # collection_tag => "comments",
112 $xml->endTag( [ $Namespace => 'table' ] );
114 $xml->endTag( [ $Namespace => 'tables' ] );
119 xml_obj_children( $xml, $schema,
121 methods => [qw/name sql fields/], }
122 # methods => [qw/name sql fields order extra/],
128 xml_obj_children( $xml, $schema,
130 methods => [qw/name database_events action on_table perform_action_when fields order/], }
131 # methods => [qw/name database_events action on_table perform_action_when fields order extra/],
137 xml_obj_children( $xml, $schema,
138 { tag => 'procedure',
139 methods => [qw/name sql parameters owner comments order/], }
140 # methods => [qw/name sql parameters owner comments order extra/],
143 $xml->endTag([ $Namespace => 'schema' ]);
151 # Takes and XML::Write object, Schema::* parent object, the tag name,
152 # the collection name and a list of methods (of the children) to write as XML.
153 # The collection name defaults to the name with an s on the end and is used to
154 # work out the method to get the children with. eg a name of 'foo' gives a
155 # collection of foos and gets the members using ->get_foos.
157 #sub xml_obj_children {
158 method xml_obj_children($xml: $parent, HashRef $args?) {
159 # my ($xml,$parent) = (shift,shift);
162 my ($name,$collection_name,$methods)
163 = @{$args}{qw/tag collection_tag methods/};
164 $collection_name ||= "${name}s";
167 if ( $collection_name eq 'comments' ) {
170 $meth = "get_$collection_name";
173 my @kids = $parent->$meth;
175 $xml->startTag( [ $Namespace => $collection_name ] );
177 for my $obj ( @kids ) {
178 if ( $collection_name eq 'comments' ){
179 $xml->dataElement( [ $Namespace => 'comment' ], $obj );
184 methods => $methods, }
188 $xml->endTag( [ $Namespace => $collection_name ] );
192 # Takes an XML::Writer, Schema::* object and list of method names
193 # and writes the obect out as XML. All methods values are written as attributes
194 # except for the methods listed in @MAP_AS_ELEMENTS which get written as child
197 # The attributes/tags are written in the same order as the method names are
201 # - Should the Namespace be passed in instead of global? Pass in the same
202 # as Writer ie [ NS => TAGNAME ]
204 my $elements_re = join("|", @MAP_AS_ELEMENTS);
205 $elements_re = qr/^($elements_re)$/;
207 method xml_obj($xml: $obj, HashRef $args?) {
208 # my ($xml, $obj, %args) = @_;
209 my $tag = $args->{'tag'} || '';
210 my $end_tag = $args->{'end_tag'} || '';
211 my @meths = @{ $args->{'methods'} };
214 # Use array to ensure consistant (ie not hash) ordering of attribs
215 # The order comes from the meths list passed in.
218 foreach ( grep { defined $obj->$_ } @meths ) {
219 my $what = m/$elements_re/ ? \@tags : \@attr;
220 my $val = $_ eq 'extra'
223 $val = ref $val eq 'ARRAY' ? join(',', @$val) : $val;
224 push @$what, $_ => $val;
226 my $child_tags = @tags;
227 $end_tag && !$child_tags
228 ? $xml->emptyTag( [ $Namespace => $tag ], @attr )
229 : $xml->startTag( [ $Namespace => $tag ], @attr );
230 while ( my ($name,$val) = splice @tags,0,2 ) { warn "NAME: $name, $val";
231 if ( ref $val eq 'HASH' ) {
232 $xml->emptyTag( [ $Namespace => $name ],
233 map { ($_, $val->{$_}) } sort keys %$val );
236 $xml->dataElement( [ $Namespace => $name ], $val );
239 $xml->endTag( [ $Namespace => $tag ] ) if $child_tags && $end_tag;