Générer la documentation de votre modèle physique de données MySQL

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

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.