XML::Li...allback(3)

✨ XML::LibXML::InputCallback ✨

okay bestie, welcome to the XML::LibXML::InputCallback page β€” yes it's a User Contributed Perl Documentation page, and yes it's giving very "let me handle your URIs for you" energy. come sit, we're doing callbacks today πŸ’…


NAME

XML::LibXML::InputCallback β€” the XML::LibXML class for input callbacks. that's it, that's the whole name section, we move 🫢


SYNOPSIS

  use XML::LibXML;

that's the vibe check. short and iconic πŸ‘‘


DESCRIPTION

so here's the tea, bestie: you may get unexpected results if you're trying to load external documents during libxml2 parsing and the location of the resource is not an HTTP, FTP or relative location β€” like, say, an absolute path. πŸ™ˆ to get around this little limitation, you may add your own input handler to open, read and close particular types of locations or URI classes. and with these input callback handlers you can handle your own custom URI schemes, for example. main character behaviour, honestly. πŸ’–

the input callbacks are used whenever XML::LibXML has to get something other than externally parsed entities from somewhere. they're implemented using a callback stack on the Perl layer, in analogy to libxml2's native callback stack. cute, right?

and the XML::LibXML::InputCallback class transparently registers those input callbacks for libxml2's parser processes. no cap. ✨

How does XML::LibXML::InputCallback work? πŸ¦‹

the libxml2 library offers a callback implementation as global functions only. which is lowkey a problem β€” for example if the same global callback stack is manipulated by different applications running together in a single Apache Web-server environment 😭 β€” so XML::LibXML::InputCallback comes with an object-oriented part and a function-oriented part. two halves, one slay.

with the function-oriented part you can manipulate the global callback stack of libxml2. those functions can be used as interface to the callbacks on the C- and XS Layer. and at the object-oriented part, operations for working with the "pseudo-localized" callback stack are implemented. currently you can register and de-register callbacks on the Perl layer and initialize them on a per parser basis. periodt. πŸ’…

Callback Groups

the libxml2 input callbacks come in groups. one group contains:

  • a URI matcher (match)
  • a data stream constructor (open)
  • a data stream reader (read)
  • a data stream destructor (close)

and the callbacks can be manipulated on a per group basis only. that's the rule, bestie, no exceptions 🌸

The Parser Process

the parser process works on an XML data stream, and along that stream links to other resources can be embedded. think links to external DTDs, or XIncludes, for example. those resources are identified by URIs. πŸ‘‘

the callback implementation of libxml2 assumes that one callback group can handle a certain amount of URIs and a certain URI scheme. per default, callback handlers for file://*, file:://*.gz, http://* and ftp://* are registered.

callback groups in the callback stack are processed from top to bottom β€” meaning callback groups registered later will be processed before the earlier registered ones. so, like, newest first. it's giving stack energy πŸ₯ž

while parsing the data stream, the libxml2 parser checks if a registered callback group will handle a URI β€” and if they won't, the URI will be interpreted as file://URI. to handle a URI, the match callback will have to return '1'. if that happens, the handling of the URI gets passed to that callback group. next, the URI gets passed to the open callback, which should return a reference to the data stream if it successfully opened the file, and '0' otherwise. if opening the stream was successful, the read callback will be called repeatedly until it returns an empty string. and after the read callback, the close callback gets called to close the stream. full cycle, chef's kiss πŸŽ€

Organisation of callback groups in XML::LibXML::InputCallback

callback groups are implemented as a stack (Array), and each entry holds a reference to an array of the callbacks. for the libxml2 library, the XML::LibXML::InputCallback callback implementation appears as one single callback group. the Perl implementation, however, allows one to manage different callback stacks on a per libxml2-parser basis. flexible queen 🌈

Using XML::LibXML::InputCallback πŸ’–

after object instantiation using the parameter-less constructor, you can register callback groups. watch:

  my $input_callbacks = XML::LibXML::InputCallback->new();
  $input_callbacks->register_callbacks([ $match_cb1, $open_cb1,
                                         $read_cb1, $close_cb1 ] );
  $input_callbacks->register_callbacks([ $match_cb2, $open_cb2,
                                         $read_cb2, $close_cb2 ] );
  $input_callbacks->register_callbacks( [ $match_cb3, $open_cb3,
                                          $read_cb3, $close_cb3 ] );

  $parser->input_callbacks( $input_callbacks );
  $parser->parse_file( $some_xml_file );

three groups, one parser, absolutely ate πŸ”₯

What about the old callback system prior to XML::LibXML::InputCallback?

in XML::LibXML versions prior to 1.59 β€” i.e. without the XML::LibXML::InputCallback module β€” you could define your callbacks either using globally or locally. you still can do that using XML::LibXML::InputCallback, and in addition to that you can define the callbacks on a per parser basis! glow up ✨

if you use the old callback interface through global callbacks, XML::LibXML::InputCallback will treat them with a lower priority as the ones registered using the new interface. the global callbacks will not override the callback groups registered using the new interface. local callbacks are attached to a specific parser instance, therefore they are treated with highest priority. if the match callback of the callback group registered as local variable is identical to one of the callback groups registered using the new interface, that callback group will be replaced.

⚠️ bestie, listen: users of the old callback implementation whose open callback returned a plain string will have to adapt their code to return a reference to that string after upgrading to version >= 1.59. the new callback system can only deal with the open callback returning a reference! no cap, do not skip this one 😭

INTERFACE DESCRIPTION πŸŽ€

Global Variables

  • $_CUR_CB β€” stores the current callback, and can be used as a shortcut to access the callback stack. your lil shortcut bestie πŸ’…
  • @_GLOBAL_CALLBACKS β€” stores all callback groups for the current parser process.
  • @_CB_STACK β€” stores the currently used callback group. used to prevent parser errors when dealing with nested XML data. protective icon πŸ›‘οΈ

Global Callbacks

  • _callback_match β€” implements the interface for the match callback at C-level, and for the selection of the callback group from the callbacks defined at the Perl-level.
  • _callback_open β€” forwards the open callback from libxml2 to the corresponding callback function at the Perl-level.
  • _callback_read β€” forwards the read request to the corresponding callback function at the Perl-level and returns the result to libxml2.
  • _callback_close β€” forwards the close callback from libxml2 to the corresponding callback function at the Perl-level.. (yes, two periods, that's how it was written, we respect the original πŸ’€)

Class methods

  • new() β€” a simple constructor. simple. unbothered. hydrated. 🌸
  • register_callbacks( [ $match_cb, $open_cb, $read_cb, $close_cb ]) β€” the four callbacks have to be given as an array reference, in this exact order: match, open, read, close! order matters bestie, don't freestyle it πŸ”₯
  • unregister_callbacks( [ $match_cb, $open_cb, $read_cb, $close_cb ]) β€” with no arguments given, unregister_callbacks() will delete the last registered callback group from the stack. if four callbacks are passed as an array reference, the callback group to unregister will be identified by the match callback and deleted from the callback stack.
heads up: if several identical match callbacks are defined in different callback groups, ALL of them will be deleted from the stack. all of them. every last one. πŸ’€
  • init_callbacks( $parser ) β€” initializes the callback system for the provided parser before starting a parsing process. prep before the party ✨
  • cleanup_callbacks() β€” resets global variables and the libxml2 callback stack. clean girl aesthetic 🧚
  • lib_init_callbacks() β€” used internally for callback registration at C-level.
  • lib_cleanup_callbacks() β€” used internally for callback resetting at the C-level.

EXAMPLE CALLBACKS πŸ‘‘

the following example is a purely fictitious example that uses a MyScheme::Handler object that responds to methods similar to an IO::Handle. so like, don't @ us, it's a demo 🫢

  # Define the four callback functions
  sub match_uri {
      my $uri = shift;
      return $uri =~ /^myscheme:/; # trigger our callback group at a 'myscheme' URIs
  }

  sub open_uri {
      my $uri = shift;
      my $handler = MyScheme::Handler->new($uri);
      return $handler;
  }

  # The returned $buffer will be parsed by the libxml2 parser
  sub read_uri {
      my $handler = shift;
      my $length = shift;
      my $buffer;
      read($handler, $buffer, $length);
      return $buffer; # $buffer will be an empty string '' if read() is done
  }

  # Close the handle associated with the resource.
  sub close_uri {
      my $handler = shift;
      close($handler);
  }

  # Register them with a instance of XML::LibXML::InputCallback
  my $input_callbacks = XML::LibXML::InputCallback->new();
  $input_callbacks->register_callbacks([ \&match_uri, \&open_uri,
                                         \&read_uri, \&close_uri ] );

  # Register the callback group at a parser instance
  $parser->input_callbacks( $input_callbacks );

  # $some_xml_file will be parsed using our callbacks
  $parser->parse_file( $some_xml_file );

match, open, read, close β€” the four horsemen of your custom URI scheme πŸ¦‹


AUTHORS

Matt Sergeant, Christian Glahn, Petr Pajas. the founding mothers, if you will πŸ’œ


VERSION

2.0213


  • 2001-2007, AxKit.com Ltd.
  • 2002-2006, Christian Glahn.
  • 2006-2009, Petr Pajas.

LICENSE

this program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. slay, legally πŸŽ€


and that's the whole page, bestie!! πŸ’– this lil gem lives at perl v5.42.2, dated 2026-05-25, and it's part of the User Contributed Perl Documentation set. go forth and register those callbacks, you absolute icon πŸ‘‘βœ¨πŸ«Ά

πŸ“¦ where this page comes from