<?xml version="1.0" encoding="UTF-8"?>
<!-- 
    wadl.xsl (07-Sep-2012)
    
    Transforms Web Application Description Language (WADL) XML documents into HTML.

    Mark Sawers <mark.sawers@ipc.com>
    
    See example_wadl.xml at http://github.com/ipcsystems/wadl-stylesheet to explore this stylesheet's capabilities
    and the README.txt for other usage information.
    Note that the contents of a doc element is rendered as a:
        * hyperlink if the title attribute contains is equal to 'Example'
        * mono-spaced font ('pre' tag) if content contains the text 'Example'
			
    Limitations:
        * Ignores globally defined methods, referred to from a resource using a method reference element.
          Methods must be embedded in a resource element.
        * Ditto for globally defined representations. Representations must be embedded within request
          and response elements.
        * Ignores type and queryType attributes of resource element.
        * Ignores resource_type element.
        * Ignores profile attribute of representation element.
        * Ignores path attribute and child link elements of param element.

    Copyright (c) 2012 IPC Systems, Inc.

    Parts of this work are adapted from Mark Notingham's wadl_documentation.xsl, at
        https://github.com/mnot/wadl_stylesheets.
    
    This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License.
    To view a copy of this license, visit 
        http://creativecommons.org/licenses/by-sa/3.0/
    or send a letter to 
        Creative Commons
        543 Howard Street, 5th Floor
        San Francisco, California, 94105, USA
 -->
<xsl:stylesheet 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
 xmlns:wadl="http://wadl.dev.java.net/2009/02"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:html="http://www.w3.org/1999/xhtml"
 xmlns="http://www.w3.org/1999/xhtml"
>

<!-- Global variables -->
<xsl:variable name="g_resourcesBase" select="wadl:application/wadl:resources/@base"/>

<!-- Template for top-level doc element -->
<xsl:template match="wadl:application">
    <html>
    <head>
        <meta charset="UTF-8" />
        <xsl:call-template name="getStyle"/>
        <title><xsl:call-template name="getTitle"/></title>
    </head>
    <body>
    <h1><xsl:call-template name="getTitle"/></h1>
    <xsl:call-template name="getDoc">
        <xsl:with-param name="base" select="$g_resourcesBase"/>
    </xsl:call-template>
    
    <!-- Summary -->
    <h2>Summary</h2>
    <table>
        <tr>
            <th>Resource</th>
            <th>Method</th>
            <th>Description</th>
        </tr>
        <xsl:for-each select="wadl:resources/wadl:resource">
            <xsl:call-template name="processResourceSummary">
                <xsl:with-param name="resourceBase" select="$g_resourcesBase"/>
                <xsl:with-param name="resourcePath" select="@path"/>
                <xsl:with-param name="lastResource" select="position() = last()"/>
            </xsl:call-template>
        </xsl:for-each>
    </table>
    <p></p>
    
    <!-- Grammars -->
    <xsl:if test="wadl:grammars/wadl:include">
        <h2>Grammars</h2>
        <p>
            <xsl:for-each select="wadl:grammars/wadl:include">
                <xsl:variable name="href" select="@href"/>
                <a href="{$href}"><xsl:value-of select="$href"/></a>
                <xsl:if test="position() != last()"><br/></xsl:if>  <!-- Add a spacer -->
            </xsl:for-each>
        </p>
    </xsl:if>

    <!-- Detail -->
    <h2>Resources</h2>
    <xsl:for-each select="wadl:resources">
        <xsl:call-template name="getDoc">
            <xsl:with-param name="base" select="$g_resourcesBase"/>
        </xsl:call-template>
        <br/>
    </xsl:for-each>
    
    <xsl:for-each select="wadl:resources/wadl:resource">
        <xsl:call-template name="processResourceDetail">
            <xsl:with-param name="resourceBase" select="$g_resourcesBase"/>
            <xsl:with-param name="resourcePath" select="@path"/>
        </xsl:call-template>
    </xsl:for-each>

    </body>
    </html>
</xsl:template>

<!-- Supporting templates (functions) -->

<xsl:template name="processResourceSummary">
    <xsl:param name="resourceBase"/>
    <xsl:param name="resourcePath"/>
    <xsl:param name="lastResource"/>

    <xsl:if test="wadl:method">
        <tr>
            <!-- Resource -->
            <td class="summary">
                <xsl:variable name="id"><xsl:call-template name="getId"/></xsl:variable>
                <a href="#{$id}">
                    <xsl:call-template name="getFullResourcePath">
                        <xsl:with-param name="base" select="$resourceBase"/>                
                        <xsl:with-param name="path" select="$resourcePath"/>                
                    </xsl:call-template>
                </a>
            </td>
            <!-- Method -->
            <td class="summary">
                <xsl:for-each select="wadl:method">
                    <xsl:variable name="name" select="@name"/>
                    <xsl:variable name="id2"><xsl:call-template name="getId"/></xsl:variable>
                    <a href="#{$id2}"><xsl:value-of select="$name"/></a>
                    <xsl:for-each select="wadl:doc"><br/></xsl:for-each>
                    <xsl:if test="position() != last()"><br/></xsl:if>  <!-- Add a spacer -->
                </xsl:for-each>
                <br/>
            </td>
            <!-- Description -->
            <td class="summary">
                <xsl:for-each select="wadl:method">
                    <xsl:call-template name="getDoc">
                        <xsl:with-param name="base" select="$resourceBase"/>
                    </xsl:call-template>
                    <br/>
                    <xsl:if test="position() != last()"><br/></xsl:if>  <!-- Add a spacer -->
                </xsl:for-each>
            </td>
        </tr>
        <!-- Add separator if not the last resource -->
        <xsl:if test="wadl:method and not($lastResource)">
            <tr><td class="summarySeparator"></td><td class="summarySeparator"/><td class="summarySeparator"/></tr>
        </xsl:if>
    </xsl:if>   <!-- wadl:method -->

    <!-- Call recursively for child resources -->
    <xsl:for-each select="wadl:resource">
        <xsl:variable name="base">
            <xsl:call-template name="getFullResourcePath">
                <xsl:with-param name="base" select="$resourceBase"/>                
                <xsl:with-param name="path" select="$resourcePath"/>           
            </xsl:call-template>
        </xsl:variable>
        <xsl:call-template name="processResourceSummary">
            <xsl:with-param name="resourceBase" select="$base"/>
            <xsl:with-param name="resourcePath" select="@path"/>
            <xsl:with-param name="lastResource" select="$lastResource and position() = last()"/>
        </xsl:call-template>
    </xsl:for-each>

</xsl:template>

<xsl:template name="processResourceDetail">
    <xsl:param name="resourceBase"/>
    <xsl:param name="resourcePath"/>

    <xsl:if test="wadl:method">
        <h3>
            <xsl:variable name="id"><xsl:call-template name="getId"/></xsl:variable>
            <a name="{$id}">
                <xsl:call-template name="getFullResourcePath">
                    <xsl:with-param name="base" select="$resourceBase"/>                
                    <xsl:with-param name="path" select="$resourcePath"/>                
                </xsl:call-template>
            </a>
        </h3>
        <p>
            <xsl:call-template name="getDoc">
                <xsl:with-param name="base" select="$resourceBase"/>
            </xsl:call-template>
        </p>

        <h5>Methods</h5>

        <div class="methods">
            <xsl:for-each select="wadl:method">
            <div class="method">
                <table class="methodNameTable">
                    <tr>
                        <td class="methodNameTd" style="font-weight: bold">
                            <xsl:variable name="name" select="@name"/>
                            <xsl:variable name="id2"><xsl:call-template name="getId"/></xsl:variable>
                            <a name="{$id2}"><xsl:value-of select="$name"/></a>
                        </td>
                        <td class="methodNameTd" style="text-align: right">
                            <xsl:if test="@id">
                                <xsl:value-of select="@id"/>() 
                            </xsl:if>
                        </td>
                    </tr>
                </table>
                <p>
                    <xsl:call-template name="getDoc">
                        <xsl:with-param name="base" select="$resourceBase"/>
                    </xsl:call-template>
                </p>

                <!-- Request -->
                <h6>request</h6>
                <div style="margin-left: 2em">  <!-- left indent -->
                <xsl:choose>
                    <xsl:when test="wadl:request">
                        <xsl:for-each select="wadl:request">
                            <xsl:call-template name="getParamBlock">
                                <xsl:with-param name="style" select="'template'"/>
                            </xsl:call-template>
                    
                            <xsl:call-template name="getParamBlock">
                                <xsl:with-param name="style" select="'matrix'"/>
                            </xsl:call-template>
                    
                            <xsl:call-template name="getParamBlock">
                                <xsl:with-param name="style" select="'header'"/>
                            </xsl:call-template>
                    
                            <xsl:call-template name="getParamBlock">
                                <xsl:with-param name="style" select="'query'"/>
                            </xsl:call-template>
                    
                            <xsl:call-template name="getRepresentations"/>
                        </xsl:for-each> <!-- wadl:request -->
                    </xsl:when>
    
                    <xsl:when test="not(wadl:request) and (ancestor::wadl:*/wadl:param)">
                        <xsl:call-template name="getParamBlock">
                            <xsl:with-param name="style" select="'template'"/>
                        </xsl:call-template>
                
                        <xsl:call-template name="getParamBlock">
                            <xsl:with-param name="style" select="'matrix'"/>
                        </xsl:call-template>
                
                        <xsl:call-template name="getParamBlock">
                            <xsl:with-param name="style" select="'header'"/>
                        </xsl:call-template>
                
                        <xsl:call-template name="getParamBlock">
                            <xsl:with-param name="style" select="'query'"/>
                        </xsl:call-template>
                
                        <xsl:call-template name="getRepresentations"/>
                    </xsl:when>
            
                    <xsl:otherwise>
                        unspecified
                    </xsl:otherwise>
                </xsl:choose>
                </div>  <!-- left indent for request -->
                                
                <!-- Response -->
                <h6>responses</h6>
                <div style="margin-left: 2em">  <!-- left indent -->
                <xsl:choose>
                    <xsl:when test="wadl:response">
                        <xsl:for-each select="wadl:response">
                            <div class="h8">status: </div>
                            <xsl:choose>
                                <xsl:when test="@status">
                                    <xsl:value-of select="@status"/>
                                </xsl:when>
                                <xsl:otherwise>
                                    200 - OK
                                </xsl:otherwise>
                            </xsl:choose>
                            <xsl:for-each select="wadl:doc">
                                <xsl:if test="@title">
                                    - <xsl:value-of select="@title"/>
                                </xsl:if>
                                <xsl:if test="text()">
                                    - <xsl:value-of select="text()"/>
                                </xsl:if>
                            </xsl:for-each>
                            
                            <!-- Get response headers/representations -->
                            <xsl:if test="wadl:param or wadl:representation">
                                <div style="margin-left: 2em"> <!-- left indent -->
                                <xsl:if test="wadl:param">
                                    <div class="h7">headers</div>
                                    <table>
                                        <xsl:for-each select="wadl:param[@style='header']">
                                            <xsl:call-template name="getParams"/>
                                        </xsl:for-each>
                                    </table>
                                </xsl:if>
    
                                <xsl:call-template name="getRepresentations"/>
                                </div>  <!-- left indent for response headers/representations -->
                            </xsl:if>
                        </xsl:for-each> <!-- wadl:response -->
                    </xsl:when>
                    <xsl:otherwise>
                        unspecified
                    </xsl:otherwise>
                </xsl:choose>                
                </div>  <!-- left indent for responses -->

            </div>  <!-- class=method -->
            </xsl:for-each> <!-- wadl:method  -->
        </div> <!-- class=methods -->

    </xsl:if>   <!-- wadl:method -->

    <!-- Call recursively for child resources -->
    <xsl:for-each select="wadl:resource">
        <xsl:variable name="base">
            <xsl:call-template name="getFullResourcePath">
                <xsl:with-param name="base" select="$resourceBase"/>                
                <xsl:with-param name="path" select="$resourcePath"/>           
            </xsl:call-template>
        </xsl:variable>
        <xsl:call-template name="processResourceDetail">
            <xsl:with-param name="resourceBase" select="$base"/>
            <xsl:with-param name="resourcePath" select="@path"/>
        </xsl:call-template>
    </xsl:for-each> <!-- wadl:resource -->
</xsl:template>

<xsl:template name="getFullResourcePath">
    <xsl:param name="base"/>
    <xsl:param name="path"/>
    <xsl:choose>
        <xsl:when test="substring($base, string-length($base)) = '/'">
            <xsl:value-of select="$base"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="concat($base, '/')"/>
        </xsl:otherwise>
    </xsl:choose>
    <xsl:choose>
        <xsl:when test="starts-with($path, '/')">
            <xsl:value-of select="substring($path, 2)"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$path"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="getDoc">
    <xsl:param name="base"/>
    <xsl:for-each select="wadl:doc">
        <xsl:if test="position() > 1"><br/></xsl:if>
        <xsl:if test="@title and local-name(..) != 'application'">
            <xsl:value-of select="@title"/>:
        </xsl:if>
        <xsl:variable name="content" select="."/>
        <xsl:choose>
            <xsl:when test="@title = 'Example'">
                <xsl:variable name="url">
                    <xsl:choose>
                        <xsl:when test="string-length($base) > 0">
                            <xsl:call-template name="getFullResourcePath">
                                <xsl:with-param name="base" select="$base"/>                
                                <xsl:with-param name="path" select="text()"/>
                            </xsl:call-template>
                        </xsl:when>
                        <xsl:otherwise><xsl:value-of select="text()"/></xsl:otherwise>
                    </xsl:choose>
                </xsl:variable>
                <a href="{$url}"><xsl:value-of select="$url"/></a>
            </xsl:when>
            <xsl:when test="contains($content, 'Example')">
               	<div style="white-space:pre-wrap"><pre><xsl:value-of select="."/></pre></div>
            </xsl:when>
            <xsl:otherwise>
               	<xsl:value-of select="$content"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</xsl:template>

<xsl:template name="getId">
    <xsl:choose>
        <xsl:when test="@id"><xsl:value-of select="@id"/></xsl:when>
        <xsl:otherwise><xsl:value-of select="generate-id()"/></xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="getParamBlock">
    <xsl:param name="style"/>
    <xsl:if test="ancestor-or-self::wadl:*/wadl:param[@style=$style]">
        <div class="h7"><xsl:value-of select="$style"/> params</div>
        <table>
            <xsl:for-each select="ancestor-or-self::wadl:*/wadl:param[@style=$style]">
                <xsl:call-template name="getParams"/>
            </xsl:for-each>
        </table>
        <p/>
    </xsl:if>
</xsl:template>

<xsl:template name="getParams">
    <tr>
        <td style="font-weight: bold"><xsl:value-of select="@name"/></td>
            <td>
                <xsl:if test="not(@type) and not(@fixed)">
                    unspecified type
                </xsl:if>
                <xsl:call-template name="getHyperlinkedElement">
                    <xsl:with-param name="qname" select="@type"/>
                </xsl:call-template>
                <xsl:if test="@required = 'true'"><br/>(required)</xsl:if>
                <xsl:if test="@repeating = 'true'"><br/>(repeating)</xsl:if>
                <xsl:if test="@default"><br/>default: <tt><xsl:value-of select="@default"/></tt></xsl:if>
                <xsl:if test="@type and @fixed"><br/></xsl:if>
                <xsl:if test="@fixed">fixed: <tt><xsl:value-of select="@fixed"/></tt></xsl:if>
                <xsl:if test="wadl:option">
                    <br/>options:
                    <xsl:for-each select="wadl:option">
                        <xsl:choose>
                            <xsl:when test="@mediaType">
                                <br/><tt><xsl:value-of select="@value"/> (<xsl:value-of select="@mediaType"/>)</tt>
                            </xsl:when>
                            <xsl:otherwise>
                                <tt><xsl:value-of select="@value"/></tt>
                                <xsl:if test="position() != last()">, </xsl:if>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </xsl:if>
            </td>
        <xsl:if test="wadl:doc">
            <td><xsl:value-of select="wadl:doc"/></td>
        </xsl:if>
    </tr>
</xsl:template>

<xsl:template name="getHyperlinkedElement">
    <xsl:param name="qname"/>
    <xsl:variable name="prefix" select="substring-before($qname,':')"/>
    <xsl:variable name="ns-uri" select="./namespace::*[name()=$prefix]"/>
    <xsl:variable name="localname" select="substring-after($qname, ':')"/>
    <xsl:choose>
        <xsl:when test="$ns-uri='http://www.w3.org/2001/XMLSchema' or $ns-uri='http://www.w3.org/2001/XMLSchema-instance'">
            <a href="http://www.w3.org/TR/xmlschema-2/#{$localname}"><xsl:value-of select="$localname"/></a>
        </xsl:when>
        <xsl:when test="$ns-uri and starts-with($ns-uri, 'http://www.w3.org/XML/') = false">
            <a href="{$ns-uri}#{$localname}"><xsl:value-of select="$localname"/></a>
        </xsl:when>
        <xsl:when test="$qname">
            <xsl:value-of select="$qname"/>
        </xsl:when>
    </xsl:choose>
</xsl:template>



<xsl:template name="getRepresentations">
    <xsl:if test="wadl:representation">
        <div class="h7">representations</div>
        <table>
            <xsl:for-each select="wadl:representation">
                <tr>
                    <td style="font-weight: bold"><xsl:value-of select="@mediaType" /></td>
			        <xsl:choose>
	                    <xsl:when test="@href or @element">
	                        <td>
	                            <xsl:variable name="href" select="@href" />
	                            <xsl:choose>
	                                <xsl:when test="@href">
										<xsl:variable name="localname" select="substring-after(@element, ':')"/>
	                                    <a href="{$href}"><xsl:value-of select="$localname" /></a>
	                                </xsl:when>
	                                <xsl:otherwise>
						                <xsl:call-template name="getHyperlinkedElement">
						                    <xsl:with-param name="qname" select="@element" />
						                </xsl:call-template>
	                                </xsl:otherwise>
	                            </xsl:choose>
	                        </td>
	                    </xsl:when>
	                    <xsl:otherwise><td/></xsl:otherwise>
					</xsl:choose>  
					                  
                    <xsl:if test="wadl:doc">
                        <td>
                            <xsl:call-template name="getDoc">
                                <xsl:with-param name="base" select="''" />
                            </xsl:call-template>
                        </td>
                    </xsl:if>
                </tr>
                <xsl:call-template name="getRepresentationParamBlock">
                    <xsl:with-param name="style" select="'template'" />
                </xsl:call-template>
        
                <xsl:call-template name="getRepresentationParamBlock">
                    <xsl:with-param name="style" select="'matrix'" />
                </xsl:call-template>
        
                <xsl:call-template name="getRepresentationParamBlock">
                    <xsl:with-param name="style" select="'header'" />
                </xsl:call-template>
        
                <xsl:call-template name="getRepresentationParamBlock">
                    <xsl:with-param name="style" select="'query'" />
                </xsl:call-template>
            </xsl:for-each>
        </table>
    </xsl:if> 
</xsl:template><xsl:template name="getRepresentationParamBlock">
    <xsl:param name="style"/>
    <xsl:if test="wadl:param[@style=$style]">
        <tr>
            <td style="padding: 0em, 0em, 0em, 2em">
                <div class="h7"><xsl:value-of select="$style"/> params</div>
                <table>
                    <xsl:for-each select="wadl:param[@style=$style]">
                        <xsl:call-template name="getParams"/>
                    </xsl:for-each>
                </table>
                <p/>
            </td>
        </tr>
    </xsl:if>
</xsl:template>

<xsl:template name="getStyle">
     <style type="text/css">
        body {
            font-family: sans-serif;
            font-size: 0.85em;
            margin: 2em 2em;
        }
        .methods {
            margin-left: 2em; 
            margin-bottom: 2em;
        }
        .method {
            background-color: #eef;
            border: 1px solid #DDDDE6;
            padding: .5em;
            margin-bottom: 1em;
            width: 50em
        }
        .methodNameTable {
            width: 100%;
            border: 0px;
            border-bottom: 2px solid white;
            font-size: 1.4em;
        }
        .methodNameTd {
            background-color: #eef;
        }
        h1 {
            font-size: 2m;
            margin-bottom: 0em;
        }
        h2 {
            border-bottom: 1px solid black;
            margin-top: 1.5em;
            margin-bottom: 0.5em;
            font-size: 1.5em;
           }
        h3 {
            color: #FF6633;
            font-size: 1.35em;
            margin-top: .5em;
            margin-bottom: 0em;
        }
        h5 {
            font-size: 1.2em;
            color: #99a;
            margin: 0.5em 0em 0.25em 0em;
        }
        h6 {
            color: #700000;
            font-size: 1em;
            margin: 1em 0em 0em 0em;
        }
        .h7 {
            margin-top: .75em;
            font-size: 1em;
            font-weight: bold;
            font-style: italic;
            color: blue;
        }
        .h8 {
            margin-top: .75em;
            font-size: 1em;
            font-weight: bold;
            font-style: italic;
            color: black;
        }
        tt {
            font-size: 1em;
        }
        table {
            margin-bottom: 0.5em;
            border: 1px solid #E0E0E0;
        }
        th {
            text-align: left;
            font-weight: normal;
            font-size: 1em;
            color: black;
            background-color: #DDDDE6;
            padding: 3px 6px;
            border: 1px solid #B1B1B8;
        }
        td {
            padding: 3px 6px;
            vertical-align: top;
            background-color: #F6F6FF;
            font-size: 0.85em;
        }
        p {
            margin-top: 0em;
            margin-bottom: 0em;
        }
        td.summary {
            background-color: white;
        }
        td.summarySeparator {
            padding: 1px;
        }
    </style>
</xsl:template>

<xsl:template name="getTitle">
    <xsl:choose>
        <xsl:when test="wadl:doc/@title">
            <xsl:value-of select="wadl:doc/@title"/>
        </xsl:when>
        <xsl:otherwise>
            Web Application
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>
