{
    "mode": "info",
    "parameter": "HTML::Element::traverse",
    "section": "",
    "url": "https://www.chedong.com/phpMan.php/info/HTML%3A%3AElement%3A%3Atraverse/json",
    "generated": "2026-07-05T11:29:37Z",
    "synopsis": "# $element->traverse is unnecessary and obscure.\n#   Don't use it in new code.",
    "sections": {
        "NAME": {
            "content": "HTML::Element::traverse - discussion of HTML::Element's traverse method\n",
            "subsections": []
        },
        "VERSION": {
            "content": "This document describes version 5.07 of HTML::Element::traverse,\nreleased August 31, 2017 as part of HTML-Tree.\n",
            "subsections": []
        },
        "SYNOPSIS": {
            "content": "# $element->traverse is unnecessary and obscure.\n#   Don't use it in new code.\n",
            "subsections": []
        },
        "DESCRIPTION": {
            "content": "\"HTML::Element\" provides a method \"traverse\" that traverses the tree\nand calls user-specified callbacks for each node, in pre- or post-\norder.  However, use of the method is quite superfluous: if you want to\nrecursively visit every node in the tree, it's almost always simpler to\nwrite a subroutine does just that, than it is to bundle up the pre-\nand/or post-order code in callbacks for the \"traverse\" method.\n",
            "subsections": []
        },
        "EXAMPLES": {
            "content": "Suppose you want to traverse at/under a node $tree and give elements an\n'id' attribute unless they already have one.\n\nYou can use the \"traverse\" method:\n\n{\nmy $counter = 'x0000';\n$startnode->traverse(\n[ # Callbacks;\n# pre-order callback:\nsub {\nmy $x = $[0];\n$x->attr('id', $counter++) unless defined $x->attr('id');\nreturn HTML::Element::OK; # keep traversing\n},\n# post-order callback:\nundef\n],\n1, # don't call the callbacks for text nodes\n);\n}\n\nor you can just be simple and clear (and not have to understand the\ncalling format for \"traverse\") by writing a sub that traverses the tree\nby just calling itself:\n\n{\nmy $counter = 'x0000';\nsub giveid {\nmy $x = $[0];\n$x->attr('id', $counter++) unless defined $x->attr('id');\nforeach my $c ($x->contentlist) {\ngiveid($c) if ref $c; # ignore text nodes\n}\n};\ngiveid($startnode);\n}\n\nSee, isn't that nice and clear?\n\nBut, if you really need to know:\n",
            "subsections": []
        },
        "THE TRAVERSE METHOD": {
            "content": "The \"traverse()\" method is a general object-method for traversing a\ntree or subtree and calling user-specified callbacks.  It accepts the\nfollowing syntaxes:\n\n$h->traverse(\\&callback)\nor $h->traverse(\\&callback, $ignoretext)\nor $h->traverse( [\\&precallback,\\&postcallback] , $ignoretext)\n\nThese all mean to traverse the element and all of its children.  That\nis, this method starts at node $h, \"pre-order visits\" $h, traverses its\nchildren, and then will \"post-order visit\" $h.  \"Visiting\" means that\nthe callback routine is called, with these arguments:\n\n$[0] : the node (element or text segment),\n$[1] : a startflag, and\n$[2] : the depth\n\nIf the $ignoretext parameter is given and true, then the pre-order\ncall will not be happen for text content.\n\nThe startflag is 1 when we enter a node (i.e., in pre-order calls) and\n0 when we leave the node (in post-order calls).\n\nNote, however, that post-order calls don't happen for nodes that are\ntext segments or are elements that are prototypically empty (like \"br\",\n\"hr\", etc.).\n\nIf we visit text nodes (i.e., unless $ignoretext is given and true),\nthen when text nodes are visited, we will also pass two extra arguments\nto the callback:\n\n$[3] : the element that's the parent\nof this text node\n$[4] : the index of this text node\nin its parent's content list\n\nNote that you can specify that the pre-order routine can be a different\nroutine from the post-order one:\n\n$h->traverse( [\\&precallback,\\&postcallback], ...);\n\nYou can also specify that no post-order calls are to be made, by\nproviding a false value as the post-order routine:\n\n$h->traverse([ \\&precallback,0 ], ...);\n\nAnd similarly for suppressing pre-order callbacks:\n\n$h->traverse([ 0,\\&postcallback ], ...);\n\nNote that these two syntaxes specify the same operation:\n\n$h->traverse([\\&foo,\\&foo], ...);\n$h->traverse( \\&foo       , ...);\n\nThe return values from calls to your pre- or post-order routines are\nsignificant, and are used to control recursion into the tree.\n\nThese are the values you can return, listed in descending order of my\nestimation of their usefulness:\n\nHTML::Element::OK, 1, or any other true value\n...to keep on traversing.\n\nNote that \"HTML::Element::OK\" et al are constants.  So if you're\nrunning under \"use strict\" (as I hope you are), and you say:\n\"return HTML::Element::PRUEN\" the compiler will flag this as an\nerror (an unallowable bareword, specifically), whereas if you spell\nPRUNE correctly, the compiler will not complain.\n\nundef, 0, '0', '', or HTML::Element::PRUNE\n...to block traversing under the current element's content.  (This\nis ignored if received from a post-order callback, since by then\nthe recursion has already happened.)  If this is returned by a pre-\norder callback, no post-order callback for the current node will\nhappen.  (Recall that if your callback exits with just \"return;\",\nit is returning undef -- at least in scalar context, and \"traverse\"\nalways calls your callbacks in scalar context.)\n\nHTML::Element::ABORT\n...to abort the whole traversal immediately.  This is often useful\nwhen you're looking for just the first node in the tree that meets\nsome criterion of yours.\n\nHTML::Element::PRUNEUP\n...to abort continued traversal into this node and its parent node.\nNo post-order callback for the current or parent node will happen.\n\nHTML::Element::PRUNESOFTLY\nLike PRUNE, except that the post-order call for the current node is\nnot blocked.\n\nAlmost every task to do with extracting information from a tree can be\nexpressed in terms of traverse operations (usually in only one pass,\nand usually paying attention to only pre-order, or to only post-order),\nor operations based on traversing. (In fact, many of the other methods\nin this class are basically calls to traverse() with particular\narguments.)\n\nThe source code for HTML::Element and HTML::TreeBuilder contain several\nexamples of the use of the \"traverse\" method to gather information\nabout the content of trees and subtrees.\n\n(Note: you should not change the structure of a tree while you are\ntraversing it.)\n\n[End of documentation for the \"traverse()\" method]\n\nTraversing with Recursive Anonymous Routines\nNow, if you've been reading Structure and Interpretation of Computer\nPrograms too much, maybe you even want a recursive lambda.  Go ahead:\n\n{\nmy $counter = 'x0000';\nmy $giveid;\n$giveid = sub {\nmy $x = $[0];\n$x->attr('id', $counter++) unless defined $x->attr('id');\nforeach my $c ($x->contentlist) {\n$giveid->($c) if ref $c; # ignore text nodes\n}\n};\n$giveid->($startnode);\nundef $giveid;\n}\n\nIt's a bit nutty, and it's still more concise than a call to the\n\"traverse\" method!\n\nIt is left as an exercise to the reader to figure out how to do the\nsame thing without using a $giveid symbol at all.\n\nIt is also left as an exercise to the reader to figure out why I\nundefine $giveid, above; and why I could achieved the same effect with\nany of:\n\n$giveid = 'I like pie!';\n# or...\n$giveid = [];\n# or even;\n$giveid = sub { print \"Mmmm pie!\\n\" };\n\nBut not:\n\n$giveid = sub { print \"I'm $giveid and I like pie!\\n\" };\n# nor...\n$giveid = \\$giveid;\n# nor...\n$giveid = { 'pie' => \\$giveid, 'mode' => 'a la' };\n\nDoing Recursive Things Iteratively\nNote that you may at times see an iterative implementation of pre-order\ntraversal, like so:\n\n{\nmy @todo = ($tree); # start-node\nwhile(@todo) {\nmy $this = shift @todo;\n\n# \"Visit\" the node:\n$this->attr('id', $counter++)\nunless defined $this->attr('id');\n\nunshift @todo, grep ref $, $this->contentlist;\n# Put children on the stack -- they'll be visited next\n}\n}\n\nThis can under certain circumstances be more efficient than just a\nnormal recursive routine, but at the cost of being rather obscure.  It\ngains efficiency by avoiding the overhead of function-calling, but\nsince there are several method dispatches however you do it (to \"attr\"\nand \"contentlist\"), the overhead for a simple function call is\ninsignificant.\n\nPruning and Whatnot\nThe \"traverse\" method does have the fairly neat features of the\n\"ABORT\", \"PRUNEUP\" and \"PRUNESOFTLY\" signals.  None of these can be\nimplemented totally straightforwardly with recursive routines, but it\nis quite possible.  \"ABORT\"-like behavior can be implemented either\nwith using non-local returning with \"eval\"/\"die\":\n\nmy $diedon; # if you need to know where...\nsub thing {\n... visits $[0]...\n... maybe set $diedon to $[0] and die \"ABORTTRAV\" ...\n... else call thing($child) for each child...\n...any post-order visiting $[0]...\n}\neval { thing($node) };\nif($@) {\nif($@ =~ m<^ABORTTRAV>) {\n...it died (aborted) on $diedon...\n} else {\ndie $@; # some REAL error happened\n}\n}\n\nor you can just do it with flags:\n\nmy($abortflag, $diedon);\nsub thing {\n... visits $[0]...\n... maybe set $abortflag = 1; $diedon = $[0]; return;\nforeach my $c ($[0]->contentlist) {\nthing($c);\nreturn if $abortflag;\n}\n...any post-order visiting $[0]...\nreturn;\n}\n\n$abortflag = $diedon = undef;\nthing($node);\n...if defined $abortflag, it died on $diedon\n",
            "subsections": []
        },
        "SEE ALSO": {
            "content": "HTML::Element\n",
            "subsections": []
        },
        "AUTHOR": {
            "content": "Current maintainers:\n\no   Christopher J. Madsen \"<perl AT cjmweb.net>\"\n\no   Jeff Fearn \"<jfearn AT cpan.org>\"\n\nOriginal HTML-Tree author:\n\no   Gisle Aas\n\nFormer maintainers:\n\no   Sean M. Burke\n\no   Andy Lester\n\no   Pete Krawczyk \"<petek AT cpan.org>\"\n\nYou can follow or contribute to HTML-Tree's development at\n<https://github.com/kentfredric/HTML-Tree>.\n",
            "subsections": []
        },
        "COPYRIGHT": {
            "content": "Copyright 2000,2001 Sean M. Burke\n\nperl v5.28.1                      2019-01-13      HTML::Element::traverse(3pm)",
            "subsections": []
        }
    },
    "summary": "HTML::Element::traverse - discussion of HTML::Element's traverse method",
    "flags": [],
    "examples": [
        "Suppose you want to traverse at/under a node $tree and give elements an",
        "'id' attribute unless they already have one.",
        "You can use the \"traverse\" method:",
        "my $counter = 'x0000';",
        "$startnode->traverse(",
        "[ # Callbacks;",
        "# pre-order callback:",
        "sub {",
        "my $x = $[0];",
        "$x->attr('id', $counter++) unless defined $x->attr('id');",
        "return HTML::Element::OK; # keep traversing",
        "},",
        "# post-order callback:",
        "undef",
        "],",
        "1, # don't call the callbacks for text nodes",
        ");",
        "or you can just be simple and clear (and not have to understand the",
        "calling format for \"traverse\") by writing a sub that traverses the tree",
        "by just calling itself:",
        "my $counter = 'x0000';",
        "sub giveid {",
        "my $x = $[0];",
        "$x->attr('id', $counter++) unless defined $x->attr('id');",
        "foreach my $c ($x->contentlist) {",
        "giveid($c) if ref $c; # ignore text nodes",
        "};",
        "giveid($startnode);",
        "See, isn't that nice and clear?",
        "But, if you really need to know:"
    ],
    "see_also": []
}