Whitespace
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Parser / XML / SQLFairy.pm
index f8af966..28210d8 100644 (file)
@@ -1,9 +1,8 @@
 package SQL::Translator::Parser::XML::SQLFairy;
 
 # -------------------------------------------------------------------
-# $Id: SQLFairy.pm,v 1.8 2004-07-09 00:50:06 grommit Exp $
-# -------------------------------------------------------------------
 # Copyright (C) 2003 Mark Addison <mark.addison@itn.co.uk>,
+# Copyright (C) 2009 Jonathan Yu <frequency@cpan.org>
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
@@ -27,22 +26,21 @@ SQL::Translator::Parser::XML::SQLFairy - parser for SQL::Translator's XML.
 =head1 SYNOPSIS
 
   use SQL::Translator;
-  use SQL::Translator::Parser::XML::SQLFairy;
 
-  my $translator     = SQL::Translator->new(
-      from           => 'XML-SQLFairy',
-      to             => 'MySQL',
-      filename       => 'schema.xml',
-      show_warnings  => 1,
-      add_drop_table => 1,
-  );
+  my $translator = SQL::Translator->new( show_warnings  => 1 );
+
+  my $out = $obj->translate(
+      from     => 'XML-SQLFairy',
+      to       => 'MySQL',
+      filename => 'schema.xml',
+  ) or die $translator->error;
 
-  print $obj->translate;
+  print $out;
 
 =head1 DESCRIPTION
 
 This parser handles the flavor of XML used natively by the SQLFairy
-project (SQL::Translator).  The XML must be in the namespace
+project (L<SQL::Translator>).  The XML must be in the namespace
 "http://sqlfairy.sourceforge.net/sqlfairy.xml."
 See L<SQL::Translator::Producer::XML::SQLFairy> for details of this format.
 
@@ -64,15 +62,14 @@ tags then the order the tags appear in the XML will be used.
 
 =head2 default_value
 
-Leave the tag out all together to use the default in Schema::Field.
-Use empty tags or 'EMPTY_STRING' for a zero lenth string. 'NULL' for an
+Leave the attribute out all together to use the default in L<Schema::Field>.
+Use empty quotes or 'EMPTY_STRING' for a zero lenth string. 'NULL' for an
 explicit null (currently sets default_value to undef in the
 Schema::Field obj).
 
-  <sqlf:default_value></sqlf:default_value>             <!-- Empty string -->
-  <sqlf:default_value>EMPTY_STRING</sqlf:default_value> <!-- Empty string -->
-  <sqlf:default_value/>                                 <!-- Empty string -->
-  <sqlf:default_value>NULL</sqlf:default_value>         <!-- NULL -->
+  <sqlf:field default_value="" />                <!-- Empty string -->
+  <sqlf:field default_value="EMPTY_STRING" />    <!-- Empty string -->
+  <sqlf:field default_value="NULL" />            <!-- NULL -->
 
 =head2 ARGS
 
@@ -88,13 +85,12 @@ XPathing etc! So we have moved to a fixed version described in
 L<SQL::Translator::Producer::XML::SQLFairy>.
 
 This version of the parser will still parse the old formats and emmit warnings
-when it sees them being used.
-The old format is B<heavily depreciated> and B<will not> be supported in future
-versions.
+when it sees them being used but they should be considered B<heavily
+depreciated>.
 
-To convert your old format files simply pass them through the translator;
+To convert your old format files simply pass them through the translator :)
 
- sqlt -f XML-SQLFairy -t XML-SQLFairy schema-old.xml > schema-new.xml
+ $ sqlt -f XML-SQLFairy -t XML-SQLFairy schema-old.xml > schema-new.xml
 
 =cut
 
@@ -103,42 +99,46 @@ To convert your old format files simply pass them through the translator;
 use strict;
 
 use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
-$VERSION = sprintf "%d.%02d", q$Revision: 1.8 $ =~ /(\d+)\.(\d+)/;
+$VERSION = '1.59';
 $DEBUG   = 0 unless defined $DEBUG;
 
 use Data::Dumper;
+use Carp::Clan qw/^SQL::Translator/;
 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;
+use XML::LibXML 1.69;
+use XML::LibXML::XPathContext;
 
 sub parse {
     my ( $translator, $data ) = @_;
     my $schema                = $translator->schema;
     local $DEBUG              = $translator->debug;
-    my $xp                    = XML::XPath->new(xml => $data);
+    my $doc                   = XML::LibXML->new->parse_string($data);
+    my $xp                    = XML::LibXML::XPathContext->new($doc);
 
-    $xp->set_namespace("sqlf", "http://sqlfairy.sourceforge.net/sqlfairy.xml");
+    $xp->registerNs("sqlf", "http://sqlfairy.sourceforge.net/sqlfairy.xml");
 
     #
     # Work our way through the tables
     #
-    my @nodes = $xp->findnodes('/sqlf:schema/sqlf:table');
+    my @nodes = $xp->findnodes(
+        '/sqlf:schema/sqlf:table|/sqlf:schema/sqlf:tables/sqlf:table'
+    );
     for my $tblnode (
         sort {
-            "".$xp->findvalue('sqlf:order|@order',$a)
+            ("".$xp->findvalue('sqlf:order|@order',$a) || 0)
             <=>
-            "".$xp->findvalue('sqlf:order|@order',$b)
+            ("".$xp->findvalue('sqlf:order|@order',$b) || 0)
         } @nodes
     ) {
         debug "Adding table:".$xp->findvalue('sqlf:name',$tblnode);
 
         my $table = $schema->add_table(
-            get_tagfields($xp, $tblnode, "sqlf:" => qw/name order/)
+            get_tagfields($xp, $tblnode, "sqlf:" => qw/name order extra/)
         ) or die $schema->error;
 
         #
@@ -187,7 +187,7 @@ sub parse {
         foreach (@nodes) {
             my %data = get_tagfields($xp, $_, "sqlf:",
                 qw/name type table fields reference_fields reference_table
-                match_type on_delete_do on_update_do/
+                match_type on_delete on_update extra/
             );
             $table->add_constraint( %data ) or die $table->error;
         }
@@ -198,19 +198,31 @@ sub parse {
         @nodes = $xp->findnodes('sqlf:indices/sqlf:index',$tblnode);
         foreach (@nodes) {
             my %data = get_tagfields($xp, $_, "sqlf:",
-                qw/name type fields options/);
+                qw/name type fields options extra/);
             $table->add_index( %data ) or die $table->error;
         }
 
+
+        #
+        # Comments
+        #
+        @nodes = $xp->findnodes('sqlf:comments/sqlf:comment',$tblnode);
+        foreach (@nodes) {
+            my $data = $_->string_value;
+            $table->comments( $data );
+        }
+
     } # tables loop
 
     #
     # Views
     #
-    @nodes = $xp->findnodes('/sqlf:schema/sqlf:view');
+    @nodes = $xp->findnodes(
+        '/sqlf:schema/sqlf:view|/sqlf:schema/sqlf:views/sqlf:view'
+    );
     foreach (@nodes) {
         my %data = get_tagfields($xp, $_, "sqlf:",
-            qw/name sql fields order/
+            qw/name sql fields order extra/
         );
         $schema->add_view( %data ) or die $schema->error;
     }
@@ -218,21 +230,43 @@ sub parse {
     #
     # Triggers
     #
-    @nodes = $xp->findnodes('/sqlf:schema/sqlf:trigger');
+    @nodes = $xp->findnodes(
+        '/sqlf:schema/sqlf:trigger|/sqlf:schema/sqlf:triggers/sqlf:trigger'
+    );
     foreach (@nodes) {
-        my %data = get_tagfields($xp, $_, "sqlf:",
-        qw/name perform_action_when database_event fields on_table action order/
-        );
+        my %data = get_tagfields($xp, $_, "sqlf:", qw/
+            name perform_action_when database_event database_events fields
+            on_table action order extra
+        /);
+
+        # back compat
+        if (my $evt = $data{database_event} and $translator->{show_warnings}) {
+          carp 'The database_event tag is deprecated - please use ' .
+            'database_events (which can take one or more comma separated ' .
+            'event names)';
+          $data{database_events} = join (', ',
+            $data{database_events} || (),
+            $evt,
+          );
+        }
+
+        # split into arrayref
+        if (my $evts = $data{database_events}) {
+          $data{database_events} = [split (/\s*,\s*/, $evts) ];
+        }
+
         $schema->add_trigger( %data ) or die $schema->error;
     }
 
     #
     # Procedures
     #
-    @nodes = $xp->findnodes('/sqlf:schema/sqlf:procedure');
+    @nodes = $xp->findnodes(
+       '/sqlf:schema/sqlf:procedure|/sqlf:schema/sqlf:procedures/sqlf:procedure'
+    );
     foreach (@nodes) {
         my %data = get_tagfields($xp, $_, "sqlf:",
-        qw/name sql parameters owner comments order/
+        qw/name sql parameters owner comments order extra/
         );
         $schema->add_procedure( %data ) or die $schema->error;
     }
@@ -258,27 +292,26 @@ sub get_tagfields {
 
         my $is_attrib = m/^(sql|comments|action|extra)$/ ? 0 : 1;
 
-        my $attrib_path = "\@$thisns$_";
+        my $attrib_path = "\@$_";
         my $tag_path    = "$thisns$_";
-        if ( $xp->exists($attrib_path,$node) ) {
-            $data{$_} = "".$xp->findvalue($attrib_path,$node);
+        if ( my $found = $xp->find($attrib_path,$node) ) {
+            $data{$_} = "".$found->to_literal;
             warn "Use of '$_' as an attribute is depricated."
                 ." Use a child tag instead."
                 ." To convert your file to the new version see the Docs.\n"
                 unless $is_attrib;
             debug "Got $_=".( defined $data{ $_ } ? $data{ $_ } : 'UNDEF' );
         }
-        elsif ( $xp->exists($tag_path,$node) ) {
+        elsif ( $found = $xp->find($tag_path,$node) ) {
             if ($_ eq "extra") {
                 my %extra;
-                my $extra_nodes = $xp->find($tag_path,$node);
-                foreach ( $extra_nodes->pop->getAttributes ) {
+                foreach ( $found->pop->getAttributes ) {
                     $extra{$_->getName} = $_->getData;
                 }
                 $data{$_} = \%extra;
             }
             else {
-                $data{$_} = "".$xp->findvalue($tag_path,$node);
+                $data{$_} = "".$found->to_literal;
             }
             warn "Use of '$_' as a child tag is depricated."
                 ." Use an attribute instead."
@@ -299,9 +332,14 @@ sub get_tagfields {
 
 =head1 BUGS
 
-Ignores the order attribute for Constraints, Views, Indices,
-Views, Triggers and Procedures, using the tag order instead. (This is the order
-output by the SQLFairy XML producer).
+Ignores the order attribute for Constraints, Views, Indices, Views, Triggers
+and Procedures, using the tag order instead. (This is the order output by the
+SQLFairy XML producer).
+
+=head1 SEE ALSO
+
+L<perl>, L<SQL::Translator>, L<SQL::Translator::Producer::XML::SQLFairy>,
+L<SQL::Translator::Schema>.
 
 =head1 TODO
 
@@ -317,17 +355,13 @@ Test foreign keys are parsed ok.
 
 =item *
 
-Control over defaulting of non-existant tags.
+Control over defaulting.
 
 =back
 
 =head1 AUTHOR
 
-Mark D. Addison E<lt>mark.addison@itn.co.ukE<gt>.
-
-=head1 SEE ALSO
-
-perl(1), SQL::Translator, SQL::Translator::Producer::XML::SQLFairy,
-SQL::Translator::Schema.
+Mark D. Addison E<lt>mark.addison@itn.co.ukE<gt>,
+Jonathan Yu E<lt>frequency@cpan.orgE<gt>
 
 =cut