1 |
sashby |
1.1 |
#____________________________________________________________________
|
2 |
|
|
# File: SimpleXMLDoc.pm
|
3 |
|
|
#____________________________________________________________________
|
4 |
|
|
#
|
5 |
|
|
# Author: Shaun Ashby <Shaun.Ashby@cern.ch>
|
6 |
|
|
# Update: 2005-04-22 17:09:26+0200
|
7 |
sashby |
1.5 |
# Revision: $Id: SimpleXMLDoc.pm,v 1.4 2006/01/19 17:26:29 sashby Exp $
|
8 |
sashby |
1.1 |
#
|
9 |
|
|
# Copyright: 2005 (C) Shaun Ashby
|
10 |
|
|
#
|
11 |
|
|
#--------------------------------------------------------------------
|
12 |
sashby |
1.2 |
|
13 |
|
|
=head1 NAME
|
14 |
|
|
|
15 |
|
|
ActiveDoc::SimpleXMLDoc - Base SCRAM document class.
|
16 |
|
|
|
17 |
|
|
=head1 SYNOPSIS
|
18 |
|
|
|
19 |
|
|
my $obj = ActiveDoc::SimpleXMLDoc->new();
|
20 |
|
|
|
21 |
|
|
=head1 DESCRIPTION
|
22 |
|
|
|
23 |
|
|
The ActiveDoc::SimpleXMLDoc class is the base class for all SCRAM documents. It hides all the
|
24 |
|
|
machinery needed to activate full XML parsing. The XML parser used is XML::Parser::Expat.
|
25 |
|
|
|
26 |
|
|
=head1 METHODS
|
27 |
|
|
|
28 |
|
|
=over
|
29 |
|
|
|
30 |
|
|
=cut
|
31 |
|
|
|
32 |
sashby |
1.1 |
package ActiveDoc::SimpleXMLDoc;
|
33 |
sashby |
1.2 |
use XML::Parser::Expat;
|
34 |
|
|
use ActiveDoc::Container;
|
35 |
sashby |
1.1 |
require 5.004;
|
36 |
|
|
use Exporter;
|
37 |
|
|
|
38 |
|
|
@ISA=qw(Exporter);
|
39 |
sashby |
1.2 |
@EXPORT_OK=qw();
|
40 |
sashby |
1.1 |
|
41 |
|
|
sub new()
|
42 |
|
|
{
|
43 |
sashby |
1.2 |
###############################################################
|
44 |
|
|
# new #
|
45 |
|
|
###############################################################
|
46 |
|
|
# modified : Fri Apr 22 17:10:10 2005 / SFA #
|
47 |
|
|
# params : #
|
48 |
|
|
# : #
|
49 |
|
|
# function : #
|
50 |
|
|
# : #
|
51 |
|
|
###############################################################
|
52 |
|
|
my $proto=shift;
|
53 |
|
|
my $class=ref($proto) || $proto;
|
54 |
|
|
my $self={};
|
55 |
|
|
bless $self,$class;
|
56 |
|
|
my @handler_list=('Start','End','Char','Proc','Comment',
|
57 |
|
|
'Entity','Element','Attlist','Doctype','DoctypeFin'); # DTD handlers
|
58 |
|
|
|
59 |
|
|
my ($context, @userhandlers)=@_;
|
60 |
|
|
|
61 |
|
|
$CONTAINER=new ActiveDoc::Container; # The base container;
|
62 |
|
|
|
63 |
|
|
# Set the default handlers:
|
64 |
|
|
$self->{DEFAULT_HANDLERS}={ 'Start' => \&open_, 'End' => \&close_,
|
65 |
|
|
'Char' => \&char_, 'Proc' => \&proc_,
|
66 |
|
|
'Comment' => \&comment_,
|
67 |
|
|
'Entity' => \&entity_,
|
68 |
|
|
'Element' => \&element_,
|
69 |
|
|
'Attlist' => \&attlist_,
|
70 |
|
|
'Doctype' => \&doctype_,
|
71 |
|
|
'DoctypeFin' => \&doctypefin_ };
|
72 |
|
|
|
73 |
|
|
# Check each supplied handler. If there's a code ref, we override the
|
74 |
|
|
# default handler given in this package:
|
75 |
|
|
my $i;
|
76 |
|
|
for ($i = 0; $i <= $#userhandlers; $i++)
|
77 |
|
|
{
|
78 |
|
|
if (ref($userhandlers[$i]) eq 'CODE')
|
79 |
|
|
{
|
80 |
|
|
$self->{DEFAULT_HANDLERS}->{$handler_list[$i]} = $userhandlers[$i];
|
81 |
|
|
}
|
82 |
|
|
}
|
83 |
sashby |
1.1 |
|
84 |
sashby |
1.2 |
$self->{CONTEXT}=$context;
|
85 |
sashby |
1.1 |
|
86 |
sashby |
1.2 |
# Initialise the XML parser:
|
87 |
|
|
$self->{xmlparser} = XML::Parser::Expat->new(ErrorContext => 3,
|
88 |
|
|
ParseParamEnt => 1);
|
89 |
sashby |
1.1 |
|
90 |
sashby |
1.2 |
# Add the default XML tag handlers:
|
91 |
|
|
foreach my $handler (@handler_list)
|
92 |
sashby |
1.1 |
{
|
93 |
sashby |
1.2 |
$self->{xmlparser}->setHandlers($handler => $self->{DEFAULT_HANDLERS}->{$handler});
|
94 |
sashby |
1.1 |
}
|
95 |
sashby |
1.2 |
|
96 |
|
|
return $self;
|
97 |
sashby |
1.1 |
}
|
98 |
|
|
|
99 |
sashby |
1.2 |
sub parse()
|
100 |
sashby |
1.1 |
{
|
101 |
|
|
my $self=shift;
|
102 |
sashby |
1.2 |
my ($filename)=@_;
|
103 |
|
|
|
104 |
|
|
if (-f $filename)
|
105 |
|
|
{
|
106 |
|
|
$self->parsefile_($filename);
|
107 |
sashby |
1.6 |
# Move the data from the container to {data_} key and
|
108 |
|
|
# also keep a reference to the whole container object
|
109 |
|
|
# just in case there is other data needed outside of 'content':
|
110 |
sashby |
1.4 |
$self->data();
|
111 |
sashby |
1.2 |
}
|
112 |
|
|
else
|
113 |
|
|
{
|
114 |
|
|
# Error: file not found
|
115 |
|
|
die "SCRAM SimpleXMLDoc: File \"".$filename."\" not found! Context label = \"".$self->{CONTEXT}."\"\n";
|
116 |
|
|
}
|
117 |
sashby |
1.1 |
}
|
118 |
|
|
|
119 |
sashby |
1.2 |
sub register_handlers_()
|
120 |
sashby |
1.1 |
{
|
121 |
sashby |
1.2 |
my $self=shift;
|
122 |
|
|
# Register tags to the container class:
|
123 |
|
|
if (@_)
|
124 |
|
|
{
|
125 |
|
|
$CONTAINER->register_handlers_(@_);
|
126 |
|
|
}
|
127 |
sashby |
1.1 |
}
|
128 |
|
|
|
129 |
sashby |
1.2 |
sub parsefile_()
|
130 |
sashby |
1.1 |
{
|
131 |
|
|
my $self=shift;
|
132 |
|
|
my ($filename)=@_;
|
133 |
sashby |
1.2 |
$self->{xmlparser}->parsefile($filename)
|
134 |
|
|
|| $self->{xmlparser}->xpcroak("SCRAM SimpleDoc XML parse error:");
|
135 |
sashby |
1.1 |
# Clean up:
|
136 |
|
|
delete $self->{xmlparser};
|
137 |
|
|
}
|
138 |
|
|
|
139 |
sashby |
1.2 |
sub data()
|
140 |
sashby |
1.1 |
{
|
141 |
|
|
my $self=shift;
|
142 |
sashby |
1.4 |
$self->{data_} = $CONTAINER->data_();
|
143 |
sashby |
1.6 |
$self->{fulldata_} = $CONTAINER;
|
144 |
sashby |
1.2 |
}
|
145 |
|
|
|
146 |
|
|
# The default handlers:
|
147 |
|
|
sub open_()
|
148 |
|
|
{
|
149 |
|
|
my $xmlparser=shift;
|
150 |
|
|
my ($element, %attributes)=@_;
|
151 |
|
|
$element=~tr[A-Z][a-z];
|
152 |
|
|
# Handle document "doc" tags and load a
|
153 |
|
|
# container class for the document type:
|
154 |
|
|
if ($element eq 'doc')
|
155 |
sashby |
1.1 |
{
|
156 |
sashby |
1.2 |
if (exists ($attributes{'type'}))
|
157 |
|
|
{
|
158 |
|
|
my $doctype=$attributes{'type'}."::Container";
|
159 |
|
|
eval "require $doctype";
|
160 |
|
|
if ($@)
|
161 |
|
|
{
|
162 |
|
|
print "SCRAM SimpleXMLDoc: Unable to parse the current document because\n";
|
163 |
|
|
print " the data container type (=DOCTYPE) is invalid!\n";
|
164 |
|
|
print "\n";
|
165 |
|
|
die $@,"\n";
|
166 |
|
|
}
|
167 |
|
|
# Bless the base container to its real type:
|
168 |
|
|
bless($CONTAINER,$doctype);
|
169 |
|
|
}
|
170 |
|
|
else
|
171 |
|
|
{
|
172 |
|
|
die "SCRAM SimpleXMLDoc: Unable to handle a NULL document type!","\n";
|
173 |
|
|
}
|
174 |
|
|
return;
|
175 |
sashby |
1.1 |
}
|
176 |
|
|
else
|
177 |
|
|
{
|
178 |
sashby |
1.2 |
# Pass the call to the container class. This will use the AUTOLOAD
|
179 |
|
|
# function of the class:
|
180 |
|
|
$CONTAINER->open($element);
|
181 |
sashby |
1.3 |
$CONTAINER->$element($element,\%attributes);
|
182 |
sashby |
1.1 |
}
|
183 |
|
|
}
|
184 |
|
|
|
185 |
sashby |
1.2 |
sub close_()
|
186 |
|
|
{
|
187 |
|
|
my $xmlparser=shift;
|
188 |
|
|
my ($element)=@_;
|
189 |
|
|
$element=~tr[A-Z][a-z];
|
190 |
|
|
return if $element eq 'doc';
|
191 |
|
|
# Tell the container that the tag ended:
|
192 |
|
|
$CONTAINER->close($element);
|
193 |
|
|
}
|
194 |
|
|
|
195 |
|
|
sub char_()
|
196 |
|
|
{
|
197 |
|
|
my ($xmlparser, @items) = @_;
|
198 |
|
|
my $string=join("",@items);
|
199 |
|
|
return if ($string !~ /[a-zA-Z0-9_].*/);
|
200 |
|
|
# Push the strings onto the container object, just in case
|
201 |
|
|
# they form part of content for the active tag:
|
202 |
|
|
$CONTAINER->text_($string);
|
203 |
|
|
}
|
204 |
|
|
|
205 |
|
|
sub proc_()
|
206 |
|
|
{
|
207 |
|
|
my ($xmlparser,$target,$data)=@_;
|
208 |
|
|
}
|
209 |
|
|
|
210 |
|
|
sub comment_()
|
211 |
sashby |
1.1 |
{
|
212 |
sashby |
1.2 |
my ($xmlparser,$string)=@_;
|
213 |
|
|
}
|
214 |
|
|
|
215 |
|
|
# Entity (Parser, Name, Val, Sysid, Pubid, Ndata,IsParam)
|
216 |
|
|
sub entity_()
|
217 |
|
|
{
|
218 |
|
|
my ($xmlparser, $name, $val, $sysid, $pubid, $ndata)=@_;
|
219 |
|
|
}
|
220 |
|
|
|
221 |
|
|
# Element (Parser, Name, Model)
|
222 |
|
|
sub element_()
|
223 |
|
|
{
|
224 |
|
|
my ($xmlparser,$name,$model)=@_;
|
225 |
|
|
}
|
226 |
|
|
|
227 |
|
|
# Attlist (Parser, Elname, Attname, Type, Default, Fixed)
|
228 |
|
|
sub attlist_()
|
229 |
|
|
{
|
230 |
|
|
my ($xmlparser,$element, $attname, $type, $default,$fixed)=@_;
|
231 |
|
|
}
|
232 |
|
|
|
233 |
|
|
# Doctype (Parser, Name, Sysid, Pubid, Internal)
|
234 |
|
|
sub doctype_()
|
235 |
|
|
{
|
236 |
|
|
my ($xmlparser,$name,$sysid,$pubid,$internal)=@_;
|
237 |
sashby |
1.1 |
}
|
238 |
|
|
|
239 |
sashby |
1.2 |
# DoctypeFin (Parser)
|
240 |
|
|
sub doctypefin_()
|
241 |
sashby |
1.1 |
{
|
242 |
sashby |
1.2 |
my ($xmlparser)=@_;
|
243 |
sashby |
1.1 |
}
|
244 |
|
|
|
245 |
|
|
1;
|
246 |
sashby |
1.2 |
|
247 |
|
|
=back
|
248 |
|
|
|
249 |
|
|
=head1 AUTHOR/MAINTAINER
|
250 |
|
|
|
251 |
|
|
Shaun ASHBY
|
252 |
|
|
|
253 |
|
|
=cut
|
254 |
|
|
|