sub
parse {
my
(
$pkg
,
$data
) =
@_
;
my
$self
=
$pkg
->new();
my
$name
= _attr(
$data
,
'name'
);
_err(
'Found element without a name.'
)
unless
$name
;
$self
->name(
$name
);
my
$type_name
= _attr(
$data
,
'type'
);
if
(
$type_name
) {
$self
->{unresolved_type} = 1;
$self
->{type_name} =
$type_name
;
}
my
$min
= _attr(
$data
,
'minOccurs'
);
$min
= 1
unless
defined
$min
;
_err(
"Invalid value for minOccurs '$min' found in <$name>."
)
unless
$min
=~ /^\d+$/;
$self
->{min} =
$min
;
my
$max
= _attr(
$data
,
'maxOccurs'
);
$max
= 1
unless
defined
$max
;
_err(
"Invalid value for maxOccurs '$max' found in <$name>."
)
unless
$max
=~ /^\d+$/ or
$max
eq
'unbounded'
;
$self
->{max} =
$max
;
return
$self
;
}
sub
add_daughter {
my
(
$self
,
$d
) =
@_
;
if
(
$self
->{is_all} and
$d
->isa(
'XML::Validator::Schema::ElementNode'
)) {
_err(
"Element '$d->{name}' must have minOccurs of 0 or 1 because it is within an <all>."
)
unless
(
$d
->{min} eq
'0'
or
$d
->{min} eq
'1'
);
_err(
"Element '$d->{name}' must have maxOccurs of 0 or 1 because it is within an <all>."
)
unless
(
$d
->{max} eq
'0'
or
$d
->{max} eq
'1'
);
}
return
$self
->SUPER::add_daughter(
$d
);
}
sub
check_contents {
my
(
$self
,
$contents
) =
@_
;
if
(
$self
->{type}) {
my
(
$ok
,
$msg
);
if
(
$self
->{type} eq
'union'
) {
if
( not
defined
(
$self
->{members}) ){
die
"Internal error: I aint got no members\n"
;
}
else
{
if
(@{
$self
->{members}} == 0 ) {
_err(
"Element '$self->{name}' is a union with no members."
);
}
}
my
$types
=
''
;
$ok
= 0;
foreach
my
$m
( @{
$self
->{members}} ) {
if
( not
my
$x
=
ref
(
$m
) ) {
die
(
"Internal error, that isn't a reference\n"
);
}
(
$ok
,
$msg
) =
$m
->{type}->check(
$contents
);
last
if
$ok
;
$types
.=
' '
.
$m
->{type}->{base}->{name};
}
if
( not
$ok
) {
$msg
=
"content does not match any of the union base types"
.
" [ $types ]"
;
}
}
else
{
(
$ok
,
$msg
) =
$self
->{type}->check(
$contents
);
}
_err(
"Illegal value '$contents' in element <$self->{name}>, $msg"
)
unless
$ok
;
}
elsif
(
$self
->{is_complex} and
$contents
=~ /\S/) {
_err(
"Illegal character data found in element <$self->{name}>."
);
}
}
sub
check_daughter {
my
(
$self
,
$name
) =
@_
;
my
(
$daughter
) =
grep
{
$_
->{name} eq
$name
} (
$self
->daughters);
_err(
"Found unexpected <$name> inside <$self->{name}>. This is not a valid child element."
)
unless
$daughter
;
push
@{
$self
->{memory} ||= []},
$name
;
$self
->{model}->check_model(
$self
->{name},
$self
->{memory})
if
$self
->{model};
if
(
$daughter
->{unresolved_type}) {
$self
->root->complete_type(
$daughter
);
(
$daughter
) =
grep
{
$_
->{name} eq
$name
} (
$self
->daughters);
}
if
(
$daughter
->{unresolved_ref}) {
$self
->root->complete_ref(
$daughter
);
(
$daughter
) =
grep
{
$_
->{name} eq
$name
} (
$self
->daughters);
}
return
$daughter
;
}
sub
check_attributes {
my
(
$self
,
$data
) =
@_
;
my
(
@required
,
%allowed
);
foreach
my
$attr
(@{
$self
->{attr} || []}) {
$allowed
{
$attr
->{name}} =
$attr
;
push
(
@required
,
$attr
->{name})
if
$attr
->{required};
}
my
%saw
;
foreach
my
$jcname
(
keys
%$data
) {
my
$attr
=
$data
->{
$jcname
};
next
if
$attr
->{NamespaceURI}
my
$name
=
$attr
->{LocalName};
my
$obj
=
$allowed
{
$name
};
_err(
"Illegal attribute '$name' found in <$self->{name}>."
)
unless
$obj
;
$saw
{
$name
} = 1;
if
(
$obj
->{unresolved_type}) {
$self
->root->complete_attr_type(
$obj
);
}
if
(
$obj
->{type}) {
my
(
$ok
,
$msg
) =
$obj
->{type}->check(
$attr
->{Value});
_err(
"Illegal value '$attr->{Value}' for attribute '$name' in <$self->{name}>, $msg"
)
unless
$ok
;
}
}
foreach
my
$name
(
@required
) {
_err(
"Missing required attribute '$name' in <$self->{name}>."
)
unless
$saw
{
$name
};
}
}
sub
compile {
my
$self
=
shift
;
if
(
$self
->daughters and
(
$self
->daughters)[0]->isa(
'XML::Validator::Schema::ModelNode'
)) {
(
$self
->daughters)[0]->compile;
}
}
sub
clear_memory {
@{
$_
[0]->{memory}} = ()
if
$_
[0]->{memory};
}
1;