common/tools/raptor/XML/NamespaceSupport.pm
changeset 923 5ccf9d5ab663
parent 922 996297fad800
parent 907 bab81256b297
child 924 a5ed0e6ca679
equal deleted inserted replaced
922:996297fad800 923:5ccf9d5ab663
     1 
       
     2 ###
       
     3 # XML::NamespaceSupport - a simple generic namespace processor
       
     4 # Robin Berjon <robin@knowscape.com>
       
     5 ###
       
     6 
       
     7 package XML::NamespaceSupport;
       
     8 use strict;
       
     9 use constant FATALS         => 0; # root object
       
    10 use constant NSMAP          => 1;
       
    11 use constant UNKNOWN_PREF   => 2;
       
    12 use constant AUTO_PREFIX    => 3;
       
    13 use constant DEFAULT        => 0; # maps
       
    14 use constant PREFIX_MAP     => 1;
       
    15 use constant DECLARATIONS   => 2;
       
    16 
       
    17 use vars qw($VERSION $NS_XMLNS $NS_XML);
       
    18 $VERSION    = '1.07';
       
    19 $NS_XMLNS   = 'http://www.w3.org/2000/xmlns/';
       
    20 $NS_XML     = 'http://www.w3.org/XML/1998/namespace';
       
    21 
       
    22 
       
    23 # add the ns stuff that baud wants based on Java's xml-writer
       
    24 
       
    25 
       
    26 #-------------------------------------------------------------------#
       
    27 # constructor
       
    28 #-------------------------------------------------------------------#
       
    29 sub new {
       
    30     my $class   = ref($_[0]) ? ref(shift) : shift;
       
    31     my $options = shift;
       
    32     my $self = [
       
    33                 1, # FATALS
       
    34                 [[ # NSMAP
       
    35                   undef,              # DEFAULT
       
    36                   { xml => $NS_XML }, # PREFIX_MAP
       
    37                   undef,              # DECLARATIONS
       
    38                 ]],
       
    39                 'aaa', # UNKNOWN_PREF
       
    40                 0,     # AUTO_PREFIX
       
    41                ];
       
    42     $self->[NSMAP]->[0]->[PREFIX_MAP]->{xmlns} = $NS_XMLNS if $options->{xmlns};
       
    43     $self->[FATALS] = $options->{fatal_errors} if defined $options->{fatal_errors};
       
    44     $self->[AUTO_PREFIX] = $options->{auto_prefix} if defined $options->{auto_prefix};
       
    45     return bless $self, $class;
       
    46 }
       
    47 #-------------------------------------------------------------------#
       
    48 
       
    49 #-------------------------------------------------------------------#
       
    50 # reset() - return to the original state (for reuse)
       
    51 #-------------------------------------------------------------------#
       
    52 sub reset {
       
    53     my $self = shift;
       
    54     $#{$self->[NSMAP]} = 0;
       
    55 }
       
    56 #-------------------------------------------------------------------#
       
    57 
       
    58 #-------------------------------------------------------------------#
       
    59 # push_context() - add a new empty context to the stack
       
    60 #-------------------------------------------------------------------#
       
    61 sub push_context {
       
    62     my $self = shift;
       
    63     push @{$self->[NSMAP]}, [
       
    64                              $self->[NSMAP]->[-1]->[DEFAULT],
       
    65                              { %{$self->[NSMAP]->[-1]->[PREFIX_MAP]} },
       
    66                              [],
       
    67                             ];
       
    68 }
       
    69 #-------------------------------------------------------------------#
       
    70 
       
    71 #-------------------------------------------------------------------#
       
    72 # pop_context() - remove the topmost context fromt the stack
       
    73 #-------------------------------------------------------------------#
       
    74 sub pop_context {
       
    75     my $self = shift;
       
    76     die 'Trying to pop context without push context' unless @{$self->[NSMAP]} > 1;
       
    77     pop @{$self->[NSMAP]};
       
    78 }
       
    79 #-------------------------------------------------------------------#
       
    80 
       
    81 #-------------------------------------------------------------------#
       
    82 # declare_prefix() - declare a prefix in the current scope
       
    83 #-------------------------------------------------------------------#
       
    84 sub declare_prefix {
       
    85     my $self    = shift;
       
    86     my $prefix  = shift;
       
    87     my $value   = shift;
       
    88 
       
    89     warn <<'    EOWARN' unless defined $prefix or $self->[AUTO_PREFIX];
       
    90     Prefix was undefined.
       
    91     If you wish to set the default namespace, use the empty string ''.
       
    92     If you wish to autogenerate prefixes, set the auto_prefix option
       
    93     to a true value.
       
    94     EOWARN
       
    95 
       
    96     return 0 if index(lc($prefix), 'xml') == 0;
       
    97 
       
    98     if (defined $prefix and $prefix eq '') {
       
    99         $self->[NSMAP]->[-1]->[DEFAULT] = $value;
       
   100     }
       
   101     else {
       
   102         die "Cannot undeclare prefix $prefix" if $value eq '';
       
   103         if (not defined $prefix and $self->[AUTO_PREFIX]) {
       
   104             while (1) {
       
   105                 $prefix = $self->[UNKNOWN_PREF]++;
       
   106                 last if not exists $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
       
   107             }
       
   108         }
       
   109         elsif (not defined $prefix and not $self->[AUTO_PREFIX]) {
       
   110             return 0;
       
   111         }
       
   112         $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix} = $value;
       
   113     }
       
   114     push @{$self->[NSMAP]->[-1]->[DECLARATIONS]}, $prefix;
       
   115     return 1;
       
   116 }
       
   117 #-------------------------------------------------------------------#
       
   118 
       
   119 #-------------------------------------------------------------------#
       
   120 # declare_prefixes() - declare several prefixes in the current scope
       
   121 #-------------------------------------------------------------------#
       
   122 sub declare_prefixes {
       
   123     my $self     = shift;
       
   124     my %prefixes = @_;
       
   125     while (my ($k,$v) = each %prefixes) {
       
   126         $self->declare_prefix($k,$v);
       
   127     }
       
   128 }
       
   129 #-------------------------------------------------------------------#
       
   130 
       
   131 #-------------------------------------------------------------------#
       
   132 # undeclare_prefix
       
   133 #-------------------------------------------------------------------#
       
   134 sub undeclare_prefix {
       
   135     my $self   = shift;
       
   136     my $prefix = shift;
       
   137     return unless not defined $prefix or $prefix eq '';
       
   138     return unless exists $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
       
   139 
       
   140     my ( $tfix ) = grep { $_ eq $prefix } @{$self->[NSMAP]->[-1]->[DECLARATIONS]};
       
   141     if ( not defined $tfix ) {
       
   142         die "prefix $prefix not declared in this context\n";
       
   143     }
       
   144 
       
   145     @{$self->[NSMAP]->[-1]->[DECLARATIONS]} = grep { $_ ne $prefix } @{$self->[NSMAP]->[-1]->[DECLARATIONS]};
       
   146     delete $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
       
   147 }
       
   148 #-------------------------------------------------------------------#
       
   149 
       
   150 #-------------------------------------------------------------------#
       
   151 # get_prefix() - get a (random) prefix for a given URI
       
   152 #-------------------------------------------------------------------#
       
   153 sub get_prefix {
       
   154     my $self    = shift;
       
   155     my $uri     = shift;
       
   156 
       
   157     # we have to iterate over the whole hash here because if we don't
       
   158     # the iterator isn't reset and the next pass will fail
       
   159     my $pref;
       
   160     while (my ($k, $v) = each %{$self->[NSMAP]->[-1]->[PREFIX_MAP]}) {
       
   161         $pref = $k if $v eq $uri;
       
   162     }
       
   163     return $pref;
       
   164 }
       
   165 #-------------------------------------------------------------------#
       
   166 
       
   167 #-------------------------------------------------------------------#
       
   168 # get_prefixes() - get all the prefixes for a given URI
       
   169 #-------------------------------------------------------------------#
       
   170 sub get_prefixes {
       
   171     my $self    = shift;
       
   172     my $uri     = shift;
       
   173 
       
   174     return keys %{$self->[NSMAP]->[-1]->[PREFIX_MAP]} unless defined $uri;
       
   175     return grep { $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$_} eq $uri } keys %{$self->[NSMAP]->[-1]->[PREFIX_MAP]};
       
   176 }
       
   177 #-------------------------------------------------------------------#
       
   178 
       
   179 #-------------------------------------------------------------------#
       
   180 # get_declared_prefixes() - get all prefixes declared in the last context
       
   181 #-------------------------------------------------------------------#
       
   182 sub get_declared_prefixes {
       
   183     return @{$_[0]->[NSMAP]->[-1]->[DECLARATIONS]};
       
   184 }
       
   185 #-------------------------------------------------------------------#
       
   186 
       
   187 #-------------------------------------------------------------------#
       
   188 # get_uri() - get an URI given a prefix
       
   189 #-------------------------------------------------------------------#
       
   190 sub get_uri {
       
   191     my $self    = shift;
       
   192     my $prefix  = shift;
       
   193 
       
   194     warn "Prefix must not be undef in get_uri(). The emtpy prefix must be ''" unless defined $prefix;
       
   195 
       
   196     return $self->[NSMAP]->[-1]->[DEFAULT] if $prefix eq '';
       
   197     return $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix} if exists $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
       
   198     return undef;
       
   199 }
       
   200 #-------------------------------------------------------------------#
       
   201 
       
   202 #-------------------------------------------------------------------#
       
   203 # process_name() - provide details on a name
       
   204 #-------------------------------------------------------------------#
       
   205 sub process_name {
       
   206     my $self    = shift;
       
   207     my $qname   = shift;
       
   208     my $aflag   = shift;
       
   209 
       
   210     if ($self->[FATALS]) {
       
   211         return( ($self->_get_ns_details($qname, $aflag))[0,2], $qname );
       
   212     }
       
   213     else {
       
   214         eval { return( ($self->_get_ns_details($qname, $aflag))[0,2], $qname ); }
       
   215     }
       
   216 }
       
   217 #-------------------------------------------------------------------#
       
   218 
       
   219 #-------------------------------------------------------------------#
       
   220 # process_element_name() - provide details on a element's name
       
   221 #-------------------------------------------------------------------#
       
   222 sub process_element_name {
       
   223     my $self    = shift;
       
   224     my $qname   = shift;
       
   225 
       
   226     if ($self->[FATALS]) {
       
   227         return $self->_get_ns_details($qname, 0);
       
   228     }
       
   229     else {
       
   230         eval { return $self->_get_ns_details($qname, 0); }
       
   231     }
       
   232 }
       
   233 #-------------------------------------------------------------------#
       
   234 
       
   235 
       
   236 #-------------------------------------------------------------------#
       
   237 # process_attribute_name() - provide details on a attribute's name
       
   238 #-------------------------------------------------------------------#
       
   239 sub process_attribute_name {
       
   240     my $self    = shift;
       
   241     my $qname   = shift;
       
   242 
       
   243     if ($self->[FATALS]) {
       
   244         return $self->_get_ns_details($qname, 1);
       
   245     }
       
   246     else {
       
   247         eval { return $self->_get_ns_details($qname, 1); }
       
   248     }
       
   249 }
       
   250 #-------------------------------------------------------------------#
       
   251 
       
   252 
       
   253 #-------------------------------------------------------------------#
       
   254 # ($ns, $prefix, $lname) = $self->_get_ns_details($qname, $f_attr)
       
   255 # returns ns, prefix, and lname for a given attribute name
       
   256 # >> the $f_attr flag, if set to one, will work for an attribute
       
   257 #-------------------------------------------------------------------#
       
   258 sub _get_ns_details {
       
   259     my $self    = shift;
       
   260     my $qname   = shift;
       
   261     my $aflag   = shift;
       
   262 
       
   263     my ($ns, $prefix, $lname);
       
   264     (my ($tmp_prefix, $tmp_lname) = split /:/, $qname, 3)
       
   265                                     < 3 or die "Invalid QName: $qname";
       
   266 
       
   267     # no prefix
       
   268     my $cur_map = $self->[NSMAP]->[-1];
       
   269     if (not defined($tmp_lname)) {
       
   270         $prefix = undef;
       
   271         $lname = $qname;
       
   272         # attr don't have a default namespace
       
   273         $ns = ($aflag) ? undef : $cur_map->[DEFAULT];
       
   274     }
       
   275 
       
   276     # prefix
       
   277     else {
       
   278         if (exists $cur_map->[PREFIX_MAP]->{$tmp_prefix}) {
       
   279             $prefix = $tmp_prefix;
       
   280             $lname  = $tmp_lname;
       
   281             $ns     = $cur_map->[PREFIX_MAP]->{$prefix}
       
   282         }
       
   283         else { # no ns -> lname == name, all rest undef
       
   284             die "Undeclared prefix: $tmp_prefix";
       
   285         }
       
   286     }
       
   287 
       
   288     return ($ns, $prefix, $lname);
       
   289 }
       
   290 #-------------------------------------------------------------------#
       
   291 
       
   292 #-------------------------------------------------------------------#
       
   293 # parse_jclark_notation() - parse the Clarkian notation
       
   294 #-------------------------------------------------------------------#
       
   295 sub parse_jclark_notation {
       
   296     shift;
       
   297     my $jc = shift;
       
   298     $jc =~ m/^\{(.*)\}([^}]+)$/;
       
   299     return $1, $2;
       
   300 }
       
   301 #-------------------------------------------------------------------#
       
   302 
       
   303 
       
   304 #-------------------------------------------------------------------#
       
   305 # Java names mapping
       
   306 #-------------------------------------------------------------------#
       
   307 *XML::NamespaceSupport::pushContext          = \&push_context;
       
   308 *XML::NamespaceSupport::popContext           = \&pop_context;
       
   309 *XML::NamespaceSupport::declarePrefix        = \&declare_prefix;
       
   310 *XML::NamespaceSupport::declarePrefixes      = \&declare_prefixes;
       
   311 *XML::NamespaceSupport::getPrefix            = \&get_prefix;
       
   312 *XML::NamespaceSupport::getPrefixes          = \&get_prefixes;
       
   313 *XML::NamespaceSupport::getDeclaredPrefixes  = \&get_declared_prefixes;
       
   314 *XML::NamespaceSupport::getURI               = \&get_uri;
       
   315 *XML::NamespaceSupport::processName          = \&process_name;
       
   316 *XML::NamespaceSupport::processElementName   = \&process_element_name;
       
   317 *XML::NamespaceSupport::processAttributeName = \&process_attribute_name;
       
   318 *XML::NamespaceSupport::parseJClarkNotation  = \&parse_jclark_notation;
       
   319 *XML::NamespaceSupport::undeclarePrefix      = \&undeclare_prefix;
       
   320 #-------------------------------------------------------------------#
       
   321 
       
   322 
       
   323 1;
       
   324 #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
       
   325 #`,`, Documentation `,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
       
   326 #```````````````````````````````````````````````````````````````````#
       
   327 
       
   328 =pod
       
   329 
       
   330 =head1 NAME
       
   331 
       
   332 XML::NamespaceSupport - a simple generic namespace support class
       
   333 
       
   334 =head1 SYNOPSIS
       
   335 
       
   336   use XML::NamespaceSupport;
       
   337   my $nsup = XML::NamespaceSupport->new;
       
   338 
       
   339   # add a new empty context
       
   340   $nsup->push_context;
       
   341   # declare a few prefixes
       
   342   $nsup->declare_prefix($prefix1, $uri1);
       
   343   $nsup->declare_prefix($prefix2, $uri2);
       
   344   # the same shorter
       
   345   $nsup->declare_prefixes($prefix1 => $uri1, $prefix2 => $uri2);
       
   346 
       
   347   # get a single prefix for a URI (randomly)
       
   348   $prefix = $nsup->get_prefix($uri);
       
   349   # get all prefixes for a URI (probably better)
       
   350   @prefixes = $nsup->get_prefixes($uri);
       
   351   # get all prefixes in scope
       
   352   @prefixes = $nsup->get_prefixes();
       
   353   # get all prefixes that were declared for the current scope
       
   354   @prefixes = $nsup->get_declared_prefixes;
       
   355   # get a URI for a given prefix
       
   356   $uri = $nsup->get_uri($prefix);
       
   357 
       
   358   # get info on a qname (java-ish way, it's a bit weird)
       
   359   ($ns_uri, $local_name, $qname) = $nsup->process_name($qname, $is_attr);
       
   360   # the same, more perlish
       
   361   ($ns_uri, $prefix, $local_name) = $nsup->process_element_name($qname);
       
   362   ($ns_uri, $prefix, $local_name) = $nsup->process_attribute_name($qname);
       
   363 
       
   364   # remove the current context
       
   365   $nsup->pop_context;
       
   366 
       
   367   # reset the object for reuse in another document
       
   368   $nsup->reset;
       
   369 
       
   370   # a simple helper to process Clarkian Notation
       
   371   my ($ns, $lname) = $nsup->parse_jclark_notation('{http://foo}bar');
       
   372   # or (given that it doesn't care about the object
       
   373   my ($ns, $lname) = XML::NamespaceSupport->parse_jclark_notation('{http://foo}bar');
       
   374 
       
   375 
       
   376 =head1 DESCRIPTION
       
   377 
       
   378 This module offers a simple to process namespaced XML names (unames)
       
   379 from within any application that may need them. It also helps maintain
       
   380 a prefix to namespace URI map, and provides a number of basic checks.
       
   381 
       
   382 The model for this module is SAX2's NamespaceSupport class, readable at
       
   383 http://www.megginson.com/SAX/Java/javadoc/org/xml/sax/helpers/NamespaceSupport.html.
       
   384 It adds a few perlisations where we thought it appropriate.
       
   385 
       
   386 =head1 METHODS
       
   387 
       
   388 =over 4
       
   389 
       
   390 =item * XML::NamespaceSupport->new(\%options)
       
   391 
       
   392 A simple constructor.
       
   393 
       
   394 The options are C<xmlns>, C<fatal_errors>, and C<auto_prefix>
       
   395 
       
   396 If C<xmlns> is turned on (it is off by default) the mapping from the
       
   397 xmlns prefix to the URI defined for it in DOM level 2 is added to the
       
   398 list of predefined mappings (which normally only contains the xml
       
   399 prefix mapping).
       
   400 
       
   401 If C<fatal_errors> is turned off (it is on by default) a number of
       
   402 validity errors will simply be flagged as failures, instead of
       
   403 die()ing.
       
   404 
       
   405 If C<auto_prefix> is turned on (it is off by default) when one
       
   406 provides a prefix of C<undef> to C<declare_prefix> it will generate a
       
   407 random prefix mapped to that namespace. Otherwise an undef prefix will
       
   408 trigger a warning (you should probably know what you're doing if you
       
   409 turn this option on).
       
   410 
       
   411 =item * $nsup->push_context
       
   412 
       
   413 Adds a new empty context to the stack. You can then populate it with
       
   414 new prefixes defined at this level.
       
   415 
       
   416 =item * $nsup->pop_context
       
   417 
       
   418 Removes the topmost context in the stack and reverts to the previous
       
   419 one. It will die() if you try to pop more than you have pushed.
       
   420 
       
   421 =item * $nsup->declare_prefix($prefix, $uri)
       
   422 
       
   423 Declares a mapping of $prefix to $uri, at the current level.
       
   424 
       
   425 Note that with C<auto_prefix> turned on, if you declare a prefix
       
   426 mapping in which $prefix is undef(), you will get an automatic prefix
       
   427 selected for you. If it is off you will get a warning.
       
   428 
       
   429 This is useful when you deal with code that hasn't kept prefixes around
       
   430 and need to reserialize the nodes. It also means that if you want to
       
   431 set the default namespace (ie with an empty prefix) you must use the
       
   432 empty string instead of undef. This behaviour is consistent with the
       
   433 SAX 2.0 specification.
       
   434 
       
   435 =item * $nsup->declare_prefixes(%prefixes2uris)
       
   436 
       
   437 Declares a mapping of several prefixes to URIs, at the current level.
       
   438 
       
   439 =item * $nsup->get_prefix($uri)
       
   440 
       
   441 Returns a prefix given an URI. Note that as several prefixes may be
       
   442 mapped to the same URI, it returns an arbitrary one. It'll return
       
   443 undef on failure.
       
   444 
       
   445 =item * $nsup->get_prefixes($uri)
       
   446 
       
   447 Returns an array of prefixes given an URI. It'll return all the
       
   448 prefixes if the uri is undef.
       
   449 
       
   450 =item * $nsup->get_declared_prefixes
       
   451 
       
   452 Returns an array of all the prefixes that have been declared within
       
   453 this context, ie those that were declared on the last element, not
       
   454 those that were declared above and are simply in scope.
       
   455 
       
   456 =item * $nsup->get_uri($prefix)
       
   457 
       
   458 Returns a URI for a given prefix. Returns undef on failure.
       
   459 
       
   460 =item * $nsup->process_name($qname, $is_attr)
       
   461 
       
   462 Given a qualified name and a boolean indicating whether this is an
       
   463 attribute or another type of name (those are differently affected by
       
   464 default namespaces), it returns a namespace URI, local name, qualified
       
   465 name tuple. I know that that is a rather abnormal list to return, but
       
   466 it is so for compatibility with the Java spec. See below for more
       
   467 Perlish alternatives.
       
   468 
       
   469 If the prefix is not declared, or if the name is not valid, it'll
       
   470 either die or return undef depending on the current setting of
       
   471 C<fatal_errors>.
       
   472 
       
   473 =item * $nsup->undeclare_prefix($prefix);
       
   474 
       
   475 Removes a namespace prefix from the current context. This function may
       
   476 be used in SAX's end_prefix_mapping when there is fear that a namespace 
       
   477 declaration might be available outside their scope (which shouldn't 
       
   478 normally happen, but you never know ;). This may be needed in order to
       
   479 properly support Namespace 1.1.
       
   480 
       
   481 =item * $nsup->process_element_name($qname)
       
   482 
       
   483 Given a qualified name, it returns a namespace URI, prefix, and local
       
   484 name tuple. This method applies to element names.
       
   485 
       
   486 If the prefix is not declared, or if the name is not valid, it'll
       
   487 either die or return undef depending on the current setting of
       
   488 C<fatal_errors>.
       
   489 
       
   490 =item * $nsup->process_attribute_name($qname)
       
   491 
       
   492 Given a qualified name, it returns a namespace URI, prefix, and local
       
   493 name tuple. This method applies to attribute names.
       
   494 
       
   495 If the prefix is not declared, or if the name is not valid, it'll
       
   496 either die or return undef depending on the current setting of
       
   497 C<fatal_errors>.
       
   498 
       
   499 =item * $nsup->reset
       
   500 
       
   501 Resets the object so that it can be reused on another document.
       
   502 
       
   503 =back
       
   504 
       
   505 All methods of the interface have an alias that is the name used in
       
   506 the original Java specification. You can use either name
       
   507 interchangeably. Here is the mapping:
       
   508 
       
   509   Java name                 Perl name
       
   510   ---------------------------------------------------
       
   511   pushContext               push_context
       
   512   popContext                pop_context
       
   513   declarePrefix             declare_prefix
       
   514   declarePrefixes           declare_prefixes
       
   515   getPrefix                 get_prefix
       
   516   getPrefixes               get_prefixes
       
   517   getDeclaredPrefixes       get_declared_prefixes
       
   518   getURI                    get_uri
       
   519   processName               process_name
       
   520   processElementName        process_element_name
       
   521   processAttributeName      process_attribute_name
       
   522   parseJClarkNotation       parse_jclark_notation
       
   523   undeclarePrefix           undeclare_prefix
       
   524 
       
   525 =head1 VARIABLES
       
   526 
       
   527 Two global variables are made available to you. They used to be constants but
       
   528 simple scalars are easier to use in a number of contexts. They are not
       
   529 exported but can easily be accessed from any package, or copied into it.
       
   530 
       
   531 =over 4
       
   532 
       
   533 =item * C<$NS_XMLNS>
       
   534 
       
   535 The namespace for xmlns prefixes, http://www.w3.org/2000/xmlns/.
       
   536 
       
   537 =item * C<$NS_XML>
       
   538 
       
   539 The namespace for xml prefixes, http://www.w3.org/XML/1998/namespace.
       
   540 
       
   541 =back
       
   542 
       
   543 =head1 TODO
       
   544 
       
   545  - add more tests
       
   546  - optimise here and there
       
   547 
       
   548 =head1 AUTHOR
       
   549 
       
   550 Robin Berjon, robin@knowscape.com, with lots of it having been done
       
   551 by Duncan Cameron, and a number of suggestions from the perl-xml
       
   552 list.
       
   553 
       
   554 =head1 COPYRIGHT
       
   555 
       
   556 Copyright (c) 2001 Robin Berjon. All rights reserved. This program is
       
   557 free software; you can redistribute it and/or modify it under the same
       
   558 terms as Perl itself.
       
   559 
       
   560 =head1 SEE ALSO
       
   561 
       
   562 XML::Parser::PerlSAX
       
   563 
       
   564 =cut
       
   565