1 <xsl:stylesheet version="3.0"
2 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 xmlns:xs="http://www.w3.org/2001/XMLSchema"
4 xmlns:d="http://github.com/vinniefalco/docca"
5 exclude-result-prefixes="xs d"
8 <!-- TODO: make sure this doesn't screw up any formatting -->
9 <!-- NEW TODO: verify we don't need/want this -->
11 <xsl:output indent="yes"/>
14 <xsl:include href="common.xsl"/>
16 <xsl:key name="visible-memberdefs-by-id"
17 match="memberdef[$include-private-members or not(@prot eq 'private')]"
20 <xsl:key name="elements-by-refid" match="compound | member" use="@refid"/>
22 <xsl:variable name="index-xml" select="/"/>
24 <xsl:template match="/">
26 <xsl:apply-templates select="/doxygenindex/compound"/>
28 <!-- Testing the ID-related functions
29 <xsl:value-of select="replace(d:extract-ns('put'), '::$', '')"/>
30 <xsl:text>
</xsl:text>
31 <xsl:value-of select="replace(d:extract-ns('foobar::parser::put'), '::$', '')"/>
32 <xsl:text>
</xsl:text>
33 <xsl:value-of select="d:extract-ns('foobar::parser::put<foo::bar, bat::bang>')"/>
34 <xsl:text>
</xsl:text>
35 <xsl:value-of select="d:strip-ns('boost::beast::http::parser::basic_parser< foo::isRequest, bar::parser >')"/>
36 <xsl:text>
</xsl:text>
37 <xsl:value-of select="d:strip-doc-ns('boost::beast::http::parser::basic_parser< foo::isRequest, bar::parser >')"/>
38 <xsl:text>
</xsl:text>
39 <xsl:text>
</xsl:text>
40 <xsl:value-of select="d:make-id('boost::beast::http::parser::basic_parser< foo::isRequest, bar::parser >')"/>
44 <!-- Default implementation; can be customized/overridden -->
45 <xsl:function name="d:should-ignore-compound">
46 <xsl:param name="compound" as="element(compound)"/>
47 <xsl:sequence select="false()"/>
50 <xsl:template match="compound[d:should-ignore-compound(.)]"/>
51 <xsl:template match="compound">
52 <!-- Load each input file only once -->
53 <xsl:variable name="source-doc" select="d:get-source-doc(.)"/>
54 <!-- Ignore private classes unless private members are enabled -->
55 <xsl:if test="$include-private-members or not($source-doc/doxygen/compounddef/@prot eq 'private')">
56 <!-- Look up memberdefs (and constrain by visibility) only once -->
57 <xsl:variable name="memberdefs" select="key('visible-memberdefs-by-id', member/@refid, $source-doc)"/>
58 <!-- Create a filtered copy of members within their minimal context, listing only the visible ones -->
59 <xsl:variable name="visible-members" as="element(member)*">
60 <xsl:variable name="compound" as="element()">
61 <compound kind="{@kind}" refid="{@refid}">
63 <xsl:copy-of select="member[@refid = $memberdefs/@id]"/>
66 <xsl:sequence select="$compound/member"/>
68 <xsl:apply-templates mode="create-page" select=".">
69 <xsl:with-param name="source-doc" select="$source-doc" tunnel="yes"/>
70 <xsl:with-param name="memberdefs" select="$memberdefs" tunnel="yes"/>
71 <xsl:with-param name="visible-members" select="$visible-members" tunnel="yes"/>
72 </xsl:apply-templates>
76 <xsl:function name="d:get-source-doc" as="document-node()">
77 <xsl:param name="compound" as="element(compound)"/>
78 <xsl:sequence select="document($compound/@refid||'.xml', $index-xml)"/>
81 <!-- Split up the content into class, struct, and member pages -->
82 <xsl:template mode="create-page" match="*"/>
83 <xsl:template mode="create-page" match="compound[@kind = 'namespace']">
84 <xsl:apply-templates mode="child-pages" select="."/>
86 <xsl:template mode="create-page" match="compound[@kind = ('class','struct')]
88 <xsl:variable name="page-id" as="xs:string">
89 <xsl:apply-templates mode="page-id" select="."/>
91 <page id="{$page-id}" href="{$page-id}.xml">
92 <xsl:result-document href="xml-pages/{$page-id}.xml">
93 <xsl:apply-templates mode="page-content" select=".">
94 <xsl:with-param name="page-id" select="$page-id" tunnel="yes"/>
95 </xsl:apply-templates>
96 </xsl:result-document>
97 <xsl:apply-templates mode="child-pages" select="."/>
101 <!-- Create the member page for each child (or, if overloaded, the overload-list page) -->
102 <xsl:template mode="child-pages" match="compound">
103 <xsl:param name="visible-members" tunnel="yes"/>
104 <!-- Create a page for each unique member name -->
105 <xsl:for-each select="$visible-members[not(name = preceding-sibling::member/name)]">
106 <xsl:apply-templates mode="create-page" select=".">
107 <xsl:with-param name="is-overload-list-page" select="d:is-overloaded(.)" tunnel="yes"/>
108 </xsl:apply-templates>
112 <!-- A member page doesn't have children, unless it is an overload-list page -->
113 <xsl:template mode="child-pages" match="compound/member">
114 <xsl:param name="is-overload-list-page" tunnel="yes"/>
115 <xsl:if test="$is-overload-list-page">
116 <xsl:apply-templates mode="create-page" select="d:overloaded-members(.)">
117 <xsl:with-param name="is-overload-list-page" select="false()" tunnel="yes"/>
118 </xsl:apply-templates>
123 <xsl:template mode="page-id" match="compound">{d:make-id(name)}</xsl:template>
124 <xsl:template mode="page-id" match="member">
125 <xsl:param name="is-overload-list-page" tunnel="yes"/>
127 <xsl:apply-templates mode="base-member-page-id" select="."/>
128 <!-- Append the overload-specific suffix, if applicable -->
129 <xsl:if test="d:is-overloaded(.) and not($is-overload-list-page)">
130 <xsl:value-of select="d:make-id('.overload'||d:overload-position(.))"/>
135 <xsl:function name="d:is-overloaded" as="xs:boolean">
136 <xsl:param name="member" as="element(member)"/>
137 <xsl:sequence select="exists(d:overloaded-members($member)[2])"/>
140 <xsl:function name="d:overload-position" as="xs:integer">
141 <xsl:param name="member" as="element(member)"/>
142 <xsl:sequence select="1 + count($member/preceding-sibling::member[name eq $member/name])"/>
145 <xsl:function name="d:overloaded-members" as="element(member)+">
146 <xsl:param name="member" as="element(member)"/>
147 <xsl:sequence select="$member/../member[name eq $member/name]"/>
151 <xsl:template mode="base-member-page-id" priority="1"
152 match="compound[@kind eq 'namespace']
153 /member">{d:make-id(../name||'::'||name)}</xsl:template>
154 <xsl:template mode="base-member-page-id" match="compound/member">{d:make-id(../name||'.' ||name)}</xsl:template>
157 <!-- The content for a class or struct is the original source document, pared down some -->
158 <xsl:template mode="page-content" match="compound">
159 <xsl:param name="source-doc" tunnel="yes"/>
160 <xsl:apply-templates mode="compound-page" select="$source-doc"/>
163 <!-- By default, copy everything -->
164 <xsl:template mode="compound-page" match="@* | node()" name="copy-in-compound-page">
166 <xsl:apply-templates mode="#current" select="@*"/>
167 <xsl:apply-templates mode="compound-page-insert" select="."/>
168 <xsl:apply-templates mode="#current"/>
172 <!-- By default, don't insert anything -->
173 <xsl:template mode="compound-page-insert" match="*"/>
175 <xsl:template mode="compound-page" match="listofallmembers"/>
177 <xsl:template mode="compound-page" match="memberdef/@*"/>
179 <!-- But directly inside <memberdef>, don't copy anything... -->
180 <xsl:template mode="compound-page" match="memberdef/node()"/>
182 <!-- ...except for <name>, <briefdescription>, and <type> -->
183 <xsl:template mode="compound-page" match="memberdef/name
184 | memberdef/briefdescription
185 | memberdef/type" priority="1">
186 <xsl:call-template name="copy-in-compound-page"/>
189 <!-- Insert a reference to each child member's page ID -->
190 <xsl:template mode="compound-page-insert" match="memberdef">
191 <xsl:attribute name="d:page-refid" select="d:make-id(/doxygen/compounddef/compoundname||'.'||name)"/>
194 <!-- Alternative implementation in case we need to start controlling whitespace more
195 <xsl:template mode="compound-page" match="memberdef">
197 <xsl:text>
</xsl:text>
198 <xsl:copy-of select="name"/>
199 <xsl:text>
</xsl:text>
200 <xsl:copy-of select="briefdescription"/>
205 <!-- The content for a member page is a subset of the source document -->
206 <xsl:template mode="page-content" match="compound/member">
207 <xsl:param name="is-overload-list-page" tunnel="yes"/>
209 <xsl:when test="$is-overload-list-page">
210 <!-- For the overload list page, include the content for every like-named member -->
211 <xsl:apply-templates mode="list-page" select=".">
212 <xsl:with-param name="applicable-members" select="d:overloaded-members(.)" tunnel="yes"/>
213 </xsl:apply-templates>
216 <!-- Otherwise, this page is just for one implementation (whether overloaded or not) -->
217 <xsl:apply-templates mode="member-page" select="."/>
222 <xsl:template mode="list-page member-page" match="member" priority="2">
223 <xsl:param name="applicable-members" as="element(member)+" select="." tunnel="yes"/>
224 <xsl:param name="source-doc" tunnel="yes"/>
225 <xsl:param name="memberdefs" tunnel="yes"/>
226 <xsl:apply-templates mode="#current" select="$source-doc">
227 <xsl:with-param name="target-memberdefs"
228 select="$memberdefs[@id = $applicable-members/@refid]"
230 <xsl:with-param name="member" select="." tunnel="yes"/>
231 </xsl:apply-templates>
234 <!-- Always copy the name of the parent compound -->
235 <xsl:template mode="list-page member-page" match="compoundname" priority="2">
236 <xsl:copy-of select="."/>
239 <!-- Otherwise, only copy an element if it's the target member or one of its ancestors -->
240 <xsl:template mode="list-page member-page" match="*" priority="1">
241 <xsl:param name="target-memberdefs" tunnel="yes"/>
242 <xsl:if test=". intersect $target-memberdefs/ancestor-or-self::*">
247 <!-- By default, copy everything -->
248 <xsl:template mode="list-page" match="@* | node()">
250 <xsl:apply-templates mode="#current" select="@*"/>
251 <xsl:apply-templates mode="list-page-insert" select="."/>
252 <xsl:apply-templates mode="#current"/>
256 <!-- By default, don't insert anything -->
257 <xsl:template mode="list-page-insert" match="*"/>
260 <!-- By default, copy everything -->
261 <xsl:template mode="member-page
262 copy-member-content" match="@* | node()">
264 <xsl:apply-templates mode="#current" select="@*"/>
265 <xsl:apply-templates mode="member-page-insert" select="."/>
266 <xsl:apply-templates mode="#current"/>
267 <xsl:apply-templates mode="member-page-append" select="."/>
271 <!-- By default, don't insert or append anything -->
272 <xsl:template mode="member-page-insert
273 member-page-append" match="*"/>
275 <!-- Strip out extraneous whitespace -->
276 <xsl:template mode="list-page member-page" match="compounddef/text() | sectiondef/text()"/>
278 <!-- Switch to an unfiltered copy once we're done filtering out the undesired elements -->
279 <xsl:template mode="list-page member-page" match="memberdef/node()" priority="2">
280 <xsl:apply-templates mode="copy-member-content" select="."/>
283 <!-- Add the page ID to the top of all page types -->
284 <xsl:template mode="compound-page-insert
286 list-page-insert" match="/doxygen" priority="2">
287 <xsl:param name="page-id" tunnel="yes"/>
288 <xsl:attribute name="d:page-id" select="$page-id"/>
292 <!-- Also, if applicable, insert the overload position and/or base compound reference of this member -->
293 <xsl:template mode="member-page-insert" match="/doxygen" priority="1">
294 <xsl:param name="member" tunnel="yes"/>
295 <xsl:if test="d:is-overloaded($member)">
296 <xsl:attribute name="d:overload-position" select="d:overload-position($member)"/>
297 <xsl:attribute name="d:overload-size" select="count(d:overloaded-members($member))"/>
299 <xsl:if test="$member[not(starts-with(@refid, ../@refid))]">
300 <xsl:variable name="base-compound" select="$index-xml/*/compound[starts-with($member/@refid, @refid)]
301 [not(d:should-ignore-compound(.))]"/>
302 <xsl:apply-templates mode="base-compound-atts" select="$base-compound"/>
307 <xsl:template mode="base-compound-atts" match="compound">
308 <xsl:attribute name="d:base-compound-name" select="d:strip-doc-ns(name)"/>
309 <xsl:attribute name="d:base-compound-refid">
310 <xsl:apply-templates mode="page-id" select="."/>
314 <!-- Make data available for the typedef tables, if applicable -->
315 <xsl:template mode="member-page-append" match="memberdef[@kind eq 'typedef']
317 [not(contains(type, '*'))]">
318 <xsl:for-each select="type/ref">
319 <d:referenced-typedef-class>
320 <xsl:variable name="compound" select="d:get-target-element(.)[self::compound]"/>
321 <xsl:apply-templates mode="compound-page" select="$compound ! d:get-source-doc(.)/*/compounddef"/>
322 </d:referenced-typedef-class>
326 <!-- Finally, add the page type -->
327 <xsl:template mode="compound-page-insert" match="/doxygen">
328 <xsl:attribute name="d:page-type" select="'compound'"/>
330 <xsl:template mode="member-page-insert" match="/doxygen">
331 <xsl:attribute name="d:page-type" select="'member'"/>
333 <xsl:template mode="list-page-insert" match="/doxygen">
334 <xsl:attribute name="d:page-type" select="'overload-list'"/>
337 <!-- For overload-list pages, include the page id for each member -->
338 <xsl:template mode="list-page-insert" match="memberdef">
339 <xsl:param name="applicable-members" tunnel="yes"/>
340 <xsl:variable name="this-id" select="@id"/>
341 <xsl:variable name="original-member" select="$applicable-members[@refid eq $this-id]"/>
342 <xsl:attribute name="d:page-refid">
343 <xsl:apply-templates mode="page-id" select="$original-member">
344 <xsl:with-param name="is-overload-list-page" select="false()" tunnel="yes"/>
345 </xsl:apply-templates>
349 <!-- For public innerclasses, insert the referenced class inline -->
350 <xsl:template mode="compound-page-insert" match="innerclass[@prot eq 'public']">
351 <xsl:attribute name="d:page-refid" select="d:make-id(.)"/>
352 <d:referenced-inner-class>
353 <xsl:variable name="compound" select="d:get-target-element(.)" as="element(compound)"/>
354 <xsl:apply-templates mode="compound-page" select="d:get-source-doc($compound)/*/compounddef"/>
355 </d:referenced-inner-class>
358 <!-- Resolve the referenced page IDs for later link generation -->
359 <xsl:template mode="compound-page-insert member-page-insert" match="ref">
360 <xsl:attribute name="d:refid">
361 <xsl:apply-templates mode="page-id" select="d:get-target-element(.)">
362 <!-- For inline links to member pages, only link to the base page id (no overloads) -->
363 <xsl:with-param name="is-overload-list-page" select="true()" tunnel="yes"/>
364 </xsl:apply-templates>
368 <xsl:function name="d:get-target-element" as="element()?"> <!-- to allow for partial builds -->
370 <xsl:function name="d:get-target-element" as="element()">
372 <xsl:param name="ref" as="element()"/> <!-- <ref> or <innerclass> or... -->
373 <xsl:variable name="referenced-elements" select="key('elements-by-refid', $ref/@refid, $index-xml)"/>
374 <xsl:variable name="result" as="element()?">
376 <!-- Handle the case where the referenced element appears two or more times in index.xml -->
377 <!-- If there's no ambiguity, we're done! -->
378 <xsl:when test="count($referenced-elements) eq 1">
379 <xsl:apply-templates mode="find-target-element" select="$referenced-elements"/>
382 <!-- Otherwise, see if a namespace in the link text successfully disambiguates -->
383 <xsl:variable name="qualified-reference" as="element()*">
384 <xsl:variable name="parent-in-link-text"
385 select="if (contains($ref,'::'))
386 then d:extract-ns-without-suffix($ref)
388 <xsl:sequence select="$referenced-elements[ends-with(parent::compound/name, '::'||$parent-in-link-text)]"/>
391 <xsl:when test="count($qualified-reference) eq 1">
392 <xsl:apply-templates mode="find-target-element" select="$qualified-reference"/>
395 <!-- Otherwise, favor the member that's in the same class or namespace as the current page -->
396 <xsl:variable name="sibling-reference" as="element()*">
397 <xsl:variable name="compound-for-current-page" select="root($ref)/doxygen/compounddef/compoundname/string()"/>
398 <xsl:sequence select="$referenced-elements[parent::compound/name eq $compound-for-current-page]"/>
401 <xsl:when test="count($sibling-reference) eq 1">
402 <xsl:apply-templates mode="find-target-element" select="$sibling-reference"/>
404 <!-- If all else fails, give up and just use the first one -->
406 <xsl:apply-templates mode="find-target-element" select="$referenced-elements[1]"/>
414 <xsl:if test="not($result)">
415 <xsl:message>Unable to find referenced ID: <xsl:value-of select="$ref/@refid"/></xsl:message>
417 <xsl:sequence select="$result"/>
420 <xsl:template mode="find-target-element" match="compound | member">
421 <xsl:sequence select="."/>
424 <!-- In the index XML, enumvalue "members" immediately follow the corresponding enum member -->
425 <xsl:template mode="find-target-element" match="member[@kind eq 'enumvalue']">
426 <xsl:sequence select="preceding-sibling::member[@kind eq 'enum'][1]"/>