view Lib/IMPL/DOM/Schema.pm @ 59:0f3e369553bd

Rewritten property implementation (probably become slower but more flexible) Configuration infrastructure in progress (in the aspect of the lazy activation) Initial concept for the code generator
author wizard
date Tue, 09 Mar 2010 02:50:45 +0300
parents 16ada169ca75
children 00d88c5e8203
line wrap: on
line source

package IMPL::DOM::Schema;
use strict;
use warnings;

require IMPL::DOM::Schema::ComplexNode;
require IMPL::DOM::Schema::ComplexType;
require IMPL::DOM::Schema::SimpleNode;
require IMPL::DOM::Schema::SimpleType;
require IMPL::DOM::Schema::Node;
require IMPL::DOM::Schema::AnyNode;
require IMPL::DOM::Schema::NodeList;
require IMPL::DOM::Schema::NodeSet;
require IMPL::DOM::Schema::Property;
require IMPL::DOM::Schema::SwitchNode;

use base qw(IMPL::DOM::Document);
use IMPL::Class::Property;
use IMPL::Class::Property::Direct;

our %CTOR = (
    'IMPL::DOM::Document' => sub { nodeName => 'schema' }
);

BEGIN {
    private _direct property _TypesMap => prop_all;
    public _direct property BaseSchemas => prop_get | owner_set;
    private _direct property _Validators => prop_all;
}

sub resolveType {
    $_[0]->{$_TypesMap}->{$_[1]};
}

sub Create {
    my ($this,$nodeName,$class,$refArgs) = @_;
    
    die new IMPL::Exception('Invalid node class') unless $class->isa('IMPL::DOM::Schema::Node');
    
    goto &SUPER::Create;
}

sub Process {
    my ($this) = @_;
    
    $this->{$_TypesMap} = { map { $_->type, $_ } $this->selectNodes(sub { $_[0]->nodeName eq 'ComplexType' || $_[0]->nodeName eq 'SimpleType' } ) };
}

sub Validate {
    my ($this,$node) = @_;
    
    if ( my ($schemaNode) = $this->selectNodes(sub { $_[0]->name eq $node->nodeName })) {
        $schemaNode->Validate($node);
    } else {
        return new IMPL::DOM::Schema::ValidationError(Message=> "A specified document doesn't match the schema");
    }
}

my $schema;

sub MetaSchema {
    
    return $schema if $schema;
    
    $schema = new IMPL::DOM::Schema;
    
    $schema->appendRange(
        IMPL::DOM::Schema::ComplexNode->new(name => 'schema')->appendRange(
            IMPL::DOM::Schema::NodeSet->new()->appendRange(
                IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type => 'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::Node->new(name => 'ComplexType', type => 'ComplexType', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type => 'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::Node->new(name => 'SimpleType', type => 'SimpleType', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::SimpleNode->new(name => 'Include', minOccur => 0, maxOccur=>'unbounded')->appendRange(
                    IMPL::DOM::Schema::Property->new(name => 'source')
                )
            ),
        ),
        IMPL::DOM::Schema::ComplexType->new(type => 'NodeSet', nativeType => 'IMPL::DOM::Schema::NodeSet')->appendRange(
            IMPL::DOM::Schema::NodeSet->new()->appendRange(
                IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type => 'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type => 'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::SwitchNode->new(minOccur => 0, maxOccur => 1)->appendRange(
                    IMPL::DOM::Schema::SimpleNode->new(name => 'AnyNode'),
                    IMPL::DOM::Schema::Node->new(name => 'SwitchNode',type => 'SwitchNode')
                )
            )
        ),
        IMPL::DOM::Schema::ComplexType->new(type => 'SwitchNode', nativeType => 'IMPL::DOM::Schema::SwitchNode')->appendRange(
            IMPL::DOM::Schema::NodeSet->new()->appendRange(
                IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type=>'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type=>'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
            )
        ),
        IMPL::DOM::Schema::ComplexType->new(type => 'NodeList', nativeType => 'IMPL::DOM::Schema::NodeList')->appendRange(
            IMPL::DOM::Schema::NodeSet->new()->appendRange(
                IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type => 'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type => 'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::Node->new(name => 'SwitchNode',type => 'SwitchNode', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
                IMPL::DOM::Schema::SimpleNode->new(name => 'AnyNode', minOccur => 0, maxOccur=>'unbounded'),
            )
        ),
        IMPL::DOM::Schema::ComplexType->new(type => 'ComplexType', nativeType => 'IMPL::DOM::Schema::ComplexType')->appendRange(
            IMPL::DOM::Schema::NodeList->new()->appendRange(
                IMPL::DOM::Schema::SwitchNode->new()->appendRange(
                    IMPL::DOM::Schema::Node->new(name => 'NodeSet', type => 'NodeSet'),
                    IMPL::DOM::Schema::Node->new(name => 'NodeList',type => 'NodeList'),
                ),
                IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
            ),
            new IMPL::DOM::Schema::Property(name => 'type')
        ),
        IMPL::DOM::Schema::ComplexType->new(type => 'ComplexNode', nativeType => 'IMPL::DOM::Schema::ComplexNode')->appendRange(
            IMPL::DOM::Schema::NodeList->new()->appendRange(
                IMPL::DOM::Schema::SwitchNode->new()->appendRange(
                    IMPL::DOM::Schema::Node->new(name => 'NodeSet', type => 'NodeSet'),
                    IMPL::DOM::Schema::Node->new(name => 'NodeList',type => 'NodeList'),
                ),
                IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
            ),
            new IMPL::DOM::Schema::Property(name => 'name')
        ),
        IMPL::DOM::Schema::ComplexType->new(type => 'SimpleType', nativeType => 'IMPL::DOM::Schema::SimpleType')->appendRange(
            IMPL::DOM::Schema::NodeSet->new()->appendRange(
                IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
            ),
            new IMPL::DOM::Schema::Property(name => 'type')
        ),
        IMPL::DOM::Schema::ComplexType->new(type => 'SimpleNode', nativeType => 'IMPL::DOM::Schema::SimpleNode')->appendRange(
            IMPL::DOM::Schema::NodeSet->new()->appendRange(
                IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
            ),
            new IMPL::DOM::Schema::Property(name => 'name')
        ),
        IMPL::DOM::Schema::ComplexType->new(type => 'Validator', nativeType => 'IMPL::DOM::Schema::Validator')->appendRange(
            IMPL::DOM::Schema::NodeList->new()->appendRange(
                IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0)
            ),
            new IMPL::DOM::Schema::Property(name => 'name')
        )
    );
    
    $schema->Process;
    
    return $schema;
}

1;

__END__

=pod

=head1 DESCRIPTION

Схема документа. Наследует C<IMPL::DOM::Document>

=head1 METHODS

=over

=item C<< $obj->Process() >>

Обновляет таблицу типов из содержимого.

=item C<< $obj->ResolveType($typeName) >>

Возвращает схему типа c именем C<$typeName>.

=back

=head1 DESCRIPTION

DOM схема - это документ, состоящий из определенных узлов, описывающая структуру
других документов.

=head1 META SCHEMA

Схема для описания схемы, эта схема используется для постороения других схем

<schema>
    <ComplexNode name="schema">
        <NodeSet>
            <Node minOcuur="0" maxOccur="unbounded" name="ComplexNode" type="ComplexNode"/>
            <Node minOcuur="0" maxOccur="unbounded" name="SimpleNode" type="SimpleNode"/>
            <Node minOcuur="0" maxOccur="unbounded" name="ComplexType" type="ComplexType"/>
            <Node minOcuur="0" maxOccur="unbounded" name="SimpleType" type="SimpleType"/>
            <SimpleNode minOcuur="0" maxOccur="unbounded" name="Node"/>
            <SimpleNode minOcuur="0" maxOccur="unbounded" name="Include"/>
        </NodeSet>
    </ComplexNode>
    
    <ComplexType type="NodeContainer">
        <NodeSet>
            <Node minOcuur="0" maxOccur="unbounded" name="ComplexNode" type="ComplexNode"/>
            <Node minOcuur="0" maxOccur="unbounded" name="SimpleNode" type="SimpleNode"/>
            <SimpleNode minOcuur="0" maxOccur="unbounded" name="Node"/>
        </NodeSet>
    </ComplexType>
    
    <ComplexType type="ComplexType">
        <NodeList>
            <Node name="NodeSet" type="NodeContainer" minOcuur=0/>
            <Node name="NodeList" type="NodeContainer" minOccur=0/>
            <AnyNode minOccur="0" maxOccur="unbounded"  type="Validator"/>
        </NodeList>
    </ComplexType>
    
    <ComplexType type="ComplexNode">
        <NodeList>
            <Node name="NodeSet" type="NodeContainer" minOcuur=0/>
            <Node name="NodeList" type="NodeContainer" minOccur=0/>
            <AnyNode minOccur="0" maxOccur="unbounded"  type="Validator"/>
        </NodeList>
    </ComplexType>
    
    <ComplexType type="SimpleNode">
        <NodeSet>
            <AnyNode minOccur=0 maxOccur="unbounded" type="Validator"/>
        </NodeSet>
    </ComplexType>
    
    <ComplexType type="SimpleType">
        <NodeSet>
            <AnyNode minOccur=0 maxOccur="unbounded" type="Validator"/>
        </NodeSet>
    </ComplexType>
    
    <ComplexType type="Validator">
        <NodeSet>
            <AnyNode minOccur=0 maxOccur="unbounded"/>
        </NodeSet>
    </ComplexType>
    
</schema>

=cut