sub
new {
my
(
$class
,
$init
) =
@_
;
$init
= {}
unless
defined
(
$init
);
return
bless
$init
,
$class
;
}
sub
add_child {
my
(
$self
,
$child
) =
@_
;
if
(Konstrukt::Debug::WARNING and
ref
(
$child
) ne
"Konstrukt::Parser::Node"
) {
$Konstrukt::Debug
->error_message(
"Child is no Konstrukt::Parser::Node!"
);
return
undef
;
}
if
(not
defined
(
$self
->{first_child})) {
$self
->{first_child} =
$self
->{last_child} =
$child
;
$child
->{prev} =
$child
->{
next
} =
undef
;
}
else
{
$child
->{prev} =
$self
->{last_child};
$child
->{
next
} =
undef
;
$self
->{last_child} =
$self
->{last_child}->{
next
} =
$child
;
}
$child
->{parent} =
$self
;
}
sub
delete
{
my
(
$self
) =
@_
;
my
$parent
=
$self
->{parent};
if
(
defined
$parent
) {
$parent
->{first_child} =
$self
->{
next
}
if
$parent
->{first_child} eq
$self
;
$parent
->{last_child} =
$self
->{prev}
if
$parent
->{last_child} eq
$self
;
}
$self
->{
next
}->{prev} =
$self
->{prev}
if
defined
(
$self
->{
next
});
$self
->{prev}->{
next
} =
$self
->{
next
}
if
defined
(
$self
->{prev});
}
sub
append {
my
(
$self
,
$node
) =
@_
;
if
(Konstrukt::Debug::WARNING and
ref
(
$node
) ne
"Konstrukt::Parser::Node"
) {
$Konstrukt::Debug
->error_message(
"Node is no Konstrukt::Parser::Node!"
);
return
undef
;
}
$self
->{parent}->{last_child} =
$node
if
defined
$self
->{parent} and
$self
->{parent}->{last_child} eq
$self
;
$node
->{parent} =
$self
->{parent};
$node
->{
next
} =
$self
->{
next
};
$node
->{prev} =
$self
;
$self
->{
next
}->{prev} =
$node
if
defined
$self
->{
next
};
$self
->{
next
} =
$node
;
}
sub
prepend {
my
(
$self
,
$node
) =
@_
;
if
(Konstrukt::Debug::WARNING and
ref
(
$node
) ne
"Konstrukt::Parser::Node"
) {
$Konstrukt::Debug
->error_message(
"Node is no Konstrukt::Parser::Node!"
);
return
undef
;
}
$self
->{parent}->{first_child} =
$node
if
defined
$self
->{parent} and
$self
->{parent}->{first_child} eq
$self
;
$node
->{parent} =
$self
->{parent};
$node
->{
next
} =
$self
;
$node
->{prev} =
$self
->{prev};
$self
->{prev}->{
next
} =
$node
if
defined
$self
->{prev};
$self
->{prev} =
$node
;
}
sub
replace_by_node {
my
(
$self
,
$node
) =
@_
;
return
if
$node
eq
$self
;
if
(Konstrukt::Debug::WARNING and
ref
(
$node
) ne
"Konstrukt::Parser::Node"
) {
$Konstrukt::Debug
->error_message(
"Node is no Konstrukt::Parser::Node!"
);
return
undef
;
}
$node
->
delete
();
$node
->{parent} =
$self
->{parent};
$node
->{prev} =
$self
->{prev};
$node
->{
next
} =
$self
->{
next
};
$self
->{parent}->{first_child} =
$node
if
$self
->{parent}->{first_child} eq
$self
;
$self
->{parent}->{last_child} =
$node
if
$self
->{parent}->{last_child} eq
$self
;
$self
->{prev}->{
next
} =
$node
if
defined
$self
->{prev};
$self
->{
next
}->{prev} =
$node
if
defined
$self
->{
next
};
}
sub
replace_by_children {
my
(
$self
) =
@_
;
if
(
defined
$self
->{first_child}) {
$self
->{parent}->{first_child} =
$self
->{first_child}
if
defined
$self
->{parent} and
$self
->{parent}->{first_child} eq
$self
;
$self
->{parent}->{last_child} =
$self
->{last_child}
if
defined
$self
->{parent} and
$self
->{parent}->{last_child} eq
$self
;
$self
->{prev}->{
next
} =
$self
->{first_child}
if
defined
$self
->{prev};
$self
->{
next
}->{prev} =
$self
->{last_child}
if
defined
$self
->{
next
};
$self
->{first_child}->{prev} =
$self
->{prev}
if
defined
$self
->{first_child};
$self
->{last_child}->{
next
} =
$self
->{
next
}
if
defined
$self
->{last_child};
my
$node
=
$self
->{first_child};
while
(
defined
$node
) {
$node
->{parent} =
$self
->{parent};
$node
=
$node
->{
next
};
}
}
else
{
$self
->
delete
();
}
}
sub
move_children {
my
(
$self
,
$dest
) =
@_
;
my
$node
=
$self
->{first_child};
while
(
defined
$node
) {
my
$next_node
=
$node
->{
next
};
$dest
->add_child(
$node
);
$node
=
$next_node
;
}
$self
->{first_child} =
$self
->{last_child} =
undef
;
}
sub
children_to_string {
my
(
$self
) =
@_
;
my
$result
=
''
;
my
$node
=
$self
->{first_child};
while
(
defined
$node
) {
if
((
$node
->{type} eq
'plaintext'
or
$node
->{type} eq
'comment'
) and
defined
$node
->{content}) {
$result
.=
$node
->{content};
}
$node
=
$node
->{
next
};
}
return
$result
;
}
sub
tree_to_string {
my
(
$self
,
$depth
) =
@_
;
$depth
||= 0;
my
$result
=
''
;
if
(
$self
->{type} eq
'root'
) {
$result
.=
"* root\n"
;
}
elsif
(
$self
->{type} eq
'plaintext'
or
$self
->{type} eq
'comment'
) {
$result
.= (
" "
x
$depth
) .
"* "
.
$self
->{type} .
": "
.
$self
->{content} .
"\n"
;
}
elsif
(
$self
->{type} eq
'dummy'
) {
$result
.= (
" "
x
$depth
) .
"* dummy\n"
;
}
elsif
(
$self
->{type} eq
'tag'
) {
if
(
exists
$self
->{content}->{preliminary}) {
$result
.= (
" "
x
$depth
) .
"* "
.
$self
->{type} .
": (preliminary) - type: "
. (
defined
(
$self
->{handler_type}) ?
$self
->{handler_type} :
"(no handler type)"
) .
" - executionstage: "
. (
$self
->{content}->{executionstage} ||
$self
->{content}->{tag}->{attributes}->{executionstage} ||
"(not defined)"
) .
"\n"
;
$result
.= (
" "
x
$depth
) .
" children inside this tag:\n"
;
$result
.=
$self
->{content}->tree_to_string(
$depth
+ 1);
}
else
{
$result
.= (
" "
x
$depth
) .
"* "
.
$self
->{type} .
": (final) - type: "
. (
defined
(
$self
->{handler_type}) ?
$self
->{handler_type} :
"(no handler type)"
) .
" "
. (
$self
->{tag}->{type} ||
"(none)"
) .
" - dynamic: "
. (
defined
(
$self
->{dynamic}) ? 1 : 0) .
" - executionstage: "
. (
defined
(
$self
->{dynamic}) ?
$self
->{executionstage} ||
$self
->{tag}->{attributes}->{executionstage} ||
"(not defined)"
:
"(not defined - no dynamic tag)"
) .
"\n"
;
}
}
if
((
$self
->{type} eq
'tag'
or
$self
->{type} eq
'root'
or
$self
->{type} eq
'tagcontent'
) and
defined
$self
->{first_child}) {
$result
.= (
" "
x
$depth
) .
" children below this tag:\n"
unless
$self
->{type} eq
'tagcontent'
;
my
$node
=
$self
->{first_child};
while
(
defined
$node
) {
$result
.=
$node
->tree_to_string(
$depth
+ 1);
$node
=
$node
->{
next
};
}
}
return
$result
;
}
sub
remove_cross_references {
my
(
$self
) =
@_
;
my
@deleted
= (
$self
->{parent},
$self
->{prev});
delete
(
$self
->{parent});
delete
(
$self
->{prev});
delete
(
$self
->{last_child});
my
$node
=
$self
->{first_child};
while
(
defined
$node
) {
$node
->remove_cross_references();
$node
=
$node
->{
next
};
}
return
@deleted
;
}
sub
restore_cross_references {
my
(
$self
,
$parent
,
$prev
) =
@_
;
$self
->{parent} =
$parent
;
$self
->{prev} =
$prev
;
my
$node
=
$self
->{first_child};
my
$last_node
=
undef
;
while
(
defined
$node
) {
$node
->restore_cross_references(
$self
,
$last_node
);
$last_node
=
$node
;
$node
=
$node
->{
next
};
}
$self
->{last_child} =
$last_node
if
defined
$last_node
;
}
1;