use vars
qw(@ISA $VERSION @TYPES %TYPES);
# although DTD declarations are not elements, we use the same API so we can
# manipulate the internal DTD subset using the same methods available for
# elements. At this state, all extensions are the same object class, but
# may be subclassed in the future to e.g. SVG::Extension::ELEMENT. Use
# e.g. isElementDecl() to determine types; this API will be retained
# DTD declarations handled in this module
use constant ELEMENT
=> "ELEMENT";
use constant ATTLIST
=> "ATTLIST";
use constant NOTATION
=> "NOTATION";
use constant ENTITY
=> "ENTITY";
@TYPES=(ELEMENT
,ATTLIST
,NOTATION
,ENTITY
);
%TYPES=map { $_ => 1 } @TYPES;
return shift->SUPER::new
(@_);
my $document=$self->{-docref
};
unless (exists $document->{-internal
}) {
$document->{-internal
}=new SVG
::Extension
("internal");
$document->{-internal
}{-docref
}=$document;
return $document->{-internal
};
my $class=ref($self) || $self;
return bless $self->SUPER::element
(@_),$class;
my $subset=$self->internal_subset();
return $subset->extension('ELEMENT',%attrs);
my ($element_decl,%attrs)=@_;
unless ($element_decl->getElementType eq 'ELEMENT') {
$element_decl->error($element_decl => 'is not an ELEMENT declaration');
return $element_decl->extension('ATTLIST',%attrs);
my $subset=$self->internal_subset();
my $element_decl=$subset->getElementDeclByName($attrs{name
});
$subset->error("ATTLIST declaration '$attrs{attr}'" => "ELEMENT declaration '$attrs{name}' does not exist");
return $element_decl->attribute_decl(%attrs);
my $subset=$self->internal_subset();
return $subset->extension('NOTATION',%attrs);
my $subset=$self->internal_subset();
return $subset->extension('ENTITY',%attrs);
# this interim version of xmlify handles the vanilla extension
# format of one parent 'internal' element containing a list of
# extension elements. A hierarchical model will follow in time
# with the same render API.
if ($self->{-name
} ne 'internal') {
SWITCH
: foreach ($self->{-name
}) {
$decl.="ELEMENT $self->{name}";
$decl.=" ".$self->{model
} if exists $self->{model
};
$decl.="ATTLIST $self->{name} $self->{attr}";
$decl.=" $self->{type} ".
($self->{fixed
}?
"#FIXED ":"").
$decl.="NOTATION $self->{name}";
$decl.=" ".$self->{base
} if exists $self->{base
};
if (exists $self->{pubid
}) {
$decl.="PUBLIC $self->{pubid} ";
$decl.=" ".$self->{sysid
} if exists $self->{sysid
};
} elsif (exists $self->{sysid
}) {
$decl.=" SYSTEM ".$self->{sysid
} if exists $self->{sysid
};
$decl.="ENTITY ".($self->{isp
}?
"% ":"").$self->{name
};
if (exists $self->{value
}) {
$decl.=' "'.$self->{value
}.'"';
} elsif (exists $self->{pubid
}) {
$decl.="PUBLIC $self->{pubid} ";
$decl.=" ".$self->{sysid
} if exists $self->{sysid
};
$decl.=" ".$self->{ndata
} if $self->{ndata
};
$decl.=" SYSTEM ".$self->{sysid
} if exists $self->{sysid
};
$decl.=" ".$self->{ndata
} if $self->{ndata
};
# we don't know what this is, but the underlying parser allowed it
$decl.="$self->{-name} $self->{name}";
$decl.=">".$self->{-docref
}{-elsep
};
if ($self->hasChildren) {
$self->{-docref
}->{-level
}++;
foreach my $child ($self->getChildren) {
$result .= ($self->{-docref
}{-indent
} x
$self->{-docref
}->{-level
}).
$self->{-docref
}->{-level
}--;
# simply an alias for the general method for SVG::Extension objects
return shift->SUPER::getElementName
();
*getExtensionName
=\
&getDeclName
;
# return list of existing decl types by extracting it from the overall list
# of existing element types
} $self->SUPER::getElementNames
();
*getExtensionNames
=\
&getDeclNames
;
# we can have only one element decl of a given name...
sub getElementDeclByName
{
my $subset=$self->internal_subset();
my @element_decls=$subset->getElementsByName('ELEMENT');
foreach my $element_decl (@element_decls) {
return $element_decl if $element_decl->{name
} eq $name;
# ...but we can have multiple attributes. Note that this searches the master list
# which is not what you are likely to want in most cases. See getAttributeDeclByName
# (no 's') below, to search for an attribute decl on a particular element decl.
# You can use the result of this method along with getParent to find the list of
# all element decls that define a given attribute.
sub getAttributeDeclsByName
{
my $subset=$self->internal_subset();
my @element_decls=$subset->getElementsByName('ELEMENT');
foreach my $element_decl (@element_decls) {
return $element_decl if $element_decl->{name
} eq $name;
return shift->SUPER::getElements
('ELEMENT');
return shift->SUPER::getElements
('NOTATION');
*getNotationDecls
=\
&getNotations
;
return shift->SUPER::getElements
('ENTITY');
*getEntityDecls
=\
&getEntities
;
return shift->SUPER::getElements
('ATTLIST');
# until/unless we subclass these, use the name. After (if) we
# subclass, will use the object class.
return (shift->getElementName eq ELEMENT
)?
1:0;
return (shift->getElementName eq NOTATION
)?
1:0;
return (shift->getElementName eq ENTITY
)?
1:0;
return (shift->getElementName eq ATTLIST
)?
1:0;
# the Decl 'name' is an attribute, the name is e.g. 'ELEMENT'
# use getElementName if you want the actual decl type
sub getElementDeclName
($) {
if (exists $self->{name
}) {
# identical to the above; will be smarter as and when we subclass
# as above, the name is ATTLIST, the 'name' is a property of the decl
sub getAttributeDeclName
($) {
if (exists $self->{name
}) {
# unlike other 'By' methods, attribute searches work from their parent element
# del only. Multiple element decls with the same attribute name is more than
# likely, so searching the master ATTLIST is not very useful. If you really want
# to do that, use getAttributeDeclsByName (with an 's') above.
sub getAttributeDeclByName
{
my @attribute_decls=$self->getElementAttributeDecls();
foreach my $attribute_decl (@attribute_decls) {
return $attribute_decl if $attribute_decl->{name
} eq $name;
# as this is element specific, we allow a 'ElementAttribute' name too,
# for those that like consistency at the price of brevity. Not that
# the shorter name is all that brief to start with...
*getElementAttributeDeclByName
=\
&getAttributeDeclByName
;
# ...and for those who live their brevity:
*getAttributeDecl
=\
&getAttributeDeclByName
;
return (shift->getElementDeclByName(shift))?
1:0;
# directly map to Child/Siblings: we presume this is being called from an
# element decl. You can use 'getChildIndex', 'getChildAtIndex' etc. as well
sub getElementAttributeAtIndex
($$;@
) {
my ($self,$index,@children)=@_;
return $self->SUPER::getChildAtIndex
($index,@children);
sub getElementAttributeIndex
($;@
) {
return shift->SUPER::getChildIndex
(@_);
sub getFirstAttributeDecl
($) {
return shift->SUPER::getFirstChild
();
sub getNextAttributeDecl
($) {
return shift->SUPER::getNextSibling
();
sub getLastAttributeDecl
($) {
return shift->SUPER::getLastChild
();
sub getPreviousAttributeDecl
($) {
return shift->SUPER::getPreviousSibling
();
sub getElementAttributeDecls
($) {
return shift->SUPER::getChildren
();
#-------------------------------------------------------------------------------
# These methods are slated for inclusion in a future release of SVG.pm. They
# will allow programmatic advance determination of the validity of various DOM
# manipulations. If you are in a hurry for this feature, get in touch!
# if ($svg_object->allowsElement("symbol")) { ... }
#sub allowedAttributes {}
#-------------------------------------------------------------------------------