diff Lib/IMPL/DOM/Navigator/SchemaNavigator.pm @ 24:7f00786f8210

Первая рабочая реазизация схемы и навигаторов
author Sergey
date Mon, 05 Oct 2009 00:48:49 +0400
parents 818c74b038ae
children a8086f85a571
line wrap: on
line diff
--- a/Lib/IMPL/DOM/Navigator/SchemaNavigator.pm	Wed Sep 30 17:43:52 2009 +0400
+++ b/Lib/IMPL/DOM/Navigator/SchemaNavigator.pm	Mon Oct 05 00:48:49 2009 +0400
@@ -6,10 +6,15 @@
 use IMPL::Class::Property;
 use IMPL::Class::Property::Direct;
 
+require IMPL::DOM::Schema::ComplexType;
+require IMPL::DOM::Schema::NodeSet;
+require IMPL::DOM::Schema::AnyNode;
+
 __PACKAGE__->PassThroughArgs;
 
 BEGIN {
     public _direct property Schema => prop_get;
+    private _direct property _historySteps => prop_all;
 }
 
 sub CTOR {
@@ -20,19 +25,72 @@
     die new IMPL::InvalidArgumentException("A schema object is required") unless $schema->isa('IMPL::DOM::Schema');
 }
 
-sub Navigate {
-    my ($this,$query) = @_;
+my $schemaAnyNode = IMPL::DOM::Schema::ComplexType->new(type => '::AnyNodeType', nativeType => 'IMPL::DOM::ComplexNode')->appendRange(
+    IMPL::DOM::Schema::NodeSet->new()->appendRange(
+        IMPL::DOM::Schema::AnyNode->new()
+    )
+);
+
+sub NavigateName {
+    my ($this,$name) = @_;
     
-    if (my ($newNode) = $this->Current->selectNodes($query)) {
-        if (ref $newNode eq 'IMPL::DOM::Schema::Node') {
-            $newNode = $this->{$Schema}->ResolveType($newNode->type) || $newNode;
+    # perform a safe navigation
+    return dosafe $this sub {
+        my $steps = 1;
+        # navigate to node
+        if (
+            my $node = $this->Navigate( sub {
+                $_->isa('IMPL::DOM::Schema::Node') and (
+                    $_->name eq $name
+                    or
+                    $_->nodeName eq 'AnyNode'
+                    or
+                    ( $_->nodeName eq 'SwitchNode' and $_->selectNodes( sub { $_->name eq $name } ) )
+                )
+            })
+        ) {
+            if ($node->nodeName eq 'AnyNode') {
+                # if we navigate to the anynode
+                # assume it to be ComplexType by default
+                $node = $node->type ? $this->{$Schema}->resolveType($node->type) : $schemaAnyNode;
+            } elsif ($node->nodeName eq 'SwitchNode') {
+                # if we are in the switchnode
+                # navigate to the target node
+                $node = $this->Navigate(sub { $_->name eq $name });
+                $steps ++;
+            }
+            
+            if ($node->nodeName eq 'Node') {
+                # if we navigate to a reference
+                # resolve it
+                $node = $this->{$Schema}->resolveType($node->type);
+                $this->internalNavigateNodeSet($node);
+                $steps++;
+            } 
+            
+            # if target node is a complex node
+            if ($node->isa('IMPL::DOM::Schema::ComplexNode')) {
+                # navigate to it's content
+                $this->internalNavigateNodeSet($node->content);
+                $steps ++;
+            }
+            
+            push @{$this->{$_historySteps}},$steps;
+            
+            # return found node schema
+            return $node;
+        } else {
+            die; # abort navigation
         }
-        return $this->_NavigateNode($newNode);
-    } else {
-        return undef;
     }
 }
 
+sub SchemaBack {
+    my ($this) = @_;
+    
+    $this->Back(pop @{$this->{$_historySteps}}) if $this->{$_historySteps};
+}
+
 1;
 __END__
 
@@ -40,7 +98,23 @@
 
 =head1 DESCRIPTION
 
-  ,    ,      <Node nodeName="SomeName" type="ReferencedType"/>.
-             .
+        ,
+   .
+
+=head1 METHODS
+
+=over
+
+=item C<< $navi->NavigateName($name) >>
+
+      .    C<name>
+
+=item C<< $navi->SchemaBack >>
+
+      C<NavigateName>.   
+         
+     .
+
+=back
 
 =cut
\ No newline at end of file