Thread hash undef bei erstem Aufruf in while()?!: perplex (2 answers)
Opened by dukeofnukem at 2007-05-21 19:24

dukeofnukem
 2007-05-21 19:24
#76811 #76811
User since
2007-01-15
47 Artikel
BenutzerIn
[default_avatar]
Alohá!

Folgender Auszug aus einem selbstgebasteltem XML-Differ:

Code: (dl )
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
sub pro {
my $self = shift;

sub attr {
my $node = shift;
my $map = $node->getAttributes;

my @tmp = %$map;

while ( my ( $key, $value ) = each %$map ) {
next unless ( ref( $value ) eq 'XML::DOM::Attr' );
my $val = $value->getValue;
return "\[\@$key=\'$val\'\]";
}
return undef;
}

sub trace {
my $node = shift;
my $attr = attr($node);

# base case
if ( $node->getParentNode->getNodeType == 9 ) {
$attr ?

return "//" . $node->getNodeName . $attr :

return "//" . $node->getNodeName;
}

# return unique path
$attr ?
return trace( $node->getParentNode ) . "/" . $node->getNodeName . $attr :
return trace( $node->getParentNode ) . "/" . $node->getNodeName;
}

# "main"
my @paths = map { trace($_) } $self->{'xml1'}->findnodes( '//*' );
print join "\n", @paths;
exit;
for my $path ( @paths ) {
print "\nPath: ", $path;
for ( $self->{'xml2'}->findnodes( $path ) ) {
print "\nFound node: ", $_->getNodeName;
print "\thas Value: ", $_->getFirstChild->getNodeValue if $_->getFirstChild;
}
}
}


Hoffe das ist nicht zu unübersichtlich; habe der Vollständigkeit halber die ganze sub reingepackt.

Der Knackpunkt:
Wenn ich in attr die namedNodeMap %$map nicht vor der while-Schleife benutze (my @tmp = %$map;), ist %$map genau bei jedem zweiten Aufruf von attr mit der selben $node leer, bzw. es wird kein Attribut zurückgegeben!
So lange ich jedoch irgendeine operation auf %$map ausführe, wird immer das Attribut zurückgeliefert.

Zur Erklärung:
XML::DOM::Node
getAttributes

A NamedNodeMap containing the attributes (Attr nodes) of this node (if it is an Element) or undef otherwise. [...]
##############
XML::DOM::Attr
getValue

On retrieval, the value of the attribute is returned as a string. Character and general entity references are replaced with their values.
##############
XML::DOM::NamedNodeMap - A hash table interface for XML::DOM
DESCRIPTION ^

Objects implementing the NamedNodeMap interface are used to represent collections of nodes that can be accessed by name. [...]

Faszinierend, aber nervig.

Interessanterweise funktioniert

Code: (dl )
1
2
3
4
5
6
7
8
9
10
    sub attr {
my $node = shift;
my $map = $node->getAttributes;
for my $key ( keys %$map ) {
next unless ( ref( $$map{$key} ) eq 'XML::DOM::Attr' );
my $val = $map->getNamedItem($key)->getValue;
return "\[\@$key=\'$val\'\]";
}
return undef;
}


Zugegebenermaßen nutzt diese Variante die API von XML::DOM sehr viel sauberer (wobei das next unless immer noch nötig ist, sonst knallts mit der objectref), aber es hat mich doch etwas stutzig gemacht...

Hat dieser Aussetzer bei jedem zweiten Aufruf bei der ersten Variante was mit AUTOLOAD oder autovivification zu tun?

Klappt ja jetzt, aber mich würde interessieren woran es liegt, daß genau jeder zweite Aufruf scheitert wenn der hash nicht vorher "benutzt" wurde.

TIA!
drum&bass is a state of mind

View full thread hash undef bei erstem Aufruf in while()?!: perplex