📄 node.pm
字号:
# $Id: Node.pm 4532 2004-05-11 05:15:40Z ezra $package XML::XPath::Node;use strict;use vars qw(@ISA @EXPORT $AUTOLOAD %EXPORT_TAGS @EXPORT_OK);use Exporter;use Carp;@ISA = ('Exporter');sub UNKNOWN_NODE () {0;}sub ELEMENT_NODE () {1;}sub ATTRIBUTE_NODE () {2;}sub TEXT_NODE () {3;}sub CDATA_SECTION_NODE () {4;}sub ENTITY_REFERENCE_NODE () {5;}sub ENTITY_NODE () {6;}sub PROCESSING_INSTRUCTION_NODE () {7;}sub COMMENT_NODE () {8;}sub DOCUMENT_NODE () {9;}sub DOCUMENT_TYPE_NODE () {10;}sub DOCUMENT_FRAGMENT_NODE () {11;}sub NOTATION_NODE () {12;}# Non core DOM stuffsub ELEMENT_DECL_NODE () {13;}sub ATT_DEF_NODE () {14;}sub XML_DECL_NODE () {15;}sub ATTLIST_DECL_NODE () {16;}sub NAMESPACE_NODE () {17;}# per-node constants# Allsub node_parent () { 0; }sub node_pos () { 1; }sub node_global_pos () { 2; }# Elementsub node_prefix () { 3; }sub node_children () { 4; }sub node_name () { 5; }sub node_attribs () { 6; }sub node_namespaces () { 7; }sub node_ids () { 8; }# Charsub node_text () { 3; }# PIsub node_target () { 3; }sub node_data () { 4; }# Commentsub node_comment () { 3; }# Attribute# sub node_prefix () { 3; }sub node_key () { 4; }sub node_value () { 5; }# Namespaces# sub node_prefix () { 3; }sub node_expanded () { 4; }@EXPORT = qw( UNKNOWN_NODE ELEMENT_NODE ATTRIBUTE_NODE TEXT_NODE CDATA_SECTION_NODE ENTITY_REFERENCE_NODE ENTITY_NODE PROCESSING_INSTRUCTION_NODE COMMENT_NODE DOCUMENT_NODE DOCUMENT_TYPE_NODE DOCUMENT_FRAGMENT_NODE NOTATION_NODE ELEMENT_DECL_NODE ATT_DEF_NODE XML_DECL_NODE ATTLIST_DECL_NODE NAMESPACE_NODE );@EXPORT_OK = qw( node_parent node_pos node_global_pos node_prefix node_children node_name node_attribs node_namespaces node_text node_target node_data node_comment node_key node_value node_expanded node_ids );%EXPORT_TAGS = ( 'node_keys' => [ qw( node_parent node_pos node_global_pos node_prefix node_children node_name node_attribs node_namespaces node_text node_target node_data node_comment node_key node_value node_expanded node_ids ), @EXPORT, ],);my $global_pos = 0;sub nextPos { my $class = shift; return $global_pos += 5;}sub resetPos { $global_pos = 0;}my %DecodeDefaultEntity =( '"' => """, ">" => ">", "<" => "<", "'" => "'", "&" => "&");sub XMLescape { my ($str, $default) = @_; return undef unless defined $str; $default ||= ''; if ($XML::XPath::EncodeUtf8AsEntity) { $str =~ s/([\xC0-\xDF].|[\xE0-\xEF]..|[\xF0-\xFF]...)|([$default])|(]]>)/ defined($1) ? XmlUtf8Decode ($1) : defined ($2) ? $DecodeDefaultEntity{$2} : "]]>" /egsx; } else { $str =~ s/([$default])|(]]>)/ defined ($1) ? $DecodeDefaultEntity{$1} : ']]>' /gsex; }#?? could there be references that should not be expanded?# e.g. should not replace &#nn; ¯ and &abc;# $str =~ s/&(?!($ReName|#[0-9]+|#x[0-9a-fA-F]+);)/&/go; $str;}## Opposite of XmlUtf8Decode plus it adds prefix "&#" or "&#x" and suffix ";"# The 2nd parameter ($hex) indicates whether the result is hex encoded or not.#sub XmlUtf8Decode{ my ($str, $hex) = @_; my $len = length ($str); my $n; if ($len == 2) { my @n = unpack "C2", $str; $n = (($n[0] & 0x3f) << 6) + ($n[1] & 0x3f); } elsif ($len == 3) { my @n = unpack "C3", $str; $n = (($n[0] & 0x1f) << 12) + (($n[1] & 0x3f) << 6) + ($n[2] & 0x3f); } elsif ($len == 4) { my @n = unpack "C4", $str; $n = (($n[0] & 0x0f) << 18) + (($n[1] & 0x3f) << 12) + (($n[2] & 0x3f) << 6) + ($n[3] & 0x3f); } elsif ($len == 1) { # just to be complete... $n = ord ($str); } else { die "bad value [$str] for XmlUtf8Decode"; } $hex ? sprintf ("&#x%x;", $n) : "&#$n;";}sub new { my $class = shift; no strict 'refs'; my $impl = $class . "Impl"; my $this = $impl->new(@_); if ($XML::XPath::SafeMode) { return $this; } my $self = \$this; return bless $self, $class;}sub AUTOLOAD { my $method = $AUTOLOAD; $method =~ s/.*:://;# warn "AUTOLOAD $method!\n"; no strict 'refs'; *{$AUTOLOAD} = sub { my $self = shift; my $olderror = $@; # store previous exceptions my $obj = eval { $$self }; if ($@) { if ($@ =~ /Not a SCALAR reference/) { croak("No such method $method in " . ref($self)); } croak $@; } if ($obj) { # make sure $@ propogates if this method call was the result # of losing scope because of a die(). if ($method =~ /^(DESTROY|del_parent_link)$/) { $obj->$method(@_); $@ = $olderror if $olderror; return; } return $obj->$method(@_); } }; goto &$AUTOLOAD;}package XML::XPath::NodeImpl;use vars qw/@ISA $AUTOLOAD/;@ISA = ('XML::XPath::Node');sub new { die "Virtual base method";}sub getNodeType { my $self = shift; return XML::XPath::Node::UNKNOWN_NODE;}sub isElementNode {}sub isAttributeNode {}sub isNamespaceNode {}sub isTextNode {}sub isProcessingInstructionNode {}sub isPINode {}sub isCommentNode {}sub getNodeValue { return;}sub getValue { shift->getNodeValue(@_);}sub setNodeValue { return;}sub setValue { shift->setNodeValue(@_);}sub getParentNode { my $self = shift; return $self->[XML::XPath::Node::node_parent];}sub getRootNode { my $self = shift; while (my $parent = $self->getParentNode) { $self = $parent; } return $self;}sub getElementById { my $self = shift; my ($id) = @_;# warn "getElementById: $id\n"; my $root = $self->getRootNode; my $node = $root->[XML::XPath::Node::node_ids]{$id};# warn "returning node: ", $node->getName, "\n"; return $node;}sub getName { }sub getData { }sub getChildNodes { return wantarray ? () : [];}sub getChildNode { return;}sub getAttribute { return;}sub getAttributes { return wantarray ? () : [];}sub getAttributeNodes { shift->getAttributes(@_);}sub getNamespaceNodes { return wantarray ? () : [];}sub getNamespace { return;}sub getLocalName { return;}sub string_value { return; }sub get_pos { my $self = shift; return $self->[XML::XPath::Node::node_pos];}sub set_pos { my $self = shift; $self->[XML::XPath::Node::node_pos] = shift;}sub get_global_pos { my $self = shift; return $self->[XML::XPath::Node::node_global_pos];}sub set_global_pos { my $self = shift; $self->[XML::XPath::Node::node_global_pos] = shift;}sub renumber { my $self = shift; my $search = shift; my $diff = shift; foreach my $node ($self->findnodes($search)) { $node->set_global_pos( $node->get_global_pos + $diff ); }} sub insertAfter { my $self = shift; my $newnode = shift; my $posnode = shift; my $pos_number = eval { $posnode->[XML::XPath::Node::node_children][-1]->get_global_pos() + 1; }; if (!defined $pos_number) { $pos_number = $posnode->get_global_pos() + 1; } eval { if ($pos_number == $posnode->findnodes( 'following::node()' )->get_node(1)->get_global_pos()) { $posnode->renumber('following::node()', +5); } }; my $pos = $posnode->get_pos; $newnode->setParentNode($self); splice @{$self->[XML::XPath::Node::node_children]}, $pos + 1, 0, $newnode; for (my $i = $pos + 1; $i < @{$self->[XML::XPath::Node::node_children]}; $i++) { $self->[XML::XPath::Node::node_children][$i]->set_pos($i); } $newnode->set_global_pos($pos_number);}sub insertBefore { my $self = shift; my $newnode = shift; my $posnode = shift; my $pos_number = ($posnode->getPreviousSibling() || $posnode->getParentNode)->get_global_pos(); if ($pos_number == $posnode->get_global_pos()) { $posnode->renumber('self::node() | descendant::node() | following::node()', +5); } my $pos = $posnode->get_pos; $newnode->setParentNode($self); splice @{$self->[XML::XPath::Node::node_children]}, $pos, 0, $newnode; for (my $i = $pos; $i < @{$self->[XML::XPath::Node::node_children]}; $i++) { $self->[XML::XPath::Node::node_children][$i]->set_pos($i); } $newnode->set_global_pos($pos_number);}sub getPreviousSibling { my $self = shift; my $pos = $self->[XML::XPath::Node::node_pos]; return unless $self->[XML::XPath::Node::node_parent]; return $self->[XML::XPath::Node::node_parent]->getChildNode($pos);}sub getNextSibling { my $self = shift; my $pos = $self->[XML::XPath::Node::node_pos]; return unless $self->[XML::XPath::Node::node_parent]; return $self->[XML::XPath::Node::node_parent]->getChildNode($pos + 2);}sub setParentNode { my $self = shift; my $parent = shift;# warn "SetParent of ", ref($self), " to ", $parent->[XML::XPath::Node::node_name], "\n"; $self->[XML::XPath::Node::node_parent] = $parent;}sub del_parent_link { my $self = shift; $self->[XML::XPath::Node::node_parent] = undef;}sub dispose { my $self = shift; foreach my $kid ($self->getChildNodes) { $kid->dispose; } foreach my $kid ($self->getAttributeNodes) { $kid->dispose; } foreach my $kid ($self->getNamespaceNodes) { $kid->dispose; } $self->[XML::XPath::Node::node_parent] = undef;}sub to_number { my $num = shift->string_value; return XML::XPath::Number->new($num);}sub find { my $node = shift; my ($path) = @_; my $xp = XML::XPath->new(); # new is v. lightweight return $xp->find($path, $node);}sub findvalue { my $node = shift; my ($path) = @_; my $xp = XML::XPath->new(); return $xp->findvalue($path, $node);}sub findnodes { my $node = shift; my ($path) = @_; my $xp = XML::XPath->new(); return $xp->findnodes($path, $node);}sub matches { my $node = shift; my ($path, $context) = @_; my $xp = XML::XPath->new(); return $xp->matches($node, $path, $context);}sub to_sax { my $self = shift; unshift @_, 'Handler' if @_ == 1; my %handlers = @_; my $doch = $handlers{DocumentHandler} || $handlers{Handler}; my $dtdh = $handlers{DTDHandler} || $handlers{Handler}; my $enth = $handlers{EntityResolver} || $handlers{Handler}; $self->_to_sax ($doch, $dtdh, $enth);}sub DESTROY {}use Carp;sub _to_sax { carp "_to_sax not implemented in ", ref($_[0]);}1;__END__=head1 NAMEXML::XPath::Node - internal representation of a node=head1 APIThe Node API aims to emulate DOM to some extent, however the APIisn't quite compatible with DOM. This is to ease transition fromXML::DOM programming to XML::XPath. Compatibility with DOM mayarise once XML::DOM gets namespace support.=head2 newCreates a new node. See the sub-classes for parameters to pass to new().=head2 getNodeTypeReturns one of ELEMENT_NODE, TEXT_NODE, COMMENT_NODE, ATTRIBUTE_NODE,PROCESSING_INSTRUCTION_NODE or NAMESPACE_NODE. UNKNOWN_NODE is returnedif the sub-class doesn't implement getNodeType - but that meanssomething is broken! The constants are exported by default fromXML::XPath::Node. The constants have the same numeric value as theXML::DOM versions.=head2 getParentNodeReturns the parent of this node, or undef if this is the root node. Notethat the root node is the root node in terms of XPath - not the rootelement node.=head2 to_sax ( $handler | %handlers )Generates sax calls to the handler or handlers. See the PerlSAX docs fordetails (not yet implemented correctly).=head1 MORE INFOSee the sub-classes for the meaning of the rest of the API:=over 4=item *L<XML::XPath::Node::Element>=item *L<XML::XPath::Node::Attribute>=item *L<XML::XPath::Node::Namespace>=item *L<XML::XPath::Node::Text>=item *L<XML::XPath::Node::Comment>=item *L<XML::XPath::Node::PI>=back=cut
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -