File Coverage

blib/lib/OTRS/OPM/Parser.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package OTRS::OPM::Parser;
2              
3             # ABSTRACT: Parser for the .opm file
4              
5             our $VERSION = 1.00;
6              
7 4     4   272780 use Moose;
  4         1771719  
  4         25  
8 4     4   26736 use Moose::Util::TypeConstraints;
  4         8  
  4         32  
9              
10 4     4   9290 use MIME::Base64 ();
  4         2236  
  4         104  
11 4     4   1140 use Path::Class;
  4         114535  
  4         217  
12 4     4   32 use Try::Tiny;
  4         9  
  4         192  
13 4     4   3866 use XML::LibXML;
  0            
  0            
14              
15             # define types
16             subtype 'VersionString' =>
17             as 'Str' =>
18             where { $_ =~ m{ \A (?:[0-9]+) (?:\.[0-9]+){0,2} (?:_\d+)? \z }xms };
19              
20             subtype 'FrameworkVersionString' =>
21             as 'Str' =>
22             where { $_ =~ m{ \A (?: (?:x|[0-9]+x?) \. ){1,2} (?: x | [0-9]+x? ) \z }xms };
23              
24             subtype 'XMLTree' =>
25             as 'Object' =>
26             where { $_->isa( 'XML::LibXML::Document' ) };
27              
28             # declare attributes
29             has name => ( is => 'rw', isa => 'Str', );
30             has version => ( is => 'rw', isa => 'VersionString', );
31             has vendor => ( is => 'rw', isa => 'Str', );
32             has url => ( is => 'rw', isa => 'Str', );
33             has license => ( is => 'rw', isa => 'Str', );
34             has description => ( is => 'rw', isa => 'Str', );
35             has error_string => ( is => 'rw', isa => 'Str', );
36              
37             has tree => (
38             is => 'rw',
39             isa => 'XMLTree',
40             );
41              
42             has opm_file => (
43             is => 'ro',
44             isa => 'Str',
45             required => 1,
46             );
47              
48             has files => (
49             traits => ['Array'],
50             is => 'rw',
51             isa => 'ArrayRef[HashRef]',
52             auto_deref => 1,
53             default => sub{ [] },
54             handles => {
55             add_file => 'push',
56             },
57             );
58              
59             has framework => (
60             traits => ['Array'],
61             is => 'rw',
62             isa => 'ArrayRef[FrameworkVersionString]',
63             auto_deref => 1,
64             default => sub { [] },
65             handles => {
66             add_framework => 'push',
67             },
68             );
69              
70             has framework_details => (
71             traits => ['Array'],
72             is => 'rw',
73             isa => 'ArrayRef[HashRef]',
74             auto_deref => 1,
75             default => sub { [] },
76             handles => {
77             add_framework_detail => 'push',
78             },
79             );
80              
81             has dependencies => (
82             traits => ['Array'],
83             is => 'rw',
84             isa => 'ArrayRef[HashRef[Str]]',
85             auto_deref => 1,
86             default => sub { [] },
87             handles => {
88             add_dependency => 'push',
89             },
90             );
91              
92              
93             sub documentation {
94             my ($self,%params) = @_;
95            
96             my $doc_file;
97             my $found_file;
98            
99             for my $file ( $self->files ) {
100             my $filename = $file->{filename};
101             next if $filename !~ m{ \A doc/ }x;
102            
103             if ( !$doc_file ) {
104             $doc_file = $file;
105             $found_file = $filename;
106             }
107            
108             my $lang = $params{lang} || '';
109             next if $lang && $filename !~ m{ \A doc/$lang/ }x;
110            
111             if ( $lang && $found_file !~ m{ \A doc/$lang/ }x ) {
112             $doc_file = $file;
113             $found_file = $filename;
114             }
115            
116             my $type = $params{type} || '';
117             next if $type && $filename !~ m{ \A doc/[^/]+/.*\.$type \z }x;
118            
119             if ( $type && $found_file !~ m{ \A doc/$lang/ }x ) {
120             $doc_file = $file;
121             $found_file = $filename;
122            
123             if ( !$lang || ( $lang && $found_file !~ m{ \A doc/$lang/ }x ) ) {
124             last;
125             }
126             }
127             }
128            
129             return $doc_file;
130             }
131              
132             sub parse {
133             my ($self) = @_;
134              
135             $self->error_string( '' );
136            
137             if ( !-e $self->opm_file ) {
138             $self->error_string( 'File does not exist' );
139             return;
140             }
141            
142             my $tree;
143             try {
144             my $parser = XML::LibXML->new;
145             $tree = $parser->parse_file( $self->opm_file );
146              
147             $self->tree( $tree );
148             }
149             catch {
150             $self->error_string( 'Could not parse .opm: ' . $_ );
151             return;
152             };
153              
154             return if $self->error_string;
155            
156             # check if the opm file is valid.
157             try {
158             my $xsd = do{ local $/; <DATA> };
159             XML::LibXML::Schema->new( string => $xsd )
160             }
161             catch {
162             $self->error_string( 'Could not validate against XML schema: ' . $_ );
163             #return;
164             };
165            
166             my $root = $tree->getDocumentElement;
167            
168             # collect basic data
169             $self->vendor( $root->findvalue( 'Vendor' ) );
170             $self->name( $root->findvalue( 'Name' ) );
171             $self->license( $root->findvalue( 'License' ) );
172             $self->version( $root->findvalue( 'Version' ) );
173             $self->url( $root->findvalue( 'URL' ) );
174            
175             # retrieve framework information
176             my @frameworks = $root->findnodes( 'Framework' );
177            
178             FILE:
179             for my $framework ( @frameworks ) {
180             my $framework_version = $framework->textContent;
181            
182             my %details = ( Content => $framework_version );
183             my $maximum = $framework->findvalue( '@Maximum' );
184             my $minimum = $framework->findvalue( '@Minimum' );
185              
186             $details{Maximum} = $maximum if $maximum;
187             $details{Minimum} = $minimum if $minimum;
188            
189             # push framework info to attribute
190             $self->add_framework( $framework_version );
191             $self->add_framework_detail( \%details );
192             }
193              
194             # retrieve file information
195             my @files = $root->findnodes( 'Filelist/File' );
196            
197             FILE:
198             for my $file ( @files ) {
199             my $name = $file->findvalue( '@Location' );
200            
201             #next FILE if $name !~ m{ \. (?:pl|pm|pod|t) \z }xms;
202             my $encode = $file->findvalue( '@Encode' );
203             next FILE if $encode ne 'Base64';
204            
205             my $content_base64 = $file->textContent;
206             my $content = MIME::Base64::decode( $content_base64 );
207            
208             # push file info to attribute
209             $self->add_file({
210             filename => $name,
211             content => $content,
212             });
213             }
214            
215             # get description - english if available, any other language otherwise
216             my @descriptions = $root->findnodes( 'Description' );
217             my $description_string;
218            
219             DESCRIPTION:
220             for my $description ( @descriptions ) {
221             $description_string = $description->textContent;
222             my $language = $description->findvalue( '@Lang' );
223            
224             last DESCRIPTION if $language eq 'en';
225             }
226            
227             $self->description( $description_string );
228            
229             # get OTRS and CPAN dependencies
230             my @otrs_deps = $root->findnodes( 'PackageRequired' );
231             my @cpan_deps = $root->findnodes( 'ModuleRequired' );
232            
233             my %types = (
234             PackageRequired => 'OTRS',
235             ModuleRequired => 'CPAN',
236             );
237            
238             for my $dep ( @otrs_deps, @cpan_deps ) {
239             my $node_type = $dep->nodeName;
240             my $version = $dep->findvalue( '@Version' );
241             my $dep_name = $dep->textContent;
242             my $dep_type = $types{$node_type};
243            
244             $self->add_dependency({
245             type => $dep_type,
246             version => $version,
247             name => $dep_name,
248             });
249             }
250            
251             return 1;
252             }
253              
254             sub as_sopm {
255             my ($self) = @_;
256              
257             my $tree = $self->tree->cloneNode(1);
258             my $root = $tree->getDocumentElement;
259            
260             my @build_host = $root->findnodes( 'BuildHost' );
261             my @build_date = $root->findnodes( 'BuildDate' );
262            
263             $root->removeChild( $_ ) for @build_host;
264             $root->removeChild( $_ ) for @build_date;
265              
266             #$build_host->unbindNode() if $build_host;
267             #$build_date->unbindNode() if $build_date;
268            
269             my @files = $root->findnodes( 'Filelist/File' );
270             for my $file ( @files ) {
271             my ($encode) = $file->findnodes( '@Encode' );
272             $encode->unbindNode() if $encode;
273            
274             $file->removeChildNodes();
275             }
276            
277             return $tree->toString;
278             }
279              
280             no Moose;
281              
282             1;
283              
284             =pod
285              
286             =encoding UTF-8
287              
288             =head1 NAME
289              
290             OTRS::OPM::Parser - Parser for the .opm file
291              
292             =head1 VERSION
293              
294             version 0.01
295              
296             =head1 SYNOPSIS
297              
298             use OTRS::OPM::Parser;
299            
300             my $opm_file = 'QuickMerge-3.3.2.opm';
301             my $opm = OTRS::OPM::Parser->new( opm_file => $opm_file );
302            
303             say sprintf "This is version %s of package %s",
304             $opm->version,
305             $opm->name;
306            
307             say "You can install it on those OTRS versions: ", join ", ", $opm->framework;
308            
309             say "Dependencies: ";
310             for my $dep ( $opm->dependencies ) {
311             say sprintf "%s (%s) - (%s)",
312             $dep->{name},
313             $dep->{version},
314             $dep->{type};
315             }
316              
317             =head1 METHODS
318              
319             =head2 new
320              
321             =head2 parse
322              
323             =head2 as_sopm
324              
325             =head2 documentation
326              
327             =head1 ATTRIBUTES
328              
329             =over 4
330              
331             =item * opm_file
332              
333             =item * tree
334              
335             =item * framework
336              
337             =item * dependencies
338              
339             =item * files
340              
341             =item * error_string
342              
343             =item * description
344              
345             =item * license
346              
347             =item * url
348              
349             =item * vendor
350              
351             =item * version
352              
353             =item * name
354              
355             =back
356              
357             =head1 AUTHOR
358              
359             Renee Baecker <reneeb@cpan.org>
360              
361             =head1 COPYRIGHT AND LICENSE
362              
363             This software is Copyright (c) 2016 by Renee Baecker.
364              
365             This is free software, licensed under:
366              
367             The Artistic License 2.0 (GPL Compatible)
368              
369             =cut
370              
371             __DATA__
372             <?xml version="1.0" encoding="UTF-8" standalone="no"?>
373             <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
374             <xs:import namespace="http://www.w3.org/XML/1998/namespace"/>
375            
376             <xs:element name="otrs_package">
377             <xs:complexType>
378             <xs:sequence>
379             <xs:element ref="Name" minOccurs="1" maxOccurs="1"/>
380             <xs:element ref="Version"/>
381             <xs:element ref="Vendor"/>
382             <xs:element ref="URL"/>
383             <xs:element ref="License"/>
384             <xs:element ref="ChangeLog" minOccurs="0" maxOccurs="unbounded" />
385             <xs:element ref="Description" maxOccurs="unbounded" />
386             <xs:element ref="Framework" maxOccurs="unbounded" />
387             <xs:element ref="OS" minOccurs="0" maxOccurs="unbounded" />
388             <xs:element ref="IntroInstall" minOccurs="0" maxOccurs="unbounded" />
389             <xs:element ref="IntroUninstall" minOccurs="0" maxOccurs="unbounded" />
390             <xs:element ref="IntroReinstall" minOccurs="0" maxOccurs="unbounded" />
391             <xs:element ref="IntroUpgrade" minOccurs="0" maxOccurs="unbounded" />
392             <xs:element ref="PackageRequired" minOccurs="0" maxOccurs="unbounded" />
393             <xs:element ref="ModuleRequired" minOccurs="0" maxOccurs="unbounded" />
394             <xs:element ref="CodeInstall" minOccurs="0" maxOccurs="unbounded" />
395             <xs:element ref="CodeUpgrade" minOccurs="0" maxOccurs="unbounded" />
396             <xs:element ref="CodeUninstall" minOccurs="0" maxOccurs="unbounded" />
397             <xs:element ref="CodeReinstall" minOccurs="0" maxOccurs="unbounded" />
398             <xs:element ref="BuildDate" minOccurs="0" />
399             <xs:element ref="BuildHost" minOccurs="0" />
400             <xs:element ref="Filelist"/>
401             <xs:element ref="DatabaseInstall" minOccurs="0" maxOccurs="unbounded" />
402             <xs:element ref="DatabaseUpgrade" minOccurs="0" maxOccurs="unbounded" />
403             <xs:element ref="DatabaseReinstall" minOccurs="0" maxOccurs="unbounded" />
404             <xs:element ref="DatabaseUninstall" minOccurs="0" maxOccurs="unbounded" />
405             </xs:sequence>
406             <xs:attribute name="version" use="required" type="xs:anySimpleType"/>
407             </xs:complexType>
408             </xs:element>
409            
410             <xs:element name="ChangeLog">
411             <xs:complexType>
412             <xs:simpleContent>
413             <xs:extension base="xs:string">
414             <xs:attribute name="Date" use="required" type="xs:anySimpleType"/>
415             <xs:attribute name="Version" use="required" type="xs:anySimpleType"/>
416             </xs:extension>
417             </xs:simpleContent>
418             </xs:complexType>
419             </xs:element>
420            
421             <xs:element name="Description">
422             <xs:complexType>
423             <xs:simpleContent>
424             <xs:extension base="xs:string">
425             <xs:attribute name="Lang" use="optional" type="xs:anySimpleType"/>
426             <xs:attribute name="Format" use="optional" type="xs:anySimpleType"/>
427             <xs:attribute name="Translatable" use="optional" type="xs:anySimpleType"/>
428             </xs:extension>
429             </xs:simpleContent>
430             </xs:complexType>
431             </xs:element>
432            
433             <xs:element name="Framework">
434             <xs:complexType>
435             <xs:simpleContent>
436             <xs:extension base="xs:string">
437             <xs:attribute name="Minimum" use="optional" type="xs:anySimpleType"/>
438             </xs:extension>
439             </xs:simpleContent>
440             </xs:complexType>
441             </xs:element>
442              
443             <xs:element name="Filelist">
444             <xs:complexType>
445             <xs:sequence>
446             <xs:element ref="File" maxOccurs="unbounded" />
447             </xs:sequence>
448             </xs:complexType>
449             </xs:element>
450            
451             <xs:element name="File">
452             <xs:complexType>
453             <xs:simpleContent>
454             <xs:extension base="xs:string">
455             <xs:attribute name="Location" use="required" type="xs:anySimpleType"/>
456             <xs:attribute name="Permission" use="required" type="xs:anySimpleType"/>
457             <xs:attribute name="Encode" use="required" type="xs:anySimpleType"/>
458             </xs:extension>
459             </xs:simpleContent>
460             </xs:complexType>
461             </xs:element>
462            
463             <xs:element name="PackageRequired">
464             <xs:complexType>
465             <xs:simpleContent>
466             <xs:extension base="xs:string">
467             <xs:attribute name="Version" use="required" type="xs:anySimpleType"/>
468             </xs:extension>
469             </xs:simpleContent>
470             </xs:complexType>
471             </xs:element>
472            
473             <xs:element name="ModuleRequired">
474             <xs:complexType>
475             <xs:simpleContent>
476             <xs:extension base="xs:string">
477             <xs:attribute name="Version" use="required" type="xs:anySimpleType"/>
478             </xs:extension>
479             </xs:simpleContent>
480             </xs:complexType>
481             </xs:element>
482            
483             <xs:element name="IntroInstall">
484             <xs:complexType>
485             <xs:simpleContent>
486             <xs:extension base="xs:string">
487             <xs:attribute name="Type" use="required" type="xs:anySimpleType"/>
488             <xs:attribute name="Lang" use="optional" type="xs:anySimpleType"/>
489             <xs:attribute name="Title" use="optional" type="xs:anySimpleType"/>
490             <xs:attribute name="Translatable" use="optional" type="xs:anySimpleType"/>
491             <xs:attribute name="Format" use="optional" type="xs:anySimpleType"/>
492             </xs:extension>
493             </xs:simpleContent>
494             </xs:complexType>
495             </xs:element>
496             <xs:element name="IntroUninstall">
497             <xs:complexType>
498             <xs:simpleContent>
499             <xs:extension base="xs:string">
500             <xs:attribute name="Type" use="required" type="xs:anySimpleType"/>
501             <xs:attribute name="Lang" use="optional" type="xs:anySimpleType"/>
502             <xs:attribute name="Title" use="optional" type="xs:anySimpleType"/>
503             <xs:attribute name="Translatable" use="optional" type="xs:anySimpleType"/>
504             <xs:attribute name="Format" use="optional" type="xs:anySimpleType"/>
505             </xs:extension>
506             </xs:simpleContent>
507             </xs:complexType>
508             </xs:element>
509             <xs:element name="IntroReinstall">
510             <xs:complexType>
511             <xs:simpleContent>
512             <xs:extension base="xs:string">
513             <xs:attribute name="Type" use="required" type="xs:anySimpleType"/>
514             <xs:attribute name="Lang" use="optional" type="xs:anySimpleType"/>
515             <xs:attribute name="Title" use="optional" type="xs:anySimpleType"/>
516             <xs:attribute name="Translatable" use="optional" type="xs:anySimpleType"/>
517             <xs:attribute name="Format" use="optional" type="xs:anySimpleType"/>
518             </xs:extension>
519             </xs:simpleContent>
520             </xs:complexType>
521             </xs:element>
522             <xs:element name="IntroUpgrade">
523             <xs:complexType>
524             <xs:simpleContent>
525             <xs:extension base="xs:string">
526             <xs:attribute name="Type" use="required" type="xs:anySimpleType"/>
527             <xs:attribute name="Lang" use="optional" type="xs:anySimpleType"/>
528             <xs:attribute name="Title" use="optional" type="xs:anySimpleType"/>
529             <xs:attribute name="Translatable" use="optional" type="xs:anySimpleType"/>
530             <xs:attribute name="Version" use="optional" type="xs:anySimpleType"/>
531             <xs:attribute name="Format" use="optional" type="xs:anySimpleType"/>
532             </xs:extension>
533             </xs:simpleContent>
534             </xs:complexType>
535             </xs:element>
536            
537             <xs:element name="CodeInstall">
538             <xs:complexType>
539             <xs:simpleContent>
540             <xs:extension base="xs:string">
541             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
542             </xs:extension>
543             </xs:simpleContent>
544             </xs:complexType>
545             </xs:element>
546             <xs:element name="CodeUninstall">
547             <xs:complexType>
548             <xs:simpleContent>
549             <xs:extension base="xs:string">
550             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
551             </xs:extension>
552             </xs:simpleContent>
553             </xs:complexType>
554             </xs:element>
555             <xs:element name="CodeReinstall">
556             <xs:complexType>
557             <xs:simpleContent>
558             <xs:extension base="xs:string">
559             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
560             </xs:extension>
561             </xs:simpleContent>
562             </xs:complexType>
563             </xs:element>
564             <xs:element name="CodeUpgrade">
565             <xs:complexType>
566             <xs:simpleContent>
567             <xs:extension base="xs:string">
568             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
569             <xs:attribute name="Version" use="optional" type="xs:anySimpleType"/>
570             </xs:extension>
571             </xs:simpleContent>
572             </xs:complexType>
573             </xs:element>
574            
575             <xs:element name="Name" type="xs:token"/>
576             <xs:element name="Vendor" type="xs:token"/>
577             <xs:element name="URL" type="xs:token"/>
578             <xs:element name="Version" type="xs:token"/>
579             <xs:element name="License" type="xs:token"/>
580             <xs:element name="OS" type="xs:token"/>
581             <xs:element name="BuildDate" type="xs:token"/>
582             <xs:element name="BuildHost" type="xs:token"/>
583            
584            
585             <!-- -->
586             <!-- Database stuff -->
587             <!-- -->
588            
589             <xs:element name="DatabaseInstall">
590             <xs:complexType>
591             <xs:choice maxOccurs="unbounded">
592             <xs:element ref="TableCreate" minOccurs="0" maxOccurs="unbounded" />
593             <xs:element ref="TableAlter" minOccurs="0" maxOccurs="unbounded" />
594             <xs:element ref="Insert" minOccurs="0" maxOccurs="unbounded" />
595             </xs:choice>
596             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
597             </xs:complexType>
598             </xs:element>
599             <xs:element name="DatabaseUninstall">
600             <xs:complexType>
601             <xs:choice maxOccurs="unbounded">
602             <xs:element ref="TableDrop" minOccurs="0" maxOccurs="unbounded" />
603             <xs:element ref="TableAlter" minOccurs="0" maxOccurs="unbounded" />
604             </xs:choice>
605             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
606             </xs:complexType>
607             </xs:element>
608             <xs:element name="DatabaseReinstall">
609             <xs:complexType>
610             <xs:simpleContent>
611             <xs:extension base="xs:string">
612             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
613             </xs:extension>
614             </xs:simpleContent>
615             </xs:complexType>
616             </xs:element>
617             <xs:element name="DatabaseUpgrade">
618             <xs:complexType>
619             <xs:choice maxOccurs="unbounded">
620             <xs:element ref="TableCreate" minOccurs="0" maxOccurs="unbounded" />
621             <xs:element ref="TableAlter" minOccurs="0" maxOccurs="unbounded" />
622             <xs:element ref="Insert" minOccurs="0" maxOccurs="unbounded" />
623             </xs:choice>
624             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
625             <xs:attribute name="Version" use="optional" type="xs:anySimpleType"/>
626             </xs:complexType>
627             </xs:element>
628            
629             <xs:element name="TableCreate">
630             <xs:complexType>
631             <xs:choice maxOccurs="unbounded">
632             <xs:element ref="Column" maxOccurs="unbounded" />
633             <xs:element ref="ForeignKey" minOccurs="0" maxOccurs="unbounded" />
634             <xs:element ref="Index" minOccurs="0" maxOccurs="unbounded" />
635             <xs:element ref="Unique" minOccurs="0" maxOccurs="unbounded" />
636             </xs:choice>
637             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
638             <xs:attribute name="Name" use="optional" type="xs:anySimpleType"/>
639             <xs:attribute name="Version" use="optional" type="xs:anySimpleType"/>
640             </xs:complexType>
641             </xs:element>
642            
643             <xs:element name="TableAlter">
644             <xs:complexType>
645             <xs:choice maxOccurs="unbounded">
646             <xs:element ref="ColumnAdd" minOccurs="0" maxOccurs="unbounded" />
647             <xs:element ref="ColumnChange" minOccurs="0" maxOccurs="unbounded" />
648             <xs:element ref="ColumnDrop" minOccurs="0" maxOccurs="unbounded" />
649             <xs:element ref="ForeignKeyCreate" minOccurs="0" maxOccurs="unbounded" />
650             <xs:element ref="ForeignKeyDrop" minOccurs="0" maxOccurs="unbounded" />
651             <xs:element ref="IndexCreate" minOccurs="0" maxOccurs="unbounded" />
652             <xs:element ref="IndexDrop" minOccurs="0" maxOccurs="unbounded" />
653             <xs:element ref="UniqueCreate" minOccurs="0" maxOccurs="unbounded" />
654             <xs:element ref="UniqueDrop" minOccurs="0" maxOccurs="unbounded" />
655             </xs:choice>
656             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
657             <xs:attribute name="Name" use="optional" type="xs:anySimpleType"/>
658             <xs:attribute name="Version" use="optional" type="xs:anySimpleType"/>
659             </xs:complexType>
660             </xs:element>
661            
662             <xs:element name="TableDrop">
663             <xs:complexType>
664             <xs:simpleContent>
665             <xs:extension base="xs:string">
666             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
667             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
668             </xs:extension>
669             </xs:simpleContent>
670             </xs:complexType>
671             </xs:element>
672            
673             <!-- Columns -->
674            
675             <xs:element name="Column">
676             <xs:complexType>
677             <xs:simpleContent>
678             <xs:extension base="xs:string">
679             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
680             <xs:attribute name="AutoIncrement" use="optional" type="xs:anySimpleType"/>
681             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
682             <xs:attribute name="Required" use="optional" type="xs:anySimpleType"/>
683             <xs:attribute name="Size" use="optional" type="xs:anySimpleType"/>
684             <xs:attribute name="PrimaryKey" use="optional" type="xs:anySimpleType"/>
685             <xs:attribute name="Default" use="optional" type="xs:anySimpleType"/>
686             </xs:extension>
687             </xs:simpleContent>
688             </xs:complexType>
689             </xs:element>
690             <xs:element name="ColumnAdd">
691             <xs:complexType>
692             <xs:simpleContent>
693             <xs:extension base="xs:string">
694             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
695             <xs:attribute name="AutoIncrement" use="optional" type="xs:anySimpleType"/>
696             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
697             <xs:attribute name="Required" use="optional" type="xs:anySimpleType"/>
698             <xs:attribute name="Size" use="optional" type="xs:anySimpleType"/>
699             <xs:attribute name="PrimaryKey" use="optional" type="xs:anySimpleType"/>
700             <xs:attribute name="Default" use="optional" type="xs:anySimpleType"/>
701             </xs:extension>
702             </xs:simpleContent>
703             </xs:complexType>
704             </xs:element>
705             <xs:element name="ColumnChange">
706             <xs:complexType>
707             <xs:simpleContent>
708             <xs:extension base="xs:string">
709             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
710             <xs:attribute name="Default" use="optional" type="xs:anySimpleType"/>
711             <xs:attribute name="NameOld" use="optional" type="xs:anySimpleType"/>
712             <xs:attribute name="NameNew" use="optional" type="xs:anySimpleType"/>
713             <xs:attribute name="AutoIncrement" use="optional" type="xs:anySimpleType"/>
714             <xs:attribute name="Required" use="optional" type="xs:anySimpleType"/>
715             <xs:attribute name="Size" use="optional" type="xs:anySimpleType"/>
716             <xs:attribute name="PrimaryKey" use="optional" type="xs:anySimpleType"/>
717             </xs:extension>
718             </xs:simpleContent>
719             </xs:complexType>
720             </xs:element>
721             <xs:element name="ColumnDrop">
722             <xs:complexType>
723             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
724             </xs:complexType>
725             </xs:element>
726            
727             <!-- Foreign Keys -->
728            
729             <xs:element name="ForeignKey">
730             <xs:complexType>
731             <xs:sequence>
732             <xs:element ref="Reference" maxOccurs="unbounded" />
733             </xs:sequence>
734             <xs:attribute name="ForeignTable" use="required" type="xs:anySimpleType"/>
735             </xs:complexType>
736             </xs:element>
737            
738             <xs:element name="ForeignKeyCreate">
739             <xs:complexType>
740             <xs:sequence>
741             <xs:element ref="Reference" maxOccurs="unbounded" />
742             </xs:sequence>
743             <xs:attribute name="ForeignTable" use="required" type="xs:anySimpleType"/>
744             </xs:complexType>
745             </xs:element>
746            
747             <xs:element name="ForeignKeyDrop">
748             <xs:complexType>
749             <xs:sequence>
750             <xs:element ref="Reference" maxOccurs="unbounded" />
751             </xs:sequence>
752             <xs:attribute name="ForeignTable" use="required" type="xs:anySimpleType"/>
753             </xs:complexType>
754             </xs:element>
755            
756             <xs:element name="Reference">
757             <xs:complexType>
758             <xs:simpleContent>
759             <xs:extension base="xs:string">
760             <xs:attribute name="Local" use="required" type="xs:anySimpleType"/>
761             <xs:attribute name="Foreign" use="required" type="xs:anySimpleType"/>
762             </xs:extension>
763             </xs:simpleContent>
764             </xs:complexType>
765             </xs:element>
766            
767             <!-- Unique columns -->
768            
769             <xs:element name="Unique">
770             <xs:complexType>
771             <xs:sequence>
772             <xs:element ref="UniqueColumn" maxOccurs="unbounded" />
773             </xs:sequence>
774             <xs:attribute name="Name" use="optional" type="xs:anySimpleType"/>
775             </xs:complexType>
776             </xs:element>
777            
778             <xs:element name="UniqueColumn">
779             <xs:complexType>
780             <xs:simpleContent>
781             <xs:extension base="xs:string">
782             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
783             </xs:extension>
784             </xs:simpleContent>
785             </xs:complexType>
786             </xs:element>
787            
788             <xs:element name="UniqueCreate">
789             <xs:complexType>
790             <xs:simpleContent>
791             <xs:extension base="xs:string">
792             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
793             </xs:extension>
794             </xs:simpleContent>
795             </xs:complexType>
796             </xs:element>
797            
798             <xs:element name="UniqueDrop">
799             <xs:complexType>
800             <xs:simpleContent>
801             <xs:extension base="xs:string">
802             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
803             </xs:extension>
804             </xs:simpleContent>
805             </xs:complexType>
806             </xs:element>
807            
808             <!-- Index columns -->
809            
810             <xs:element name="Index">
811             <xs:complexType>
812             <xs:sequence>
813             <xs:element ref="IndexColumn" maxOccurs="unbounded" />
814             </xs:sequence>
815             <xs:attribute name="Name" use="optional" type="xs:anySimpleType"/>
816             </xs:complexType>
817             </xs:element>
818            
819             <xs:element name="IndexColumn">
820             <xs:complexType>
821             <xs:simpleContent>
822             <xs:extension base="xs:string">
823             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
824             </xs:extension>
825             </xs:simpleContent>
826             </xs:complexType>
827             </xs:element>
828            
829             <xs:element name="IndexCreate">
830             <xs:complexType>
831             <xs:simpleContent>
832             <xs:extension base="xs:string">
833             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
834             </xs:extension>
835             </xs:simpleContent>
836             </xs:complexType>
837             </xs:element>
838            
839             <xs:element name="IndexDrop">
840             <xs:complexType>
841             <xs:simpleContent>
842             <xs:extension base="xs:string">
843             <xs:attribute name="Name" use="required" type="xs:anySimpleType"/>
844             </xs:extension>
845             </xs:simpleContent>
846             </xs:complexType>
847             </xs:element>
848            
849             <!-- Insert stuff into database -->
850            
851             <xs:element name="Insert">
852             <xs:complexType>
853             <xs:sequence>
854             <xs:element ref="Data" maxOccurs="unbounded" />
855             </xs:sequence>
856             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
857             <xs:attribute name="Table" use="required" type="xs:anySimpleType"/>
858             <xs:attribute name="Version" use="optional" type="xs:anySimpleType"/>
859             </xs:complexType>
860             </xs:element>
861            
862             <xs:element name="Data">
863             <xs:complexType>
864             <xs:simpleContent>
865             <xs:extension base="xs:string">
866             <xs:attribute name="Key" use="optional" type="xs:anySimpleType"/>
867             <xs:attribute name="Type" use="optional" type="xs:anySimpleType"/>
868             </xs:extension>
869             </xs:simpleContent>
870             </xs:complexType>
871             </xs:element>
872            
873             </xs:schema>