L'outil mysqldump permet d'exporter toute ou une partie de la structure d'une base de données au format XML. De là, il est possible de tansformer ce document, avec une feuille de style XSL, pour générer la documentation de votre modèle physique de données au format HTML.
La solution exposée ici permet de générer une documentation complète de la structure des tables du schéma, en incluant les index, les clés étrangères ainsi que les commentaires des tables et des colonnes.
Structure de la base de données
mysqldump -d --xml --skip-lock-tables {database} > db.xml
Clés étrangères
Dans le cas où vous souhaiteriez inclure dans votre documentation les clés étrangères (InnoDB), un second export XML sera nécessaire car ces informations ne sont pas stockées dans la base de données, mais dans la base information_schema.
mysql --xml information_schema -e "SELECT * FROM KEY_COLUMN_USAGE WHERE CONSTRAINT_SCHEMA = '{database}' AND REFERENCED_TABLE_NAME IS NOT NULL" > foreign.xml
Feuille de style XSL
Une fois les documents db.xml et foreign.xml crées, il vous faudra une feuille de style XSL pour générer votre documentation HTML.
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <xsl:variable name="foreign" select="document('foreign.xml')"/> <xsl:output method="html" encoding="ISO-8859-1"/> <xsl:template name="tablelink"> <xsl:param name="name"/> <samp><a href="#{$name}"><xsl:value-of select="$name"/></a></samp> </xsl:template> <xsl:template name="fieldlink"> <xsl:param name="table"/> <xsl:param name="field"/> <a href="#{$table}"><xsl:value-of select="$table"/></a>.<a href="#{$table}-{$field}"><xsl:value-of select="$field"/></a> </xsl:template> <xsl:template match="database"> <html> <head> <title><xsl:value-of select="@name"/> - MPD Documentation</title> <style> th, td {text-align: left;border: 1px solid #ddd;} table {border-collapse: collapse;border-spacing: 0; } table > tbody > tr:nth-child(2n+1) > td {background-color: #f9f9f9;} </style> </head> <body> <a name="top"/> <hr/> <xsl:apply-templates select="table_structure"/> </body> </html> </xsl:template> <xsl:template match="table_structure"> <xsl:variable name="table" select="@name"/> <a name="{@name}"/><h2><xsl:value-of select="@name"/></h2> <xsl:if test="./options/@Comment != ''"> <em><xsl:value-of select="./options/@Comment"/></em><br/> </xsl:if> <!-- fields --> <h3>Fields for table <xsl:call-template name="tablelink"> <xsl:with-param name="name" select="@name"/> </xsl:call-template> (<xsl:value-of select="count(./field)"/>) </h3> <table> <thead> <tr> <th>Name</th> <th>Type</th> <th>Nullable</th> <th>Default</th> <th>Extra</th> <th>Comments</th> </tr> </thead> <tbody> <xsl:for-each select="./field"> <xsl:variable name="field" select="@Field"/> <xsl:variable name="type" select="@Type"/> <tr> <td><a name="{$table}-{$field}"/><samp><strong><xsl:value-of select="@Field"/></strong></samp></td> <td><samp><xsl:value-of select="@Type"/></samp></td> <td><samp><xsl:value-of select="@Null"/></samp></td> <td><samp><xsl:value-of select="@Default"/></samp></td> <td><samp><xsl:value-of select="@Extra"/></samp></td> <td><em><xsl:value-of select="@Comment"/></em></td> </tr> </xsl:for-each> </tbody> </table> <!-- keys --> <h3>Keys for table <xsl:call-template name="tablelink"> <xsl:with-param name="name" select="@name"/> </xsl:call-template> (<xsl:value-of select="count(./key)"/>) </h3> <table> <thead> <tr> <th>Key name</th> <th>Column</th> <th>Unique</th> </tr> </thead> <tbody> <xsl:for-each select="./key"> <tr> <td><samp><strong><xsl:value-of select="@Key_name"/></strong></samp></td> <td><samp><xsl:value-of select="@Column_name"/></samp></td> <td> <samp> <xsl:choose> <xsl:when test="@Non_unique='0'">YES</xsl:when> <xsl:otherwise>NO</xsl:otherwise> </xsl:choose> </samp> </td> </tr> </xsl:for-each> </tbody> </table> <!-- related --> <h3>Foreign keys for table <xsl:call-template name="tablelink"> <xsl:with-param name="name" select="@name"/> </xsl:call-template> (<xsl:value-of select="count( $foreign/resultset/row/field[@name='TABLE_NAME' and text()=$table] )"/>) </h3> <xsl:choose> <xsl:when test="count( $foreign/resultset/row/field[@name='TABLE_NAME' and text()=$table] ) > 0"> <table> <thead> <tr> <th>Local column</th> <th>Foreign column</th> </tr> </thead> <tbody> <xsl:for-each select="$foreign/resultset/row/field[@name='TABLE_NAME' and text()=$table]"> <xsl:variable name="local_column" select="../field[@name='COLUMN_NAME']"/> <xsl:variable name="referenced_table" select="../field[@name='REFERENCED_TABLE_NAME']"/> <xsl:variable name="referenced_column" select="../field[@name='REFERENCED_COLUMN_NAME']"/> <tr> <td><strong><samp><xsl:value-of select="$local_column"/></samp></strong></td> <td> <samp> <xsl:call-template name="fieldlink"> <xsl:with-param name="table" select="$referenced_table"/> <xsl:with-param name="field" select="$referenced_column"/> </xsl:call-template> </samp> </td> </tr> </xsl:for-each> </tbody> </table> </xsl:when> <xsl:otherwise> <em>This table doesn't have foreign keys</em> </xsl:otherwise> </xsl:choose> <hr/> </xsl:template> </xsl:stylesheet>
Transformation
Ceci fait, il vous faut maintenant générer votre documentation. Un simple script PHP fera ici l'affaire :
<?php $xml = new DOMDocument; $xml -> load( 'db.xml' ); $xsl = new DOMDocument; $xsl -> load( 'transform.xslt' ); $xslt = new xsltProcessor; $xslt->importStyleSheet( $xsl ); header('Content-type: text/html'); print $xslt->transformToXML($xml);
Il ne vous reste plus qu'à lancer la conversion :
php doc.php > doc.html