DBI(3)
π DBI(3) β aka XML::Generator::DBI π
okay so bestie, gather round π«Ά this is a page from the User Contributed Perl Documentation, and no cap, it's a good one. Let's get into it.
β¨ NAME β¨
XML::Generator::DBI β Generate SAX events from SQL queries π₯
πΈ SYNOPSIS πΈ
use XML::Generator::DBI;
use XML::SAX::Writer;
use DBI;
my $dbh = DBI->connect("dbi:Pg:dbname=foo", "user", "pass");
my $sth = $dbh->prepare("select * from mytable where mycol = ?");
my $generator = XML::Generator::DBI->new(
Handler => XML::SAX::Writer->new(),
);
$generator->execute($sth, $mycol_value);
π¦ DESCRIPTION π¦
So basically: this module generates SAX events from SQL queries run against a DBI connection. It's giving "SQL in, XML out," and honestly? Iconic. π
The default XML structure it creates looks like this, periodt:
<database>
<select>
<row>
<column1>1</column1>
<column2>fubar</column2>
</row>
<row>
<column1>2</column1>
<column2>intravert</column2>
</row>
</select>
</database>
Alternatively β and this is the fun part β pass the option AsAttributes => 1 to either the execute() method or to the new() method, and your XML will look like this instead:
<database>
<select>
<row column1="1" column2="fubar"/>
<row column1="2" column2="intravert"/>
</select>
</database>
Heads up bestie: with attributes, the ordering of columns is likely to be lost β but on the flip side, it may save you some bytes. Trade-offs, yk? βοΈ
Nulls are handled by excluding either the attribute or the tag. Simple as. πΈ
π API π
π XML::Generator::DBI->new()
Create a new XML generator. New year, new generator, same energy β¨
Parameters are passed as key/value pairs:
Handler(required) β A SAX handler to recieve the events. πdbh(required) β A DBI handle on which to execute the queries. It must support theprepare,execute,fetchmodel of execution, and it also has to supporttype_infoif you wanna use theShowColumnsoption (peep below π).AsAttributesβ The default is to output everything as elements. If you wish to use attributes instead (perhaps to save some bytes), you can specify theAsAttributesoption with a true value.RootElementβ You can specify the root element name by passing the parameterRootElement => "myelement". The default root element name is"database".QueryElementβ You can specify the query element name by passing the parameterQueryElement => "thequery". The default is"select".RowElementβ You can specify the row element name by passing the parameterRowElement => "item". The default is"row".Indentβ By default this module does no indenting (which is different from the previous version). If you want the XML beautified, pass theIndentoption with a true value. πShowColumnsβ If you wish to add information about the columns to your output, specify theShowColumnsoption with a true value. This will then show things like the name and data type of the column, whether the column isNULLABLE, the precision and scale, and also the size of the column. All of this information comes from$dbh->type_info()(seeperldoc DBI), and it may change β because the author is not 100% happy with the output. πByColumnNameβ It allows usage of column names (aliases) for element generation. Aliases can contain slashes in order to generate child elements. It is limited by the length of aliases β depends on your DBMS.
Example:
$select = qq(
SELECT c.client as 'client_id',
c.company_name as 'company_name',
c.address_line as 'address/address_line',
c.city as 'address/city',
c.county as 'address/county',
c.post_code as 'address/post_code',
co.name as 'address/country',
c.phone as 'phone',
c.fax as 'fax',
c.payment_term as 'payment_term',
c.accounting_id as 'accounting_id'
FROM client c,
country co
WHERE c.country = co.country
AND c.client = $client_id
);
$gen->execute(
$select,
undef,
ByColumnName => 1,
RootElement => 'client_detail',
RowElement => 'client',
QueryElement => undef
);
print $output;
<?xml version="1.0" encoding="UTF-8"?>
<client_detail>
<client>
<client_id>3</client_id>
<company_name>SomeCompanyName</company_name>
<address>
<address_line>SomeAddress</address_line>
<city>SomeCity</city>
<county>SomeCounty</county>
<post_code>SomePostCode</post_code>
<country>SomeCountry</country>
</address>
<phone>22222</phone>
<fax>11111</fax>
<payment_term>14</payment_term>
<accounting_id>351</accounting_id>
</client>
</client_detail>
GroupByβ By this parameter you can group rows based on changes in the value of a particular column. It relys on ordering done by your SQL query. This parameter requires two more parameters:GroupElementβ the name of element holding all'row'elements.GroupAttributeβ orGroupValueElementGroupAttributeβ when the'value'goes as attribute ofGroupElement.GroupAttributeis the name of this attribute.GroupValueElementβ when the'value'goes in a separate element.GroupValueElementis the name of the element holding'value'.
Note: in order to avoid unwanted nesting,RowElementisundef.
Example:
contractor_job time_record
-------------- -----------
9 10
9 13
9 14
10 9
10 11
10 12
$select = qq(
SELECT time_record,
contractor_job
FROM time_record
ORDER BY contractor_job
);
Using GroupAttribute:
$gen->execute(
$select,
undef,
ByColumnName => 1,
RootElement => 'client_detail',
RowElement => undef,
GroupBy => 'contractor_job',
GroupElement => 'group',
GroupAttribute => 'ID',
QueryElement => undef
);
print $output;
<?xml version="1.0" encoding="UTF-8"?>
<client_detail>
<group ID="9">
<time_record>10</time_record>
<time_record>13</time_record>
<time_record>14</time_record>
</group>
<group ID="10">
<time_record>9</time_record>
<time_record>11</time_record>
<time_record>12</time_record>
</group>
</client_detail>
Using GroupValueElement:
$gen->execute(
$select,
undef,
ByColumnName => 1,
RootElement => 'client_detail',
RowElement => undef,
GroupBy => 'contractor_job',
GroupElement => 'group',
GroupValueElement => 'ID',
QueryElement => undef
);
print $output;
<?xml version="1.0" encoding="UTF-8"?>
<client_detail>
<group>
<ID>9</ID>
<time_record>10</time_record>
<time_record>13</time_record>
<time_record>14</time_record>
</group>
<group>
<ID>10</ID>
<time_record>9</time_record>
<time_record>11</time_record>
<time_record>12</time_record>
</group>
</client_detail>
π $generator->execute($query, $bind, %params)
You execute a query and generate results with the execute method. That's the whole vibe. β¨
The first parameter is a string containing the query. The second is a single or set of bind parameters. If you wish to make it more than one bind parameter, it must be passed as an array reference:
$generator->execute(
"SELECT * FROM Users WHERE name = ?
AND password = ?",
[ $name, $password ],
);
Following the bind parameters you may pass any options you wish to use to override the above options to new(). Thus allowing you to turn on and off certain options on a per-query basis. Per-query customization? Obsessed. π§
π $generator->execute_one($query, $bind, %params)
If you wish to execute multiple statements within one XML structure, you can use the execute_one() method, as follows:
$generator->pre_execute();
$generator->execute_one($query);
$generator->execute_one($query);
$generator->post_execute();
The pre and post calls are required. No skipping, bestie. π¨
β Other Information β
Binary data is encoded using Base64. If you are using AsElements, the element containing binary data will have an attribute dbi:encoding="base64", where the DBI namespace is bound to the URL "http://axkit.org/NS/xml-generator-dbi". We detect binary data as anything containing characters outside of the XML UTF-8 allowed character set. π«§
π AUTHOR π
Matt Sergeant, matt@sergeant.org
π LICENSE π
This is free software, you may use it and distribute it under the same terms as Perl itself. Specifically this is the Artistic License, or the GNU GPL Version 2. π«Ά
π SEE ALSO π
PerlSAX, XML::Handler::YAWriter.
and that's the whole page, bestie!! π this was perl v5.42.0, dated 2025-07-25, from the DBI(3) page β slay, you made it to the end β¨ππ¦
π¦ where this page comes from
- fedora 43: perl-XML-Generator-DBI 1.00-53.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms