launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #02325
[Merge] lp:~leonardr/launchpad/fix-apidoc into lp:launchpad
Leonard Richardson has proposed merging lp:~leonardr/launchpad/fix-apidoc into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~leonardr/launchpad/fix-apidoc/+merge/46161
This branch fixes bug 476974 by changing the XSLT stylesheet used to generate the HTML documentation from the WADL. Previously anything that showed up in the representation of the service root resource was considered to be a top-level collection. In this branch, only a collection showing up in the representation of the service root is considered to be a collection. This means that 'me_link' (a person) is not subjected to some code that thinks a person is a collection and some code that thinks it's an entry. It's just an entry.
I moved in the XSLT stylesheet in from launchpadlib. It was originally part of Launchpad, but was moved to launchpadlib so that third parties could see it. (This was before Launchpad was open source.) Now I'm moving it back. I'll do a launchpadlib branch that simply removes the file.
The entire XSLT stylesheet shows up as new, so I've isolated the changes I made (with sinzui's help): http://pastebin.ubuntu.com/553684/
To test this i ran bin/test -vvt apidoc, and also did a clean make, ensuring that the apidoc files were generated correctly.
I also grepped the source code for unchanged references to the XSLT file, and didn't find any.
--
https://code.launchpad.net/~leonardr/launchpad/fix-apidoc/+merge/46161
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~leonardr/launchpad/fix-apidoc into lp:launchpad.
=== modified file 'lib/canonical/launchpad/rest/wadl.py'
--- lib/canonical/launchpad/rest/wadl.py 2010-09-24 19:19:14 +0000
+++ lib/canonical/launchpad/rest/wadl.py 2011-01-13 17:55:33 +0000
@@ -46,7 +46,7 @@
# stderr file handle and then discard the output. Otherwise we let the
# subprocess inherit stderr.
stylesheet = pkg_resources.resource_filename(
- 'launchpadlib', 'wadl-to-refhtml.xsl')
+ 'lp.services.webservice', 'wadl-to-refhtml.xsl')
if suppress_stderr:
stderr = subprocess.PIPE
else:
=== added directory 'lib/lp/services/webservice'
=== added file 'lib/lp/services/webservice/__init__.py'
=== added file 'lib/lp/services/webservice/wadl-to-refhtml.xsl'
--- lib/lp/services/webservice/wadl-to-refhtml.xsl 1970-01-01 00:00:00 +0000
+++ lib/lp/services/webservice/wadl-to-refhtml.xsl 2011-01-13 17:55:33 +0000
@@ -0,0 +1,1067 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ wadl-to-refhtml.xsl
+
+ Generate HTML documentation for a webservice described in a WADL file.
+ This is tailored to WADL generated by Launchpad's web service.
+
+ Based on wadl_documentaion.xsl from Mark Nottingham <mnot@xxxxxxxxxxxxx>
+ that can be found at http://www.mnot.net/webdesc/
+ Copyright (c) 2006-2007 Yahoo! Inc.
+ Copyright (c) 2008 Canonical Ltd.
+
+ This work is licensed under the Creative Commons Attribution-ShareAlike 2.5
+ License. To view a copy of this license, visit
+ http://creativecommons.org/licenses/by-sa/2.5/
+ 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="1.0"
+ xmlns:wadl="http://research.sun.com/wadl/2006/10"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.w3.org/1999/xhtml"
+ exclude-result-prefixes="xsl wadl html"
+>
+ <xsl:output
+ method="xml"
+ encoding="UTF-8"
+ indent="yes"
+ doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
+ doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
+ />
+
+
+ <!-- Allow using key('id', 'people') to identify unique elements, since
+ the document doesn't have a parsed DTD.
+ -->
+ <xsl:key name="id" match="*[@id]" use="@id"/>
+
+ <!-- Embedded stylesheet. -->
+ <xsl:template name="css-stylesheet">
+ <style type="text/css">
+ body {
+ font-family: sans-serif;
+ font-size: 0.85em;
+ margin: 2em 8em;
+ }
+ .methods {
+ background-color: #eef;
+ padding: 1em;
+ margin-bottom: 0.5em;
+ }
+ .method {
+ padding-left: 4em;
+ }
+ h1 {
+ font-size: 2.5em;
+ }
+ h2 {
+ border-bottom: 1px solid black;
+ margin-top: 1em;
+ margin-bottom: 0.5em;
+ font-size: 2em;
+ }
+ h3 {
+ color: orange;
+ font-size: 1.75em;
+ margin-top: 1.25em;
+ margin-bottom: 0em;
+ }
+ h4 {
+ font-size: 1.50em;
+ margin: 0em;
+ padding: 0em;
+ border-bottom: 2px solid white;
+ }
+ h5 {
+ font-size: 1.25em;
+ margin-left: -3em;
+ }
+ h6 {
+ font-size: 1.1em;
+ color: #99a;
+ margin: 0.5em 0em 0.25em 0em;
+ }
+ dd {
+ margin-left: 1em;
+ }
+ tt, code {
+ font-size: 1.2em;
+ }
+ table {
+ margin-bottom: 0.5em;
+ }
+ th {
+ text-align: left;
+ font-weight: normal;
+ color: black;
+ border-bottom: 1px solid black;
+ padding: 3px 6px;
+ }
+ td {
+ padding: 3px 6px;
+ vertical-align: top;
+ background-color: #f6f6ff;
+ font-size: 0.85em;
+ }
+ td p {
+ margin: 0px;
+ }
+ ul {
+ padding-left: 1.75em;
+ }
+ p + ul, p + ol, p + dl {
+ margin-top: 0em;
+ }
+ label {
+ font-weight: bold;
+ }
+ .optional {
+ font-weight: normal;
+ opacity: 0.75;
+ }
+ .toc-link {
+ font-size: 0.85em;
+ }
+ </style>
+ </xsl:template>
+
+ <!-- Contains the base URL for the webservice without a trailing
+ slash. -->
+ <xsl:variable name="base">
+ <xsl:variable name="uri" select="//wadl:resources/@base"/>
+ <xsl:choose>
+ <xsl:when
+ test="substring($uri, string-length($uri) , 1) = '/'">
+ <xsl:value-of
+ select="substring($uri, 1, string-length($uri) - 1)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$uri"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <!-- Contains the list of top-level parameters that are links to
+ collections. Does not contain parameters that are not links to
+ collections, such as 'me_link'. -->
+ <xsl:variable name="top_level_collections"
+ select="key('id', 'service-root-json')/wadl:param[
+ contains(@name, '_collection_link')]/wadl:link" />
+
+ <!-- Generate the URL to the top-level collection. -->
+ <xsl:template name="resource-uri-doc">
+ <xsl:param name="url"><xsl:value-of
+ select="$base"/>/<xsl:value-of select="@id"/></xsl:param>
+ <p><label>URL:</label>
+ <code><xsl:copy-of select="$url" /></code></p>
+ </xsl:template>
+
+ <xsl:template name="entry-uri-doc">
+ <xsl:call-template name="resource-uri-doc">
+ <xsl:with-param name="url">
+ <xsl:choose>
+ <xsl:when test="@id = 'has_milestones'
+ or @id = 'bug_target'
+ or @id = 'has_bugs'">
+ <em>depends on the underlying entry</em>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="find-entry-uri"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template name="find-entry-uri">
+ <xsl:value-of select="$base"/>
+ <xsl:choose>
+ <xsl:when test="@id = 'archive'">
+ <xsl:text>/</xsl:text>
+ <var><distribution></var>
+ <xsl:text>/+archive/</xsl:text>
+ <var><archive.name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'archive_permission'">
+ <xsl:text>/</xsl:text>
+ <var><archive.distribution></var>
+ <xsl:text>/+archive/</xsl:text>
+ <var><archive.name></var>
+ <xsl:text>/+</xsl:text>
+ <xsl:text>name</xsl:text>
+ <xsl:text>/</xsl:text>
+ <xsl:text>person.name</xsl:text>
+ <xsl:text>.</xsl:text>
+ <xsl:text>[component or source package].name</xsl:text>
+ </xsl:when>
+ <xsl:when test="@id = 'binary_package_publishing_history'">
+ <xsl:text>/</xsl:text>
+ <var><distribution.name></var>
+ <xsl:text>/+archive/</xsl:text>
+ <var><binary_package.name></var>
+ <xsl:text>/+binarypub/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'branch'">
+ <xsl:text>/~</xsl:text>
+ <var><author.name></var>
+ <xsl:text>/</xsl:text>
+ <var><project.name></var>
+ <xsl:text>/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'branch_merge_proposal'">
+ <xsl:text>/~</xsl:text>
+ <var><author.name></var>
+ <xsl:text>/</xsl:text>
+ <var><project.name></var>
+ <xsl:text>/</xsl:text>
+ <var><branch.name></var>
+ <xsl:text>/+merge/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'bug'">
+ <xsl:text>/bugs/</xsl:text><var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'bug_attachment'">
+ <xsl:text>/bugs/</xsl:text>
+ <var><bug.id></var>
+ <xsl:text>/attachments/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'bug_subscription'">
+ <xsl:text>/bugs/</xsl:text>
+ <var><bug.id></var>
+ <xsl:text>/subscriptions/</xsl:text>
+ <var><subscriber.name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'bug_task'">
+ <xsl:text>/</xsl:text>
+ <var><target.name></var>
+ <xsl:text>/+bug/</xsl:text>
+ <var ><bug.id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'bug_watch'">
+ <xsl:text>/bugs/</xsl:text>
+ <var><bug.id></var>
+ <xsl:text>/watch/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'bug_tracker'">
+ <xsl:text>/bugs/bugtrackers/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'build'">
+ <xsl:text>/</xsl:text>
+ <var><distribution.name></var>
+ <xsl:text>/+source/</xsl:text>
+ <var><source_package.name></var>
+ <xsl:text>/+build/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'cve'">
+ <xsl:text>/bugs/cve/</xsl:text>
+ <var><sequence></var>
+ </xsl:when>
+ <xsl:when test="@id = 'distribution_source_package'">
+ <xsl:text>/</xsl:text>
+ <var><distribution.name></var>
+ <xsl:text>/+source/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'distro_arch_series'">
+ <xsl:text>/</xsl:text>
+ <var><distribution.name></var>
+ <xsl:text>/</xsl:text>
+ <var><distroseries.name></var>
+ <xsl:text>/</xsl:text>
+ <var><architecture_tag></var>
+ </xsl:when>
+ <xsl:when test="@id = 'distro_series'">
+ <xsl:text>/</xsl:text>
+ <var><distribution.name></var>
+ <xsl:text>/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'email_address'">
+ <xsl:text>/</xsl:text>
+ <var><person.name></var>
+ <xsl:text>/+email/</xsl:text>
+ <var><email></var>
+ </xsl:when>
+ <xsl:when test="@id = 'h_w_device'">
+ <xsl:text>/+hwdb/+device/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'h_w_device_class'">
+ <xsl:text>/+hwdb/+deviceclass/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'h_w_driver'">
+ <xsl:text>/+hwdb/+driver/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'h_w_submission'">
+ <xsl:text>/+hwdb/+submission/</xsl:text>
+ <var><submission-key></var>
+ </xsl:when>
+ <xsl:when test="@id = 'h_w_submission_device'">
+ <xsl:text>/+hwdb/+submissiondevice/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'h_w_vendor_i_d'">
+ <xsl:text>/+hwdb/+hwvendorid/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'jabber_id'">
+ <xsl:text>/</xsl:text>
+ <var><person.name></var>
+ <xsl:text>/+jabberid/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'irc_id'">
+ <xsl:text>/</xsl:text>
+ <var><person.name></var>
+ <xsl:text>/+ircnick/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'language'">
+ <xsl:text>/+languages/</xsl:text>
+ <var><code></var>
+ </xsl:when>
+ <xsl:when test="@id = 'message'">
+ <xsl:text>/</xsl:text>
+ <var><target.name></var>
+ <xsl:text>/+bug/</xsl:text>
+ <var><bug.id></var>
+ <xsl:text>/comments/</xsl:text>
+ <var><index></var>
+ </xsl:when>
+ <xsl:when test="@id = 'milestone'">
+ <xsl:text>/</xsl:text>
+ <var><target.name></var>
+ <xsl:text>/+milestone/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test=" @id = 'distribution'
+ or @id = 'pillar'
+ or @id = 'product'
+ or @id = 'project'
+ or @id = 'project_group'">
+ <xsl:text>/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'team' or @id = 'person'">
+ <xsl:text>/~</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'product_release'">
+ <xsl:text>/</xsl:text>
+ <var><product.name></var>
+ <xsl:text>/</xsl:text>
+ <var><product_series.name></var>
+ <xsl:text>/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'product_series'">
+ <xsl:text>/</xsl:text>
+ <var><product.name></var>
+ <xsl:text>/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'project_release'">
+ <xsl:text>/</xsl:text>
+ <var><project.name></var>
+ <xsl:text>/</xsl:text>
+ <var><project_series.name></var>
+ <xsl:text>/</xsl:text>
+ <var><release.version></var>
+ </xsl:when>
+ <xsl:when test="@id = 'project_release_file'">
+ <xsl:text>/</xsl:text>
+ <var><project.name></var>
+ <xsl:text>/</xsl:text>
+ <var><project_series.name></var>
+ <xsl:text>/</xsl:text>
+ <var><release.version></var>
+ <xsl:text>/+file/</xsl:text>
+ <var><hosted_file.filename></var>
+ </xsl:when>
+ <xsl:when test="@id = 'project_series'">
+ <xsl:text>/</xsl:text>
+ <var><project.name></var>
+ <xsl:text>/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'source_package'">
+ <xsl:text>/</xsl:text>
+ <var><distribution.name></var>
+ <xsl:text>/</xsl:text>
+ <var><distro_series.name></var>
+ <xsl:text>/+source/</xsl:text>
+ <var><name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'source_package_publishing_history'">
+ <xsl:text>/</xsl:text>
+ <var><distribution></var>
+ <xsl:text>/+archive/</xsl:text>
+ <var><name></var>
+ <xsl:text>/+sourcepub/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'team_membership'">
+ <xsl:text>/~</xsl:text>
+ <var><team.name></var>
+ <xsl:text>/+member/</xsl:text>
+ <var><member.name></var>
+ </xsl:when>
+ <xsl:when test="@id = 'wiki_name'">
+ <xsl:text>/~</xsl:text>
+ <var><person.name></var>
+ <xsl:text>/+wikiname/</xsl:text>
+ <var><id></var>
+ </xsl:when>
+ <xsl:when test="@id = 'commercial_subscription'">
+ <xsl:text>/+commercialsubscription/</xsl:text>
+ <var><commercial_subscription.id></var>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message>Unknown entry URL:
+ <xsl:value-of select="@id" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!-- We start here. -->
+ <xsl:template match="/wadl:application">
+ <xsl:variable name="title">
+ <xsl:choose>
+ <xsl:when test="wadl:doc[@title]">
+ <xsl:value-of select="wadl:doc[@title][1]/@title"/>
+ </xsl:when>
+ <xsl:otherwise>Launchpad Web Service API</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <html>
+ <head>
+ <title><xsl:value-of select="$title" /></title>
+ <xsl:call-template name="css-stylesheet"/>
+ </head>
+ <body>
+ <h1><xsl:value-of select="$title" /></h1>
+ <xsl:apply-templates select="wadl:doc"/>
+
+ <xsl:call-template name="table-of-contents" />
+ <xsl:call-template name="top-level-objects" />
+ <xsl:call-template name="entry-types" />
+ </body>
+ </html>
+ </xsl:template>
+
+ <!-- Table of contents -->
+ <xsl:template name="table-of-contents">
+ <div id="toc" title="toc">
+ <h2>Table of Contents</h2>
+ <h3>Top-level collections</h3>
+ <ul>
+ <xsl:for-each select="$top_level_collections">
+ <xsl:sort select="../@name" />
+
+ <xsl:variable name="object_id"
+ select="substring-after(@resource_type, '#')" />
+ <xsl:variable name="collection_link_name"
+ select="substring-before(
+ ../@name, '_collection_link')" />
+ <xsl:variable name="entry_link_name"
+ select="substring-before(
+ ../@name, '_link')" />
+ <xsl:if test="string-length($object_id) > 0">
+ <li><a href="#{$object_id}">
+ <xsl:choose>
+ <xsl:when test="$collection_link_name">
+ <xsl:value-of select="$collection_link_name" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$entry_link_name" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </a></li>
+ </xsl:if>
+ </xsl:for-each>
+ </ul>
+ <h3>Entry types</h3>
+ <ul>
+ <xsl:for-each select="wadl:resource_type[
+ @id != 'service-root'
+ and @id != 'HostedFile'
+ and @id != 'ScalarValue'
+ and not(contains(@id, 'page-resource'))
+ ]">
+ <xsl:sort select="@id" />
+ <xsl:variable name="id" select="./@id"/>
+ <xsl:variable name="in_top_level_collections"
+ select="$top_level_collections/@resource_type[
+ substring-after(., '#') = $id]" />
+ <xsl:if test="not($in_top_level_collections)">
+ <li><a href="#{$id}">
+ <xsl:call-template name="get-title-or-id">
+ <xsl:with-param name="element" select="." />
+ </xsl:call-template>
+ </a></li>
+ </xsl:if>
+ </xsl:for-each>
+ </ul>
+ </div>
+ </xsl:template>
+
+ <!-- Top level collections container -->
+ <xsl:template name="top-level-objects">
+ <div id="top-level-objects" title="top-level-objects">
+ <h2>Top-level collections</h2>
+ <xsl:for-each select="$top_level_collections">
+ <xsl:sort select="../@name" />
+ <xsl:variable name="object_id"
+ select="substring-after(@resource_type, '#')" />
+
+ <xsl:apply-templates
+ select="key('id', $object_id)"
+ mode="top-level-objects" />
+ </xsl:for-each>
+ </div>
+ </xsl:template>
+
+ <xsl:template name="find-root-object-uri">
+ <xsl:value-of select="$base"/>
+ <xsl:choose>
+ <xsl:when test="@id = 'hwdb'">
+ <xsl:text>/+hwdb</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>/</xsl:text><xsl:value-of select="@id" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Documentation for one top-level-object -->
+ <xsl:template match="wadl:resource_type" mode="top-level-objects">
+ <div id="{@id}" title="{@id}" class="top-level-object">
+ <h3><xsl:call-template name="get-title-or-id"/></h3>
+ <xsl:apply-templates select="wadl:doc"/>
+
+ <xsl:call-template name="resource-uri-doc">
+ <xsl:with-param name="url">
+ <!-- The default URL schema used for root objects of
+ Launchpad's webservice is
+
+ [urlbase]/[root-object-name]
+
+ e.g,
+
+ https://api.launchpad.net/beta/bugs
+
+ while the HWDB application root's URL is
+
+ https://api.launchpad.net/beta/+hwdb
+
+ In other words, the URL for the HWDB application
+ root needs to be mangled in a form similar to
+ that used for non-root objects in the template
+ "find-entry-uri".
+ -->
+
+ <xsl:call-template name="find-root-object-uri"/>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <!-- All top-level collections support a GET without arguments
+ iterating over all the resources.
+ The type of the resource is found by looking at the href attribute
+ of the default representation. Link is in the form
+ <resource>-page.
+ -->
+ <div class="methods standard">
+ <h4>Standard method</h4>
+ <xsl:variable name="default_get"
+ select="wadl:method[not(wadl:request)][1]" />
+ <xsl:variable name="resource_type"
+ select="substring-after(
+ substring-before(
+ $default_get//wadl:representation[
+ not(@mediaType)]/@href, '-page'),
+ '#')" />
+ <dl>
+ <dt>GET</dt>
+ <dd>Response contains a <a href="#{$resource_type}"
+ ><xsl:call-template name="get-title-or-id">
+ <xsl:with-param name="element"
+ select="key('id', $resource_type)" />
+ </xsl:call-template></a>
+ collection.</dd>
+ </dl>
+ </div>
+
+ <xsl:call-template name="custom-GETs" />
+ <xsl:call-template name="custom-POSTs" />
+ <a href="#toc" class="toc-link">(back to Table of Contents)</a>
+ </div>
+ </xsl:template>
+
+ <!-- Documentation for the standard methods on an entry -->
+ <xsl:template name="standard-methods">
+ <div id="{@id}-standard-methods" title="{@id}-standard-methods" class="methods standard">
+ <h4>Standard methods</h4>
+ <dl>
+ <!-- Standard methods are the ones without a ws.op param. -->
+ <xsl:apply-templates
+ select="wadl:method[not(.//wadl:param[@name = 'ws.op'])]"
+ mode="standard-method">
+ <xsl:sort select="@name"/>
+ </xsl:apply-templates>
+ </dl>
+ </div>
+ </xsl:template>
+
+ <!-- Documentation for the standard GET on an entry -->
+ <xsl:template match="wadl:method[@name='GET']" mode="standard-method">
+ <dt><xsl:value-of select="@name" /></dt>
+ <dd>Response contains the default
+ <xsl:call-template name="representation-type" /> representation
+ for this entry.
+ </dd>
+ </xsl:template>
+
+ <!-- Documentation for the standard PUT on an entry -->
+ <xsl:template match="wadl:method[@name='PUT']" mode="standard-method">
+ <dt><xsl:value-of select="@name" /></dt>
+ <dd>Entity body should contain a representation encoded using
+ <xsl:call-template name="representation-type" /> of the entry.
+ All fields of the default representation should be included. Only
+ fields marked as writeable in the default representation should be
+ modified.
+ </dd>
+ </xsl:template>
+
+ <!-- Documentation for the standard PATCH on an entry -->
+ <xsl:template match="wadl:method[@name='PATCH']" mode="standard-method">
+ <dt><xsl:value-of select="@name" /></dt>
+ <dd>Entity body should contain a represention encoded using
+ <xsl:call-template name="representation-type"/> of the entry
+ fields to update. Any fields of the default representation marked
+ as writeable can be included.
+ </dd>
+ </xsl:template>
+
+ <!-- Documentation for the custom GET operations of the resource type -->
+ <xsl:template name="custom-GETs">
+ <xsl:variable name="operations" select="wadl:method[
+ @name = 'GET'][.//wadl:param[@name = 'ws.op']]" />
+
+ <xsl:if test="$operations">
+ <div id="{@id}-custom-GETs" title="{@id}-custom-GETs" class="methods GETs">
+ <h4>Custom GET methods</h4>
+
+ <xsl:apply-templates select="$operations">
+ <xsl:sort select=".//wadl:param[@name='ws.op']/@fixed"/>
+ </xsl:apply-templates>
+ </div>
+ </xsl:if>
+ </xsl:template>
+
+ <!-- Documentation for the custom POST operations of the resource type -->
+ <xsl:template name="custom-POSTs">
+ <xsl:variable name="operations" select="wadl:method[
+ @name = 'POST'][.//wadl:param[@name = 'ws.op']]" />
+
+ <xsl:if test="$operations">
+ <div id="{@id}-custom-POSTs" title="{@id}-custom-POSTs" class="methods POSTs">
+ <h4>Custom POST methods</h4>
+
+ <xsl:apply-templates select="$operations">
+ <xsl:sort select=".//wadl:param[@name='ws.op']/@fixed"/>
+ </xsl:apply-templates>
+ </div>
+ </xsl:if>
+ </xsl:template>
+
+ <!-- Container for all the entry types documentation -->
+ <xsl:template name="entry-types">
+ <h2 id="entry-types" title="entry-types">Entry types</h2>
+
+ <!-- Process all the resource_types, except the service root,
+ special types like HostedFile, and the top-level collections. -->
+ <xsl:for-each select="wadl:resource_type[
+ @id != 'service-root'
+ and @id != 'HostedFile'
+ and @id != 'ScalarValue'
+ and not(contains(@id, 'page-resource'))
+ ]">
+ <xsl:sort select="@id" />
+ <xsl:variable name="id" select="./@id"/>
+ <xsl:variable name="in_top_level_collections"
+ select="$top_level_collections/@resource_type[
+ substring-after(., '#') = $id]" />
+ <xsl:if test="not($in_top_level_collections)">
+ <xsl:apply-templates select="." mode="entry-types" />
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!-- Documentation for one entry-type -->
+ <xsl:template match="wadl:resource_type" mode="entry-types">
+ <h3 id="{@id}" title="{@id}"><xsl:call-template name="get-title-or-id"/></h3>
+ <xsl:apply-templates select="wadl:doc"/>
+
+ <xsl:call-template name="entry-uri-doc"/>
+
+ <xsl:call-template name="default-representation" />
+ <xsl:call-template name="standard-methods" />
+ <xsl:call-template name="custom-GETs" />
+ <xsl:call-template name="custom-POSTs" />
+ <a href="#toc" class="toc-link">(back to Table of Contents)</a>
+ </xsl:template>
+
+ <!-- Documentation of the default representation for an entry -->
+ <xsl:template name="default-representation">
+ <xsl:variable name="default_get" select="wadl:method[
+ @name = 'GET' and not(wadl:request)]" />
+ <xsl:variable name="representation" select="key(
+ 'id', substring-after(
+ $default_get/wadl:response/wadl:representation[
+ not(@mediaType)]/@href, '#'))"/>
+
+ <div class="representation">
+ <h4>Default representation
+ (<xsl:value-of select="$representation/@mediaType"/>)</h4>
+
+ <table>
+ <tr>
+ <th>Key</th>
+ <th>Value</th>
+ <th>Description</th>
+ </tr>
+ <xsl:apply-templates select="$representation/wadl:param"
+ mode="representation">
+ <xsl:sort select="@name"/>
+ </xsl:apply-templates>
+ </table>
+ </div>
+ </xsl:template>
+
+ <!-- Output the cell containing the field name.
+
+ current() should be a wadl:param.
+ -->
+ <xsl:template name="param-name">
+ <td>
+ <p><strong><xsl:value-of select="@name"/></strong></p>
+ </td>
+ </xsl:template>
+
+ <!-- Output a table cell containing the parameter description.
+
+ current() should a wadl:param.
+ -->
+ <xsl:template name="param-description">
+ <td>
+ <xsl:apply-templates select="wadl:doc"/>
+ <xsl:if test="wadl:option[wadl:doc]">
+ <dl>
+ <xsl:apply-templates
+ select="wadl:option" mode="option-doc"/>
+ </dl>
+ </xsl:if>
+ </td>
+ </xsl:template>
+
+ <!-- Output information about the parameter value.
+
+ current() should be a wadl:param.
+ -->
+ <xsl:template name="param-value">
+ <xsl:if test="wadl:option">
+ <p><em>One of:</em></p>
+ <ul>
+ <xsl:apply-templates select="wadl:option"/>
+ </ul>
+ </xsl:if>
+ <xsl:apply-templates select="wadl:link[@resource_type]"/>
+ <xsl:if test="@default">
+ <p>
+ Default:
+ <var><xsl:value-of select="@default"/></var>
+ </p>
+ </xsl:if>
+ <xsl:if test="@fixed">
+ <p>
+ Fixed:
+ <var><xsl:value-of select="@fixed"/></var>
+ </p>
+ </xsl:if>
+ </xsl:template>
+
+ <!-- Output row describing one field in the default representation -->
+ <xsl:template match="wadl:param" mode="representation">
+ <xsl:variable name="resource_type"
+ select="substring-before(../@id, '-')" />
+ <xsl:variable name="patch_representation_id"
+ ><xsl:value-of select="$resource_type"/>-diff</xsl:variable>
+ <xsl:variable name="patch_representation"
+ select="key('id', $patch_representation_id)"/>
+ <tr>
+ <xsl:call-template name="param-name"/>
+ <td>
+ <p>
+ <xsl:choose>
+ <xsl:when test="$patch_representation/wadl:param[@name
+ = current()/@name]">
+ <small>(writeable)</small>
+ </xsl:when>
+ <xsl:otherwise>
+ <small>(read-only)</small>
+ </xsl:otherwise>
+ </xsl:choose>
+ </p>
+ <xsl:call-template name="param-value" />
+ </td>
+ <xsl:call-template name="param-description" />
+ </tr>
+ </xsl:template>
+
+ <!-- Output the description of a link type in param listing -->
+ <xsl:template match="wadl:link[
+ @resource_type and ../@name != 'self_link']">
+ <xsl:variable name="resource_type"
+ select="substring-after(@resource_type, '#')"/>
+ <xsl:choose>
+ <xsl:when test="contains($resource_type, 'page-resource')">
+ Link to a <a href="#{substring-before($resource_type, '-')}"
+ ><xsl:value-of
+ select="substring-before($resource_type, '-')"
+ /></a> collection.
+ </xsl:when>
+ <xsl:when test="$resource_type = 'HostedFile'">
+ Link to a file resource.
+ </xsl:when>
+ <xsl:otherwise>
+ Link to a <a href="#{$resource_type}"
+ ><xsl:value-of select="$resource_type"/></a>.
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Documentation for a custom method -->
+ <xsl:template match="wadl:method[.//wadl:param[@name = 'ws.op']]">
+ <div class="method">
+ <h5 id="{@id}" title="{@id}"><xsl:value-of
+ select=".//wadl:param[@name = 'ws.op']/@fixed"/></h5>
+ <xsl:choose>
+ <xsl:when test="wadl:doc|wadl:request|wadl:response">
+ <xsl:apply-templates select="wadl:doc"/>
+ <xsl:apply-templates select="wadl:request"/>
+ <xsl:apply-templates select="wadl:response"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <p><em>Missing documentation.</em></p>
+ </xsl:otherwise>
+ </xsl:choose>
+ </div>
+ </xsl:template>
+
+ <!-- Documentation for the request parameters of a custom method -->
+ <xsl:template match="wadl:request">
+ <h6>Parameters</h6>
+ <table>
+ <tr>
+ <th>Parameter</th>
+ <th>Value</th>
+ <th>Description</th>
+ </tr>
+ <xsl:apply-templates
+ select=".//wadl:param[@style='query'][@fixed]"/>
+ <xsl:apply-templates
+ select=".//wadl:param[@style='query'][not(@fixed)]">
+ <xsl:sort select="@name" />
+ </xsl:apply-templates>
+ </table>
+ </xsl:template>
+
+ <!-- Documentation for the response of custom methods returning
+ and entry or a collection.
+ -->
+ <xsl:template match="wadl:response/wadl:representation[@href]">
+ <xsl:variable name="id" select="substring-after(@href, '#')" />
+ <xsl:variable name="resource_type"
+ select="substring-before($id, '-')"/>
+
+ <p class="response">Response contains an
+ <xsl:apply-templates select="key('id', $id)"
+ mode="representation-type"/>
+ representation of a
+ <a href="#{$resource_type}"><xsl:value-of
+ select="$resource_type"
+ /></a><xsl:if test="contains($id, '-page')">
+ collection
+ </xsl:if>.
+ </p>
+ </xsl:template>
+
+ <!-- Documentation for request parameter. -->
+ <xsl:template match="wadl:param">
+ <tr>
+ <xsl:call-template name="param-name"/>
+ <td>
+ <xsl:if test="@required or @repeating">
+ <p>
+ <xsl:if test="@required='true'">
+ <small>(required)</small>
+ </xsl:if>
+ <xsl:if test="@repeating='true'">
+ <small>(repeating)</small>
+ </xsl:if>
+ </p>
+ </xsl:if>
+ <xsl:call-template name="param-value"/>
+ </td>
+ <xsl:call-template name="param-description"/>
+ </tr>
+ </xsl:template>
+
+ <!-- Documentation for factories.
+
+ Factory's response include a Location header pointint to a resource type.
+ -->
+ <xsl:template match="wadl:response/wadl:param[
+ @name = 'Location' and @style = 'header'
+ and wadl:link[@resource_type]]">
+ <xsl:variable name="resource_type"
+ select="substring-after(
+ wadl:link[@resource_type]/@resource_type, '#')"/>
+ <p>On success, the response status will be 201 and the
+ <var>Location</var> header will contain the link to the newly
+ created <a href="#{$resource_type}"
+ ><xsl:value-of select="$resource_type" /></a>.
+ </p>
+ </xsl:template>
+
+ <!-- Output the available value for the parameter. -->
+ <xsl:template match="wadl:option">
+ <li>
+ <tt><xsl:value-of select="@value"/></tt>
+ <xsl:if test="ancestor::wadl:param[1]/@default=@value">
+ <small>(default)</small>
+ </xsl:if>
+ </li>
+ </xsl:template>
+
+ <!-- Ouput list of the documentation for each available option. -->
+ <xsl:template match="wadl:option" mode="option-doc">
+ <dt>
+ <tt><xsl:value-of select="@value"/></tt>
+ <xsl:if test="ancestor::wadl:param[1]/@default=@value">
+ <small>(default)</small>
+ </xsl:if>
+ </dt>
+ <dd>
+ <xsl:apply-templates select="wadl:doc"/>
+ </dd>
+ </xsl:template>
+
+ <!-- Format wadl:doc -->
+ <xsl:template match="wadl:doc">
+ <xsl:param name="inline">0</xsl:param>
+ <!-- skip WADL elements -->
+ <xsl:choose>
+ <xsl:when test="node()[1]=text() and $inline=0">
+ <!-- If the wadl:doc contains <p> tags wrap it in a <div>,
+ otherwise wrap it in a <p> tag. -->
+ <xsl:choose>
+ <xsl:when test="./html:p">
+ <div>
+ <xsl:apply-templates select="node()" mode="copy"/>
+ </div>
+ </xsl:when>
+ <xsl:otherwise>
+ <p>
+ <xsl:apply-templates select="node()" mode="copy"/>
+ </p>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="node()" mode="copy"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Returns the title or id of an element.
+
+ Look for the first wadl:doc title attribute content of the
+ current node or fall back to the element id.
+
+ :param element: The element to return the title or id. Defaults to the
+ current node.
+ -->
+ <xsl:template name="get-title-or-id">
+ <xsl:param name="element" select="current()" />
+ <xsl:choose>
+ <xsl:when test="$element/wadl:doc[@title]">
+ <xsl:value-of select="$element/wadl:doc[@title][1]/@title"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$element/@id"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Output the mediaType attribute of the default representation.
+
+ Should be call on an element that contain a wadl:representation element
+ without a mediaType attribute.
+ -->
+ <xsl:template name="representation-type">
+ <xsl:apply-templates
+ select="key('id',
+ substring-after(
+ .//wadl:representation[not(@mediaType)]/@href,
+ '#'))"
+ mode="representation-type"/>
+ </xsl:template>
+
+ <!-- Omit docutils parameter lists in methods since they are redundant
+ or misleading with the one we give. -->
+ <xsl:template match="wadl:method//html:table[
+ contains(@class, 'field-list')]"
+ mode="copy"/>
+
+ <!-- Output the mediaType attribute of a representation -->
+ <xsl:template match="wadl:representation[@mediaType]"
+ mode="representation-type">
+ <code><xsl:value-of select="@mediaType"/></code>
+ </xsl:template>
+
+ <!-- Copy html elements. -->
+ <xsl:template match="html:*" mode="copy">
+ <!-- remove the prefix on HTML elements -->
+ <xsl:element name="{local-name()}">
+ <xsl:for-each select="@*">
+ <xsl:attribute name="{local-name()}"
+ ><xsl:value-of select="."/></xsl:attribute>
+ </xsl:for-each>
+ <xsl:apply-templates select="node()" mode="copy"/>
+ </xsl:element>
+ </xsl:template>
+
+ <xsl:template match="@*|node()[
+ namespace-uri()!='http://www.w3.org/1999/xhtml']" mode="copy">
+ <!-- everything else goes straight through -->
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" mode="copy"/>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>