=head1 NAME Message::Markup::XML::Node --- manakai XML : XML Node Implementation =head1 DESCRIPTION This module implements the XML Node object. This module is part of manakai XML. =cut package Message::Markup::XML::NodeTree; use strict; our $VERSION = do{my @r=(q$Revision: 1.3 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r}; use Message::Markup::XML::Node; use Message::Markup::XML::QName qw/:prefix :special-uri/; use Exporter; push our @ISA, 'Exporter'; our @EXPORT_OK = qw/construct_xml_tree/; =head1 METHODS =over 4 =cut sub construct_xml_tree (%); sub construct_xml_tree (%) { my %opt = @_; my $parent = $opt{parent} || 'Message::Markup::XML::Node'; my $method = ref $opt{parent} ? 'append_new_node' : 'new'; my $node = $parent->$method (map {$_=>$opt{$_}} grep /^[^-]/, keys %opt); for (keys %{$opt{-attr}||{}}) { $node->set_attribute ($_ => $opt{-attr}->{$_}); } for (@{$opt{-child}||[]}) { construct_xml_tree (%$_, parent => $node); } for (keys %{$opt{-ns}||{}}) { $node->{ns}->{ $_ || ($_ eq '0' ? '0' : DEFAULT_PFX) } = $opt{-ns}->{$_} || ($opt{-ns}->{$_} eq '0' ? ZERO_URI : NULL_URI); } $node; } #------- Not (re-)Implemented Yet ------- my %NS; sub merge_external_subset ($) { my $self = shift; unless ($self->{type} eq '#declaration' && $self->{namespace_uri} eq $NS{SGML}.'doctype') { return unless $self->{type} eq '#document' || $self->{type} eq '#fragment'; for (@{$self->{node}}) { $_->merge_external_subset; } return; } my $xsub = $self->get_attribute ('external-subset'); return unless ref $xsub; for (@{$xsub->{node}}) { $_->{parent} = $self; } push @{$self->{node}}, @{$xsub->{node}}; $self->remove_child_node ($xsub); $self->remove_child_node ($self->get_attribute ('PUBLIC')); $self->remove_child_node ($self->get_attribute ('SYSTEM')); $self->remove_marked_section; } sub remove_marked_section ($) { my $self = shift; my @node; for (@{$self->{node}}) { if ({qw/#declaration 1 #element 1 #section 1 #reference 1 #attribute 1 #document 1 #fragment 1/}->{$_->{type}}) { $_->remove_marked_section; } } for (@{$self->{node}}) { if ($_->{type} ne '#section') { push @node, $_; } else { my $status = $_->get_attribute ('status', make_new_node => 1)->inner_text; if ($status eq 'CDATA') { $_->{type} = '#text'; $_->remove_attribute ('status'); push @node, $_; } elsif ($status ne 'IGNORE') { # INCLUDE for my $e (@{$_->{node}}) { if ($e->{type} ne '#attribute') { $e->{parent} = $self; push @node, $e; } } } } } $self->{node} = \@node; } ## TODO: references in EntityValue sub remove_references ($) { my $self = shift; my @node; for (@{$self->{node}}) { if ({qw/#declaration 1 #element 1 #section 1 #reference 1 #attribute 1 #document 1 #fragment 1/}->{$_->{type}}) { $_->remove_references; } } for (@{$self->{node}}) { if ($_->{type} ne '#reference' || ($self->{type} eq '#declaration' && $_->{namespace_uri} eq $NS{SGML}.'entity')) { push @node, $_; } else { if (index ($_->{namespace_uri}, 'char') > -1) { my $e = ref ($_)->new (type => '#text', value => chr $_->{value}); $e->{parent} = $self; push @node, $e; } elsif ($_->{flag}->{smxp__ref_expanded}) { for my $e (@{$_->{node}}) { if ($e->{type} ne '#attribute') { $e->{parent} = $self; push @node, $e; } } } else { ## reference is not expanded push @node, $_; } } $_->{flag}->{smxp__defined_with_param_ref} = 0 if $_->{flag}->{smxp__defined_with_param_ref} && !$_->{flag}->{smxp__non_processed_declaration}; } $self->{node} = \@node; } sub resolve_relative_uri ($;$%) { require URI; my ($self, $rel, %o) = @_; my $base = $self->get_attribute ('base', namespace_uri => $NS{xml}); $base = ref ($base) ? $base->inner_text : $NS{default_base_uri}; if ($base !~ /^[0-9A-Za-z.%+-]+:/) { # $base is relative $base = $self->Message::Markup::XML::NodeTree::_resolve_relative_uri_by_parent ($base, \%o); } eval q{ ## Catch error such as $base is 'data:,foo' (non hierarchic scheme,...) return URI->new ($rel)->abs ($base || '.'); ## BUG (or spec) of URI: $base == false } or return $rel; } sub _resolve_relative_uri_by_parent ($$$) { my ($self, $rel, $o) = @_; if (ref $self->{parent}) { if (!$o->{use_references_base_uri} && $self->{parent}->{type} eq '#reference') { ## This case is necessary to work with ## ## text ## &ent; ## ## entity's text ## ## return $self->{parent}->_resolve_relative_uri_by_parent ($rel, $o); } else { return $self->{parent}->resolve_relative_uri ($rel, %$o); } } else { return $rel; } } sub root_node ($) { my $self = shift; if ($self->{type} eq '#document') { return $self; } elsif (ref $self->{parent}) { return $self->{parent}->root_node; } else { return $self; } } sub _get_entity_manager ($) { my $self = shift; if ($self->{type} eq '#document') { unless ($self->{flag}->{smx__entity_manager}) { require Message::Markup::XML::EntityManager; $self->{flag}->{smx__entity_manager} = Message::Markup::XML::EntityManager->new ($self); } return $self->{flag}->{smx__entity_manager}; } elsif (ref $self->{parent}) { return $self->{parent}->_get_entity_manager; } else { unless ($self->{flag}->{smx__entity_manager}) { require Message::Markup::XML::EntityManager; $self->{flag}->{smx__entity_manager} = Message::Markup::XML::EntityManager->new ($self); } return $self->{flag}->{smx__entity_manager}; } } =head1 LICENSE Copyright 2003 Wakaba This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; # $Date: 2004/02/22 01:46:23 $