changeset 101:d8dc6cad3f55

Schema in progress
author wizard
date Thu, 06 May 2010 17:55:59 +0400
parents df6b4f054957
children cf3b6ef2be22
files Lib/IMPL/DOM/Schema.pm Lib/IMPL/DOM/Schema/Property.pm Lib/IMPL/DOM/Schema/Validator.pm _test/Resources/types.xml _test/Test/DOM/Schema.pm
diffstat 5 files changed, 82 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/Lib/IMPL/DOM/Schema.pm	Thu May 06 00:54:17 2010 +0400
+++ b/Lib/IMPL/DOM/Schema.pm	Thu May 06 17:55:59 2010 +0400
@@ -12,10 +12,14 @@
 require IMPL::DOM::Schema::NodeSet;
 require IMPL::DOM::Schema::Property;
 require IMPL::DOM::Schema::SwitchNode;
+require IMPL::DOM::Schema::Validator;
+require IMPL::DOM::Navigator::Builder;
+require IMPL::DOM::XMLReader;
 
 use base qw(IMPL::DOM::Document);
 use IMPL::Class::Property;
 use IMPL::Class::Property::Direct;
+use File::Spec;
 
 our %CTOR = (
     'IMPL::DOM::Document' => sub { nodeName => 'schema' }
@@ -23,6 +27,7 @@
 
 BEGIN {
     private _direct property _TypesMap => prop_all;
+    public _direct property baseDir => prop_all;
     public _direct property BaseSchemas => prop_get | owner_set;
     private _direct property _Validators => prop_all;
 }
@@ -36,15 +41,66 @@
     
     die new IMPL::Exception('Invalid node class') unless $class->isa('IMPL::DOM::Node');
     
-    goto &SUPER::Create;
+    if ($class->isa('IMPL::DOM::Schema::Validator')) {
+    	$class = "IMPL::DOM::Schema::Validator::$nodeName";
+    	local $@;
+    	unless (eval {$class->can('new')}) {
+    		eval "require $class; 1;";
+    		my $e = $@;
+			die new IMPL::Exception("Invalid validator",$class,$e) if $e;
+    	}
+    }
+    
+    return $this->SUPER::Create($nodeName,$class,$refArgs);
 }
 
 sub Process {
     my ($this) = @_;
     
+    # process instructions
+    $this->Include($_) foreach map $_->nodeProperty('source'), $this->selectNodes('Include');
+    
+    # build types map
     $this->{$_TypesMap} = { map { $_->type, $_ } $this->selectNodes(sub { $_[0]->nodeName eq 'ComplexType' || $_[0]->nodeName eq 'SimpleType' } ) };
 }
 
+sub Include {
+	my ($this,$file) = @_;
+	
+	my $schema = $this->LoadSchema($file);
+	
+	$this->appendRange( $schema->childNodes );
+}
+
+sub LoadSchema {
+	my ($this,$file,$base) = @_;
+	
+	my $class = ref $this || $this;
+	
+	my $reader = new IMPL::DOM::XMLReader(
+		Navigator => new IMPL::DOM::Navigator::Builder(
+			$class,
+			$class->MetaSchema
+		)
+	);
+		
+	$reader->ParseFile($file) or die new IMPL::Exception("Failed to load a schema",$file);
+	
+	my $schema = $reader->Navigator->Document;
+	
+	my ($vol,$dir) = File::Spec->splitpath($file);
+	
+	$schema->baseDir($dir);
+	
+	my @errors = $class->MetaSchema->Validate($schema);
+	
+	die new IMPL::Exception("Schema is invalid",$file,map( $_->Message, @errors ) ) if @errors;
+	
+	$schema->Process;
+	
+	return $schema;
+}
+
 sub Validate {
     my ($this,$node) = @_;
     
--- a/Lib/IMPL/DOM/Schema/Property.pm	Thu May 06 00:54:17 2010 +0400
+++ b/Lib/IMPL/DOM/Schema/Property.pm	Thu May 06 17:55:59 2010 +0400
@@ -36,7 +36,7 @@
     
     if ($this->minOccur) {
         my $prop = $this->name;
-        my $nodeProp = new IMPL::DOM::Node(nodeName => '::property', nodeValue => $node->$prop() || $node->nodePropety($prop));
+        my $nodeProp = new IMPL::DOM::Node(nodeName => '::property', nodeValue => eval { $node->$prop() } || $node->nodeProperty($prop));
         
         if (! $nodeProp->nodeValue) {
             return new IMPL::DOM::Schema::ValidationError(
--- a/Lib/IMPL/DOM/Schema/Validator.pm	Thu May 06 00:54:17 2010 +0400
+++ b/Lib/IMPL/DOM/Schema/Validator.pm	Thu May 06 17:55:59 2010 +0400
@@ -23,6 +23,7 @@
 C<IMPL::DOM::Schema::Validator> - Базовый класс для ограничений на простые значения.
 
 =head1 DESCRIPTION
+
 От основных элементов схемы его отличает то, что в конечном документе он не соответсвует
 никаким узлам и поэтому у него отсутствуют свойства C<minOcuur,maxOccur,name>.
 
--- a/_test/Resources/types.xml	Thu May 06 00:54:17 2010 +0400
+++ b/_test/Resources/types.xml	Thu May 06 17:55:59 2010 +0400
@@ -2,6 +2,9 @@
 	<SimpleType type="email" nativeType="SCALAR">
 		<RegExp message="Неверный формат %Node.name_no%">^\w+(\.\w+)*@$\w+(\.\w+)+</RegExp>
 	</SimpleType>
-	<SimpleType name="scalar" nativeType="SCALAR"/>
-	<SimpleType name="date" nativeType="DateTime"/>
+	<SimpleType type="scalar" nativeType="SCALAR"/>
+	<SimpleType type="date" nativeType="DateTime">
+		<Property name="timezone" optional="1"/>
+		<Property name="locale" optional="1"/>
+	</SimpleType>
 </schema>
\ No newline at end of file
--- a/_test/Test/DOM/Schema.pm	Thu May 06 00:54:17 2010 +0400
+++ b/_test/Test/DOM/Schema.pm	Thu May 06 17:55:59 2010 +0400
@@ -8,7 +8,8 @@
 
 __PACKAGE__->PassThroughArgs;
 
-require IMPL::DOM::Schema;
+use IMPL::DOM::Schema;
+use IMPL::DOM::Navigator::Builder;
 
 BEGIN {
     shared public property SampleSchema => prop_all;
@@ -100,5 +101,21 @@
     failed "A wrong data validated corretly" unless $this->SampleSchema->Validate($data);
 };
 
+test LoadXmlSchemaTypes => sub {
+	my ($this) = @_;
+	
+	my $schema = IMPL::DOM::Schema->LoadSchema("Resources/types.xml") or failed "Failed to parse schema";
+	
+	return 1;
+};
+
+test LoadXmlSchemaData => sub {
+	my ($this) = @_;
+	
+	my $schema = IMPL::DOM::Schema->LoadSchema("Resources/form.xml") or failed "Failed to parse schema";
+	
+	return 1;
+};
+
 
 1;