Mercurial > pub > Impl
view Lib/IMPL/DOM/Navigator/Builder.pm @ 103:c289ed9662ca
Schema beta 2
More strict validation, support for inflating a simple nodes and properties
author | wizard |
---|---|
date | Fri, 07 May 2010 18:17:40 +0400 |
parents | cf3b6ef2be22 |
children | 196bf443b5e1 |
line wrap: on
line source
package IMPL::DOM::Navigator::Builder; use strict; use warnings; use base qw(IMPL::Object); use IMPL::Class::Property; use IMPL::Class::Property::Direct; require IMPL::DOM::Navigator::SchemaNavigator; BEGIN { private _direct property _schemaNavi => prop_all; private _direct property _nodesPath => prop_all; private _direct property _nodeCurrent => prop_all; private _direct property _docClass => prop_all; public _direct property Document => prop_get | owner_set; } sub CTOR { my ($this,$docClass,$schema) = @_; $this->{$_docClass} = $docClass; $this->{$_schemaNavi} = $schema ? IMPL::DOM::Navigator::SchemaNavigator->new($schema) : undef; } sub NavigateCreate { my ($this,$nodeName,%props) = @_; if (my $schemaNode = $this->{$_schemaNavi}->NavigateName($nodeName)) { my $class = $schemaNode->can('nativeType') ? $schemaNode->nativeType : 'IMPL::DOM::Node'; $this->inflateProperties($schemaNode,\%props); my $node; if (! $this->{$Document}) { $node = $this->{$Document} = $this->{$_docClass}->new(nodeName => $nodeName,%props); } else { die new IMPL::InvalidOperationException('Can\t create a second top level element') unless $this->{$_nodeCurrent}; $node = $this->{$Document}->Create($nodeName,$class,\%props); push @{$this->{$_nodesPath}}, $this->{$_nodeCurrent}; $this->{$_nodeCurrent}->appendChild($node); } $this->{$_nodeCurrent} = $node; return $node; } else { die new IMPL::InvalidOperationException("The specified node is undefined", $nodeName); } } sub inflateProperties { my ($this,$schemaNode,$refProps) = @_; $refProps->{$_->name} = $_->inflator->new($refProps->{$_->name}) foreach $schemaNode->selectNodes( sub { $_->nodeName eq 'Property' and exists $refProps->{$_->name} and $_->inflator } ); } sub inflateValue { my ($this,$value) = @_; my $schemaNode = $this->{$_schemaNavi}->Current; if ($schemaNode->can('inflator') and my $inflator = $schemaNode->inflator) { return $inflator->new($value); } else { return $value; } } sub Back { my ($this) = @_; $this->{$_schemaNavi}->SchemaBack(); $this->{$_nodeCurrent} = pop @{$this->{$_nodesPath}}; } 1; __END__ =pod =head1 NAME C< IMPL::DOM::Navigator::Builder > - Навигатор, строящий документ по указанной схеме. =head1 SYNOPSIS =begin code my $builder = new IMPL::DOM::Navigator::Builder(new MyApp::Document,$schema); my $reader = new IMPL::DOM::XMLReader(Navigator => $builder); $reader->ParseFile("document.xml"); my @errors = $schema->Validate($builder->Document); =end code =head1 DESCRIPTION Построитель DOM документов по указанной схеме. Обычно используется в связке с объектами для чтения такими как C<IMPL::DOM::XMLReader>. =head1 METHODS =over =item C< CTOR($classDocument,$schema) > Создает новый объект, принимает на вход класс документа (или фабрику, например L<IMPL::Object::Factory>) и схему. В процессе процедуры построения документа будет создан объект документа. =item C< NavigateCreate($nodeName,\%props) > Создает новый узел с указанным именем и переходит в него. В случае если в схеме подходящий узел не найден, то вызывается исключение. При этом по имени узла ищется его схема, после чего определяется класс для создания экземпляра и созданный узел доавляется в документ. При создании нового узла используется метод документа C<< IMPL::DOM::Document->Create >> Свойства узла передаются при создании через параметр C<props>, но имя создаваемого узла НЕ может быть переопределено свойством C<nodeName>, оно будет проигнорировано. =item C< Document > Свойство, которое содержит документ по окончании процедурв построения. =back =cut