Mercurial > pub > Impl
view Lib/IMPL/DOM/Navigator/SchemaNavigator.pm @ 26:c529d386d80e
Text services in progress
author | Sergey |
---|---|
date | Thu, 15 Oct 2009 17:52:09 +0400 |
parents | 7f00786f8210 |
children | a8086f85a571 |
line wrap: on
line source
package IMPL::DOM::Navigator::SchemaNavigator; use strict; use warnings; use base qw(IMPL::DOM::Navigator); 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 { my ($this,$schema) = @_; $this->{$Schema} = $schema; die new IMPL::InvalidArgumentException("A schema object is required") unless $schema->isa('IMPL::DOM::Schema'); } 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) = @_; # 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 } } } sub SchemaBack { my ($this) = @_; $this->Back(pop @{$this->{$_historySteps}}) if $this->{$_historySteps}; } 1; __END__ =pod =head1 DESCRIPTION Помимо стандартных методов навигации позволяет переходить по элементам документа, который данной схемой описывается. =head1 METHODS =over =item C<< $navi->NavigateName($name) >> Переходит на схему узла с указанным именем. Тоесть использует свойство C<name> =item C<< $navi->SchemaBack >> Возвращается на позицию до последней операции C<NavigateName>. Данный метод нужен посокольку операция навигации по элементам описываемым схемой может приводить к нескольким операциям навигации по самой схеме. =back =cut