To make xml output easier I have made three small stored SQL functions. They produce xml fragments, which you can easily put together to get a complete xml:
xml_escape(value) replace characters not allowed in xml with the escape sequences
xml_attr(name, value) create an xml attribute
xml_tag(tagname, tagvalue, attrs, subtags) create a tag, optionally with
Lets see some examples. First a real simple one:
select xml_tag('table',table_name,null,null)
from information_schema.tables
where table_schema = 'INFORMATION_SCHEMA'
Gives you something like:
<table>CHARACTER_SETS</table>
<table>COLLATIONS</table>
<table>COLLATION_CHARACTER_SET_APPLICABILITY</table>
etc...
To make this a valid xml, you need to add an xml header and a root tag, surrounding all the content. Something like this:
<?xml version="1.0" encoding="UTF-8"?>
<list>
your content...
</list>
That will give you a real simple xml, with a list of the tables
in the information schema. But perhaps your specification says
you should present the data as attributes and not as text nodes.
Let's try that:
select xml_tag('table',null,xml_attr('name',table_name),null)
from information_schema.tables
where table_schema = 'INFORMATION_SCHEMA'
Gives you:
<table name="CHARACTER_SETS" />
<table name="COLLATIONS" />
<table name="COLLATION_CHARACTER_SET_APPLICABILITY" />
etc..
Since we don't want a text node we let the tagvalue parameter be null.
Instead we use the xml_attr function to format an xml attribute and
send it in in the attrs parameter.
But what if we need several attributes? You can not write a stored
function with variable number of arguments, so we use the MySql
standard function concat() for this.
select xml_tag('table',null, concat(xml_attr('name',table_name),
xml_attr('engine',engine)),null)
from information_schema.tables
where table_schema = 'INFORMATION_SCHEMA'
gives you:
<table name="CHARACTER_SETS" engine="MEMORY" />
<table name="COLLATIONS" engine="MEMORY" />
<table name="COLLATION_CHARACTER_SET_APPLICABILITY"
engine="MEMORY" />
<table name="COLUMNS" engine="MyISAM" />
And if you want your data as text nodes in sub tags, you do the
same trick with the last parameter in xml_tag, the subtags parameter:
select xml_tag('table',null,null,
concat(xml_tag('name',table_name,null,null),
xml_tag('engine',engine,null,null)))
from information_schema.tables
where table_schema = 'INFORMATION_SCHEMA'
Results in:
<table><name>CHARACTER_SETS</name><engine>MEMORY</engine></table>
<table><name>COLLATIONS</name><engine>MEMORY</engine></table>
<table><name>COLLATION_CHARACTER_SET_APPLICABILITY</name>
<engine>MEMORY</engine></table>
etc..
Of course you can combine attributes, subtags and a text node,
but I leave that for yourself to experiment with.
The stored functions are defined like this:
DELIMITER $$
DROP FUNCTION IF EXISTS `xml_escape` $$
CREATE FUNCTION `xml_escape`( tagvalue VARCHAR(2000))
RETURNS varchar(2000)
BEGIN
IF (tagvalue IS NULL) THEN
RETURN null;
END IF;
RETURN REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
tagvalue,'&','&'),
'<','<'),
'>','>'),
'"','"'),
'\'',''');
END $$
DROP FUNCTION IF EXISTS `xml_attr` $$
CREATE FUNCTION `xml_attr`(tagname VARCHAR(2000),
tagvalue VARCHAR(2000))
RETURNS varchar(2000)
BEGIN
IF (tagvalue IS NULL) THEN
RETURN null;
END IF;
RETURN CONCAT(' ', tagname ,'="',xml_escape(tagvalue),'" ');
END $$
DROP FUNCTION IF EXISTS `xml_tag` $$
CREATE FUNCTION `xml_tag`(tagname VARCHAR(2000),
tagvalue VARCHAR(2000),
attrs VARCHAR(2000),
subtags VARCHAR(2000))
RETURNS varchar(2000)
BEGIN
DECLARE result VARCHAR(2000);
SET result = CONCAT('<' , tagname);
IF attrs IS NOT NULL THEN
SET result = CONCAT(result,' ', attrs);
END IF;
IF (tagvalue IS NULL AND subtags IS NULL) THEN
RETURN CONCAT(result,' />');
END IF;
RETURN CONCAT(result ,'>',ifnull(xml_escape(tagvalue),''),
ifnull(subtags,''),'</',tagname, '>');
END $$
DELIMITER ;

6 comments:
Shouldn't that second-to-last line of xml_tag() include the closing tag? Such as:
RETURN CONCAT(result ,'>',ifnull(xml_escape(tagvalue),''),ifnull(subtags,''),'</', tagname, '>');
Hi Erik!
Please consider adding your fine functions to the code snippet repository on MySQL Forge. Great stuff!
http://forge.mysql.com/snippets/
Or just go to the command line and do
mysql --xml -e "your query here"
The functions are now available at http://forge.mysql.com/snippets/view.php?id=86
I have also corrected the error jess pointed out.
The mysql --xml is an alternative, but you can not control the xml format and you need to create a command shell to use it.
The snippets link is broken, it should be http://forge.mysql.com/tools/tool.php?id=86
Can I suggest the following change to xml_tag() :
Argument : nsPrefix VARCHAR(20)
Code :
IF nsPrefix IS NOT NULL THEN
SET tagname = concat(nsPrefix, ':', tagname);
END IF;
And to xml_escape() bold portion:
IF (tagvalue IS NULL) THEN
RETURN NULL;
ELSEIF (tagvalue regexp '\'|"|&|<|>') = 0 THEN
RETURN tagvalue;
END IF;
Hi,
just to add another approach to the XML creation. I wrote PHP XML generator in less than 80 lines. It accepts SQL and outputs XML. You can even describe hierarchy with optional parameter. If you are interested, please visit www.redips.net | From MySQL to XML with PHP
Thank you!
Post a Comment