/usr/share/perl5/XML/Twig/XPath.pm is in libxml-twig-perl 1:3.39-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | # $Id: /xmltwig/trunk/Twig/XPath.pm 32 2008-01-18T13:11:52.128782Z mrodrigu $
package XML::Twig::XPath;
use strict;
use XML::Twig;
my $XPATH; # XPath engine (XML::XPath or XML::XPathEngine);
my $XPATH_NUMBER; # <$XPATH>::Number, the XPath number class
BEGIN
{ foreach my $xpath_engine ( qw( XML::XPathEngine XML::XPath) )
{ if( XML::Twig::_use( $xpath_engine) ) { $XPATH= $xpath_engine; last; } }
unless( $XPATH) { die "cannot use XML::Twig::XPath: neither XML::XPathEngine 0.09+ nor XML::XPath are available"; }
$XPATH_NUMBER= "${XPATH}::Number";
}
use vars qw($VERSION);
$VERSION="0.02";
BEGIN
{ package XML::XPath::NodeSet;
no warnings; # to avoid the "Subroutine sort redefined" message
# replace the native sort routine by a Twig'd one
sub sort
{ my $self = CORE::shift;
@$self = CORE::sort { $a->node_cmp( $b) } @$self;
return $self;
}
package XML::XPathEngine::NodeSet;
no warnings; # to avoid the "Subroutine sort redefined" message
# replace the native sort routine by a Twig'd one
sub sort
{ my $self = CORE::shift;
@$self = CORE::sort { $a->node_cmp( $b) } @$self;
return $self;
}
}
package XML::Twig::XPath;
use base 'XML::Twig';
sub to_number { return $XPATH_NUMBER->new( $_[0]->root->text); }
sub new
{ my $class= shift;
my $t= XML::Twig->new( elt_class => 'XML::Twig::XPath::Elt', @_);
$t->{twig_xp}= $XPATH->new();
bless $t, $class;
return $t;
}
sub set_namespace { my $t= shift; $t->{twig_xp}->set_namespace( @_); }
sub set_strict_namespaces { my $t= shift; $t->{twig_xp}->set_strict_namespaces( @_); }
sub node_cmp($$) { return $_[1] == $_[0] ? 0 : -1; } # document is before anything but itself
sub isElementNode { 0 }
sub isAttributeNode { 0 }
sub isTextNode { 0 }
sub isProcessingInstructionNode { 0 }
sub isPINode { 0 }
sub isCommentNode { 0 }
sub isNamespaceNode { 0 }
sub getAttributes { [] }
sub getValue { return $_[0]->root->text; }
sub findnodes { my( $t, $path)= @_; return $t->{twig_xp}->findnodes( $path, $t); }
sub findnodes_as_string { my( $t, $path)= @_; return $t->{twig_xp}->findnodes_as_string( $path, $t); }
sub findvalue { my( $t, $path)= @_; return $t->{twig_xp}->findvalue( $path, $t); }
sub exists { my( $t, $path)= @_; return $t->{twig_xp}->exists( $path, $t); }
sub find { my( $t, $path)= @_; return $t->{twig_xp}->find( $path, $t); }
sub matches { my( $t, $path, $node)= @_; $node ||= $t; return $t->{twig_xp}->matches( $node, $path, $t) || 0; }
1;
# adds the appropriate methods to XML::Twig::Elt so XML::XPath can be used as the XPath engine
package XML::Twig::XPath::Elt;
use base 'XML::Twig::Elt';
*getLocalName= *XML::Twig::Elt::local_name;
*getValue = *XML::Twig::Elt::text;
sub isAttributeNode { 0 }
sub isNamespaceNode { 0 }
sub to_number { return $XPATH_NUMBER->new( $_[0]->text); }
sub getAttributes
{ my $elt= shift;
my $atts= $elt->atts;
# alternate, faster but less clean, way
my @atts= map { bless( { name => $_, value => $atts->{$_}, elt => $elt },
'XML::Twig::XPath::Attribute')
}
sort keys %$atts;
# my @atts= map { XML::Twig::XPath::Attribute->new( $elt, $_) } sort keys %$atts;
return wantarray ? @atts : \@atts;
}
sub getNamespace
{ my $elt= shift;
my $prefix= shift() || $elt->ns_prefix;
if( my $expanded= $elt->namespace( $prefix))
{ return XML::Twig::XPath::Namespace->new( $prefix, $expanded); }
else
{ return XML::Twig::XPath::Namespace->new( $prefix, ''); }
}
sub node_cmp($$)
{ my( $a, $b)= @_;
if( UNIVERSAL::isa( $b, 'XML::Twig::XPath::Elt'))
{ # 2 elts, compare them
return $a->cmp( $b);
}
elsif( UNIVERSAL::isa( $b, 'XML::Twig::XPath::Attribute'))
{ # elt <=> att, compare the elt to the att->{elt}
# if the elt is the att->{elt} (cmp return 0) then -1, elt is before att
return ($a->cmp( $b->{elt}) ) || -1 ;
}
elsif( UNIVERSAL::isa( $b, 'XML::Twig::XPath'))
{ # elt <=> document, elt is after document
return 1;
}
else
{ die "unknown node type ", ref( $b); }
}
sub getParentNode
{ return $_[0]->_parent
|| $_[0]->twig;
}
sub findnodes { my( $elt, $path)= @_; return $elt->twig->{twig_xp}->findnodes( $path, $elt); }
sub findnodes_as_string { my( $elt, $path)= @_; return $elt->twig->{twig_xp}->findnodes_as_string( $path, $elt); }
sub findvalue { my( $elt, $path)= @_; return $elt->twig->{twig_xp}->findvalue( $path, $elt); }
sub exists { my( $elt, $path)= @_; return $elt->twig->{twig_xp}->exists( $path, $elt); }
sub find { my( $elt, $path)= @_; return $elt->twig->{twig_xp}->find( $path, $elt); }
sub matches { my( $elt, $path)= @_; return $elt->twig->{twig_xp}->matches( $elt, $path, $elt->getParentNode) || 0; }
1;
# this package is only used to allow XML::XPath as the XPath engine, otherwise
# attributes are just attached to their parent element and are not considered objects
package XML::Twig::XPath::Attribute;
sub new
{ my( $class, $elt, $att)= @_;
return bless { name => $att, value => $elt->att( $att), elt => $elt }, $class;
}
sub getValue { return $_[0]->{value}; }
sub getName { return $_[0]->{name} ; }
sub getLocalName { (my $name= $_[0]->{name}) =~ s{^.*:}{}; $name; }
sub string_value { return $_[0]->{value}; }
sub to_number { return $XPATH_NUMBER->new( $_[0]->{value}); }
sub isElementNode { 0 }
sub isAttributeNode { 1 }
sub isNamespaceNode { 0 }
sub isTextNode { 0 }
sub isProcessingInstructionNode { 0 }
sub isPINode { 0 }
sub isCommentNode { 0 }
sub toString { return qq{$_[0]->{name}="$_[0]->{value}"}; }
sub getNamespace
{ my $att= shift;
my $prefix= shift();
if( ! defined( $prefix))
{ if($att->{name}=~ m{^(.*):}) { $prefix= $1; }
else { $prefix=''; }
}
if( my $expanded= $att->{elt}->namespace( $prefix))
{ return XML::Twig::XPath::Namespace->new( $prefix, $expanded); }
}
sub node_cmp($$)
{ my( $a, $b)= @_;
if( UNIVERSAL::isa( $b, 'XML::Twig::XPath::Attribute'))
{ # 2 attributes, compare their elements, then their name
return ($a->{elt}->cmp( $b->{elt}) ) || ($a->{name} cmp $b->{name});
}
elsif( UNIVERSAL::isa( $b, 'XML::Twig::XPath::Elt'))
{ # att <=> elt : compare the att->elt and the elt
# if att->elt is the elt (cmp returns 0) then 1 (elt is before att)
return ($a->{elt}->cmp( $b) ) || 1 ;
}
elsif( UNIVERSAL::isa( $b, 'XML::Twig::XPath'))
{ # att <=> document, att is after document
return 1;
}
else
{ die "unknown node type ", ref( $b); }
}
*cmp=*node_cmp;
1;
package XML::Twig::XPath::Namespace;
sub new
{ my( $class, $prefix, $expanded)= @_;
bless { prefix => $prefix, expanded => $expanded }, $class;
}
sub isNamespaceNode { 1; }
sub getPrefix { $_[0]->{prefix}; }
sub getExpanded { $_[0]->{expanded}; }
sub getValue { $_[0]->{expanded}; }
sub getData { $_[0]->{expanded}; }
1
|