handler = $handler; $this->callback = $callback; $this->verbosity = $verbosity; } /** * Send a message */ private function trace( $msg ) { call_user_func( $this->callback, "[Tree] $msg" ); } /** * Get a debug tag for an element or null * * @param Element|null $element */ private function getDebugTag( $element ) { return $element ? $element->getDebugTag() : ''; } /** * Get a short excerpt of some text * * @param string $text * @return string */ private function excerpt( $text ) { if ( strlen( $text ) > 20 ) { $text = substr( $text, 0, 20 ) . '...'; } return str_replace( "\n", "\\n", $text ); } /** * Get a readable version of the TreeBuilder preposition constants */ private function getPrepositionName( $prep ) { $names = [ TreeBuilder::BEFORE => 'before', TreeBuilder::UNDER => 'under', TreeBuilder::ROOT => 'under root' ]; return isset( $names[$prep] ) ? $names[$prep] : '???'; } /** * A helper called before the underlying handler is called. */ private function before() { if ( $this->verbosity > 0 ) { $this->trace( "Before: " . $this->handler->dump() . "\n" ); } } /** * A helper called after the underlying handler is called. */ private function after() { if ( $this->verbosity > 0 ) { $this->trace( "After: " . $this->handler->dump() . "\n" ); } } public function startDocument( $fns, $fn ) { $this->trace( "startDocument" ); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); } public function endDocument( $pos ) { $this->trace( "endDocument $pos" ); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); } public function characters( $preposition, $refNode, $text, $start, $length, $sourceStart, $sourceLength ) { $excerpt = $this->excerpt( substr( $text, $start, $length ) ); $prepName = $this->getPrepositionName( $preposition ); $refTag = $this->getDebugTag( $refNode ); $this->trace( "characters \"$excerpt\", $prepName $refTag, start=$sourceStart" ); $this->before(); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); $this->after(); } public function insertElement( $preposition, $refNode, Element $element, $void, $sourceStart, $sourceLength ) { $prepName = $this->getPrepositionName( $preposition ); $refTag = $this->getDebugTag( $refNode ); $elementTag = $this->getDebugTag( $element ); $voidMsg = $void ? 'void' : ''; $this->trace( "insert $elementTag $voidMsg, $prepName $refTag, start=$sourceStart" ); $this->before(); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); $this->after(); } public function endTag( Element $element, $sourceStart, $sourceLength ) { $elementTag = $this->getDebugTag( $element ); $this->trace( "end $elementTag, start=$sourceStart" ); $this->before(); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); $this->after(); } public function doctype( $name, $public, $system, $quirks, $sourceStart, $sourceLength ) { $quirksTypes = [ TreeBuilder::QUIRKS => 'quirks', TreeBuilder::NO_QUIRKS => 'no-quirks', TreeBuilder::LIMITED_QUIRKS => 'limited-quirks' ]; $quirksMsg = $quirksTypes[$quirks]; $this->trace( "doctype $name, public=\"$public\", system=\"$system\", " . "$quirksMsg, start=$sourceStart" ); $this->before(); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); $this->after(); } public function comment( $preposition, $refNode, $text, $sourceStart, $sourceLength ) { $prepName = $this->getPrepositionName( $preposition ); $refTag = $this->getDebugTag( $refNode ); $excerpt = $this->excerpt( $text ); $this->trace( "comment \"$excerpt\", $prepName $refTag, start=$sourceStart" ); $this->before(); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); $this->after(); } public function error( $text, $pos ) { $this->trace( "error \"$text\", start=$pos" ); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); } public function mergeAttributes( Element $element, Attributes $attrs, $sourceStart ) { $elementTag = $this->getDebugTag( $element ); $this->trace( "merge $elementTag, start=$sourceStart" ); $this->before(); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); } public function removeNode( Element $element, $sourceStart ) { $elementTag = $this->getDebugTag( $element ); $this->trace( "remove $elementTag, start=$sourceStart" ); $this->before(); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); $this->after(); } public function reparentChildren( Element $element, Element $newParent, $sourceStart ) { $elementTag = $this->getDebugTag( $element ); $newParentTag = $this->getDebugTag( $newParent ); $this->trace( "reparent children of $elementTag under $newParentTag, start=$sourceStart" ); $this->before(); call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() ); $this->after(); } }