view Lib/IMPL/DOM/Schema.pm @ 85:190c794a41ae

DateTime renamed because of collision
author wizard
date Fri, 16 Apr 2010 16:33:11 +0400
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