Home | History | Annotate | Download | only in xslt
      1 <?xml version="1.0" encoding="UTF-8"?>
      2 
      3 <!--
      4     xml2text.xsl - transform Bison XML Report into plain text.
      5 
      6     Copyright (C) 2007-2012 Free Software Foundation, Inc.
      7 
      8     This file is part of Bison, the GNU Compiler Compiler.
      9 
     10     This program is free software: you can redistribute it and/or modify
     11     it under the terms of the GNU General Public License as published by
     12     the Free Software Foundation, either version 3 of the License, or
     13     (at your option) any later version.
     14 
     15     This program is distributed in the hope that it will be useful,
     16     but WITHOUT ANY WARRANTY; without even the implied warranty of
     17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18     GNU General Public License for more details.
     19 
     20     You should have received a copy of the GNU General Public License
     21     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     22 
     23     Written by Wojciech Polak <polak (a] gnu.org>.
     24   -->
     25 
     26 <xsl:stylesheet version="1.0"
     27   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     28   xmlns:bison="http://www.gnu.org/software/bison/">
     29 
     30 <xsl:import href="bison.xsl"/>
     31 <xsl:output method="text" encoding="UTF-8" indent="no"/>
     32 
     33 <xsl:template match="/">
     34   <xsl:apply-templates select="bison-xml-report"/>
     35 </xsl:template>
     36 
     37 <xsl:template match="bison-xml-report">
     38   <xsl:apply-templates select="grammar" mode="reductions"/>
     39   <xsl:apply-templates select="grammar" mode="useless-in-parser"/>
     40   <xsl:apply-templates select="automaton" mode="conflicts"/>
     41   <xsl:apply-templates select="grammar"/>
     42   <xsl:apply-templates select="automaton"/>
     43 </xsl:template>
     44 
     45 <xsl:template match="grammar" mode="reductions">
     46   <xsl:apply-templates select="nonterminals" mode="useless-in-grammar"/>
     47   <xsl:apply-templates select="terminals" mode="unused-in-grammar"/>
     48   <xsl:apply-templates select="rules" mode="useless-in-grammar"/>
     49 </xsl:template>
     50 
     51 <xsl:template match="nonterminals" mode="useless-in-grammar">
     52   <xsl:if test="nonterminal[@usefulness='useless-in-grammar']">
     53     <xsl:text>Nonterminals useless in grammar&#10;&#10;</xsl:text>
     54     <xsl:for-each select="nonterminal[@usefulness='useless-in-grammar']">
     55       <xsl:text>   </xsl:text>
     56       <xsl:value-of select="@name"/>
     57       <xsl:text>&#10;</xsl:text>
     58     </xsl:for-each>
     59     <xsl:text>&#10;&#10;</xsl:text>
     60   </xsl:if>
     61 </xsl:template>
     62 
     63 <xsl:template match="terminals" mode="unused-in-grammar">
     64   <xsl:if test="terminal[@usefulness='unused-in-grammar']">
     65     <xsl:text>Terminals unused in grammar&#10;&#10;</xsl:text>
     66     <xsl:for-each select="terminal[@usefulness='unused-in-grammar']">
     67       <xsl:sort select="@symbol-number" data-type="number"/>
     68       <xsl:text>   </xsl:text>
     69       <xsl:value-of select="@name"/>
     70       <xsl:text>&#10;</xsl:text>
     71     </xsl:for-each>
     72     <xsl:text>&#10;&#10;</xsl:text>
     73   </xsl:if>
     74 </xsl:template>
     75 
     76 <xsl:template match="rules" mode="useless-in-grammar">
     77   <xsl:variable name="set" select="rule[@usefulness='useless-in-grammar']"/>
     78   <xsl:if test="$set">
     79     <xsl:text>Rules useless in grammar&#10;</xsl:text>
     80     <xsl:call-template name="style-rule-set">
     81       <xsl:with-param name="rule-set" select="$set"/>
     82     </xsl:call-template>
     83     <xsl:text>&#10;&#10;</xsl:text>
     84   </xsl:if>
     85 </xsl:template>
     86 
     87 <xsl:template match="grammar" mode="useless-in-parser">
     88   <xsl:variable
     89     name="set" select="rules/rule[@usefulness='useless-in-parser']"
     90   />
     91   <xsl:if test="$set">
     92     <xsl:text>Rules useless in parser due to conflicts&#10;</xsl:text>
     93     <xsl:call-template name="style-rule-set">
     94       <xsl:with-param name="rule-set" select="$set"/>
     95     </xsl:call-template>
     96     <xsl:text>&#10;&#10;</xsl:text>
     97   </xsl:if>
     98 </xsl:template>
     99 
    100 <xsl:template match="grammar">
    101   <xsl:text>Grammar&#10;</xsl:text>
    102   <xsl:call-template name="style-rule-set">
    103     <xsl:with-param
    104       name="rule-set" select="rules/rule[@usefulness!='useless-in-grammar']"
    105     />
    106   </xsl:call-template>
    107   <xsl:text>&#10;&#10;</xsl:text>
    108   <xsl:apply-templates select="terminals"/>
    109   <xsl:apply-templates select="nonterminals"/>
    110 </xsl:template>
    111 
    112 <xsl:template name="style-rule-set">
    113   <xsl:param name="rule-set"/>
    114   <xsl:for-each select="$rule-set">
    115     <xsl:apply-templates select=".">
    116       <xsl:with-param name="pad" select="'3'"/>
    117       <xsl:with-param name="prev-lhs">
    118         <xsl:if test="position()>1">
    119           <xsl:variable name="position" select="position()"/>
    120           <xsl:value-of select="$rule-set[$position - 1]/lhs"/>
    121         </xsl:if>
    122       </xsl:with-param>
    123     </xsl:apply-templates>
    124   </xsl:for-each>
    125 </xsl:template>
    126 
    127 <xsl:template match="grammar/terminals">
    128   <xsl:text>Terminals, with rules where they appear&#10;&#10;</xsl:text>
    129   <xsl:apply-templates select="terminal"/>
    130   <xsl:text>&#10;&#10;</xsl:text>
    131 </xsl:template>
    132 
    133 <xsl:template match="grammar/nonterminals">
    134   <xsl:text>Nonterminals, with rules where they appear&#10;&#10;</xsl:text>
    135   <xsl:apply-templates select="nonterminal[@usefulness!='useless-in-grammar']"/>
    136 </xsl:template>
    137 
    138 <xsl:template match="terminal">
    139   <xsl:value-of select="@name"/>
    140   <xsl:call-template name="line-wrap">
    141     <xsl:with-param name="first-line-length">
    142       <xsl:choose>
    143         <xsl:when test="string-length(@name) &gt; 66">0</xsl:when>
    144         <xsl:otherwise>
    145           <xsl:value-of select="66 - string-length(@name)" />
    146         </xsl:otherwise>
    147       </xsl:choose>
    148     </xsl:with-param>
    149     <xsl:with-param name="line-length" select="66" />
    150     <xsl:with-param name="text">
    151       <xsl:value-of select="concat(' (', @token-number, ')')"/>
    152       <xsl:for-each select="key('bison:ruleByRhs', @name)">
    153         <xsl:value-of select="concat(' ', @number)"/>
    154       </xsl:for-each>
    155     </xsl:with-param>
    156   </xsl:call-template>
    157 </xsl:template>
    158 
    159 <xsl:template match="nonterminal">
    160   <xsl:value-of select="@name"/>
    161   <xsl:value-of select="concat(' (', @symbol-number, ')')"/>
    162   <xsl:text>&#10;</xsl:text>
    163   <xsl:variable name="output">
    164     <xsl:call-template name="line-wrap">
    165       <xsl:with-param name="line-length" select="66" />
    166       <xsl:with-param name="text">
    167         <xsl:text>    </xsl:text>
    168         <xsl:if test="key('bison:ruleByLhs', @name)">
    169           <xsl:text>on@left:</xsl:text>
    170           <xsl:for-each select="key('bison:ruleByLhs', @name)">
    171             <xsl:value-of select="concat(' ', @number)"/>
    172           </xsl:for-each>
    173         </xsl:if>
    174         <xsl:if test="key('bison:ruleByRhs', @name)">
    175           <xsl:if test="key('bison:ruleByLhs', @name)">
    176             <xsl:text>, </xsl:text>
    177           </xsl:if>
    178           <xsl:text>on@right:</xsl:text>
    179           <xsl:for-each select="key('bison:ruleByRhs', @name)">
    180             <xsl:value-of select="concat(' ', @number)"/>
    181           </xsl:for-each>
    182         </xsl:if>
    183       </xsl:with-param>
    184     </xsl:call-template>
    185   </xsl:variable>
    186   <xsl:value-of select="translate($output, '@', ' ')" />
    187 </xsl:template>
    188 
    189 <xsl:template match="automaton" mode="conflicts">
    190   <xsl:variable name="conflict-report">
    191     <xsl:apply-templates select="state" mode="conflicts"/>
    192   </xsl:variable>
    193   <xsl:if test="string-length($conflict-report) != 0">
    194     <xsl:value-of select="$conflict-report"/>
    195     <xsl:text>&#10;&#10;</xsl:text>
    196   </xsl:if>
    197 </xsl:template>
    198 
    199 <xsl:template match="state" mode="conflicts">
    200   <xsl:variable name="conflict-counts">
    201     <xsl:apply-templates select="." mode="bison:count-conflicts" />
    202   </xsl:variable>
    203   <xsl:variable
    204     name="sr-count" select="substring-before($conflict-counts, ',')"
    205   />
    206   <xsl:variable
    207     name="rr-count" select="substring-after($conflict-counts, ',')"
    208   />
    209   <xsl:if test="$sr-count > 0 or $rr-count > 0">
    210     <xsl:value-of select="concat('State ', @number, ' conflicts:')"/>
    211     <xsl:if test="$sr-count > 0">
    212       <xsl:value-of select="concat(' ', $sr-count, ' shift/reduce')"/>
    213       <xsl:if test="$rr-count > 0">
    214         <xsl:value-of select="(',')"/>
    215       </xsl:if>
    216     </xsl:if>
    217     <xsl:if test="$rr-count > 0">
    218       <xsl:value-of select="concat(' ', $rr-count, ' reduce/reduce')"/>
    219     </xsl:if>
    220     <xsl:value-of select="'&#10;'"/>
    221   </xsl:if>
    222 </xsl:template>
    223 
    224 <xsl:template match="automaton">
    225   <xsl:apply-templates select="state">
    226     <xsl:with-param name="pad" select="'3'"/>
    227   </xsl:apply-templates>
    228 </xsl:template>
    229 
    230 <xsl:template match="automaton/state">
    231   <xsl:param name="pad"/>
    232   <xsl:text>&#10;&#10;</xsl:text>
    233   <xsl:text>State </xsl:text>
    234   <xsl:value-of select="@number"/>
    235   <xsl:text>&#10;&#10;</xsl:text>
    236   <xsl:apply-templates select="itemset/item">
    237     <xsl:with-param name="pad" select="$pad"/>
    238   </xsl:apply-templates>
    239   <xsl:apply-templates select="actions/transitions">
    240     <xsl:with-param name="type" select="'shift'"/>
    241   </xsl:apply-templates>
    242   <xsl:apply-templates select="actions/errors"/>
    243   <xsl:apply-templates select="actions/reductions"/>
    244   <xsl:apply-templates select="actions/transitions">
    245     <xsl:with-param name="type" select="'goto'"/>
    246   </xsl:apply-templates>
    247   <xsl:apply-templates select="solved-conflicts"/>
    248 </xsl:template>
    249 
    250 <xsl:template match="actions/transitions">
    251   <xsl:param name="type"/>
    252   <xsl:if test="transition[@type = $type]">
    253     <xsl:text>&#10;</xsl:text>
    254     <xsl:apply-templates select="transition[@type = $type]">
    255       <xsl:with-param name="pad">
    256 	<xsl:call-template name="max-width-symbol">
    257 	  <xsl:with-param name="node" select="transition[@type = $type]"/>
    258 	</xsl:call-template>
    259       </xsl:with-param>
    260     </xsl:apply-templates>
    261   </xsl:if>
    262 </xsl:template>
    263 
    264 <xsl:template match="actions/errors">
    265   <xsl:if test="error">
    266     <xsl:text>&#10;</xsl:text>
    267     <xsl:apply-templates select="error">
    268       <xsl:with-param name="pad">
    269 	<xsl:call-template name="max-width-symbol">
    270 	  <xsl:with-param name="node" select="error"/>
    271 	</xsl:call-template>
    272       </xsl:with-param>
    273     </xsl:apply-templates>
    274   </xsl:if>
    275 </xsl:template>
    276 
    277 <xsl:template match="actions/reductions">
    278   <xsl:if test="reduction">
    279     <xsl:text>&#10;</xsl:text>
    280     <xsl:apply-templates select="reduction">
    281       <xsl:with-param name="pad">
    282 	<xsl:call-template name="max-width-symbol">
    283 	  <xsl:with-param name="node" select="reduction"/>
    284 	</xsl:call-template>
    285       </xsl:with-param>
    286     </xsl:apply-templates>
    287   </xsl:if>
    288 </xsl:template>
    289 
    290 <xsl:template match="item">
    291   <xsl:param name="pad"/>
    292   <xsl:param name="prev-rule-number"
    293 	     select="preceding-sibling::item[1]/@rule-number"/>
    294   <xsl:apply-templates
    295     select="key('bison:ruleByNumber', current()/@rule-number)"
    296   >
    297     <xsl:with-param name="itemset" select="'true'"/>
    298     <xsl:with-param name="pad" select="$pad"/>
    299     <xsl:with-param
    300       name="prev-lhs"
    301       select="key('bison:ruleByNumber', $prev-rule-number)/lhs[text()]"
    302    />
    303     <xsl:with-param name="point" select="@point"/>
    304     <xsl:with-param name="lookaheads">
    305       <xsl:apply-templates select="lookaheads"/>
    306     </xsl:with-param>
    307   </xsl:apply-templates>
    308 </xsl:template>
    309 
    310 <xsl:template match="rule">
    311   <xsl:param name="itemset"/>
    312   <xsl:param name="pad"/>
    313   <xsl:param name="prev-lhs"/>
    314   <xsl:param name="point"/>
    315   <xsl:param name="lookaheads"/>
    316 
    317   <xsl:if test="$itemset != 'true' and not($prev-lhs = lhs[text()])">
    318     <xsl:text>&#10;</xsl:text>
    319   </xsl:if>
    320 
    321   <xsl:text>  </xsl:text>
    322   <xsl:call-template name="lpad">
    323     <xsl:with-param name="str" select="string(@number)"/>
    324     <xsl:with-param name="pad" select="number($pad)"/>
    325   </xsl:call-template>
    326   <xsl:text> </xsl:text>
    327 
    328   <!-- LHS -->
    329   <xsl:choose>
    330     <xsl:when test="$itemset != 'true' and $prev-lhs = lhs[text()]">
    331       <xsl:call-template name="lpad">
    332 	<xsl:with-param name="str" select="'|'"/>
    333 	<xsl:with-param name="pad" select="number(string-length(lhs[text()])) + 1"/>
    334       </xsl:call-template>
    335     </xsl:when>
    336     <xsl:when test="$itemset = 'true' and $prev-lhs = lhs[text()]">
    337       <xsl:call-template name="lpad">
    338 	<xsl:with-param name="str" select="'|'"/>
    339 	<xsl:with-param name="pad" select="number(string-length(lhs[text()])) + 1"/>
    340       </xsl:call-template>
    341     </xsl:when>
    342     <xsl:otherwise>
    343       <xsl:value-of select="lhs"/>
    344       <xsl:text>:</xsl:text>
    345     </xsl:otherwise>
    346   </xsl:choose>
    347 
    348   <!-- RHS -->
    349   <xsl:for-each select="rhs/*">
    350     <xsl:if test="position() = $point + 1">
    351       <xsl:text> .</xsl:text>
    352     </xsl:if>
    353     <xsl:if test="$itemset = 'true' and name(.) != 'empty'">
    354       <xsl:apply-templates select="."/>
    355     </xsl:if>
    356     <xsl:if test="$itemset != 'true'">
    357       <xsl:apply-templates select="."/>
    358     </xsl:if>
    359     <xsl:if test="position() = last() and position() = $point">
    360       <xsl:text> .</xsl:text>
    361     </xsl:if>
    362   </xsl:for-each>
    363   <xsl:if test="$lookaheads">
    364     <xsl:value-of select="$lookaheads"/>
    365   </xsl:if>
    366 
    367   <xsl:text>&#10;</xsl:text>
    368 </xsl:template>
    369 
    370 <xsl:template match="symbol">
    371   <xsl:text> </xsl:text>
    372   <xsl:value-of select="."/>
    373 </xsl:template>
    374 
    375 <xsl:template match="empty">
    376   <xsl:text> /* empty */</xsl:text>
    377 </xsl:template>
    378 
    379 <xsl:template match="lookaheads">
    380   <xsl:text>  [</xsl:text>
    381   <xsl:apply-templates select="symbol"/>
    382   <xsl:text>]</xsl:text>
    383 </xsl:template>
    384 
    385 <xsl:template match="lookaheads/symbol">
    386   <xsl:value-of select="."/>
    387   <xsl:if test="position() != last()">
    388     <xsl:text>, </xsl:text>
    389   </xsl:if>
    390 </xsl:template>
    391 
    392 <xsl:template match="transition">
    393   <xsl:param name="pad"/>
    394   <xsl:text>    </xsl:text>
    395   <xsl:call-template name="rpad">
    396     <xsl:with-param name="str" select="string(@symbol)"/>
    397     <xsl:with-param name="pad" select="number($pad) + 2"/>
    398   </xsl:call-template>
    399   <xsl:choose>
    400     <xsl:when test="@type = 'shift'">
    401       <xsl:text>shift, and go to state </xsl:text>
    402       <xsl:value-of select="@state"/>
    403     </xsl:when>
    404     <xsl:when test="@type = 'goto'">
    405       <xsl:text>go to state </xsl:text>
    406       <xsl:value-of select="@state"/>
    407     </xsl:when>
    408   </xsl:choose>
    409   <xsl:text>&#10;</xsl:text>
    410 </xsl:template>
    411 
    412 <xsl:template match="error">
    413   <xsl:param name="pad"/>
    414   <xsl:text>    </xsl:text>
    415   <xsl:call-template name="rpad">
    416     <xsl:with-param name="str" select="string(@symbol)"/>
    417     <xsl:with-param name="pad" select="number($pad) + 2"/>
    418   </xsl:call-template>
    419   <xsl:text>error</xsl:text>
    420   <xsl:text> (</xsl:text>
    421   <xsl:value-of select="text()"/>
    422   <xsl:text>)</xsl:text>
    423   <xsl:text>&#10;</xsl:text>
    424 </xsl:template>
    425 
    426 <xsl:template match="reduction">
    427   <xsl:param name="pad"/>
    428   <xsl:text>    </xsl:text>
    429   <xsl:call-template name="rpad">
    430     <xsl:with-param name="str" select="string(@symbol)"/>
    431     <xsl:with-param name="pad" select="number($pad) + 2"/>
    432   </xsl:call-template>
    433   <xsl:if test="@enabled = 'false'">
    434     <xsl:text>[</xsl:text>
    435   </xsl:if>
    436   <xsl:choose>
    437     <xsl:when test="@rule = 'accept'">
    438       <xsl:text>accept</xsl:text>
    439     </xsl:when>
    440     <xsl:otherwise>
    441       <xsl:text>reduce using rule </xsl:text>
    442       <xsl:value-of select="@rule"/>
    443       <xsl:text> (</xsl:text>
    444       <xsl:value-of
    445 	  select="key('bison:ruleByNumber', current()/@rule)/lhs[text()]"/>
    446       <xsl:text>)</xsl:text>
    447     </xsl:otherwise>
    448   </xsl:choose>
    449   <xsl:if test="@enabled = 'false'">
    450     <xsl:text>]</xsl:text>
    451   </xsl:if>
    452   <xsl:text>&#10;</xsl:text>
    453 </xsl:template>
    454 
    455 <xsl:template match="solved-conflicts">
    456   <xsl:if test="resolution">
    457     <xsl:text>&#10;</xsl:text>
    458     <xsl:apply-templates select="resolution"/>
    459   </xsl:if>
    460 </xsl:template>
    461 
    462 <xsl:template match="resolution">
    463   <xsl:text>    Conflict between rule </xsl:text>
    464   <xsl:value-of select="@rule"/>
    465   <xsl:text> and token </xsl:text>
    466   <xsl:value-of select="@symbol"/>
    467   <xsl:text> resolved as </xsl:text>
    468   <xsl:if test="@type = 'error'">
    469     <xsl:text>an </xsl:text>
    470   </xsl:if>
    471   <xsl:value-of select="@type"/>
    472   <xsl:text> (</xsl:text>
    473   <xsl:value-of select="."/>
    474   <xsl:text>).&#10;</xsl:text>
    475 </xsl:template>
    476 
    477 <xsl:template name="max-width-symbol">
    478   <xsl:param name="node"/>
    479   <xsl:variable name="longest">
    480     <xsl:for-each select="$node">
    481       <xsl:sort data-type="number" select="string-length(@symbol)"
    482 		order="descending"/>
    483       <xsl:if test="position() = 1">
    484 	<xsl:value-of select="string-length(@symbol)"/>
    485       </xsl:if>
    486     </xsl:for-each>
    487   </xsl:variable>
    488   <xsl:value-of select="$longest"/>
    489 </xsl:template>
    490 
    491 <xsl:template name="lpad">
    492   <xsl:param name="str" select="''"/>
    493   <xsl:param name="pad" select="0"/>
    494   <xsl:variable name="diff" select="$pad - string-length($str)" />
    495   <xsl:choose>
    496     <xsl:when test="$diff &lt; 0">
    497       <xsl:value-of select="$str"/>
    498     </xsl:when>
    499     <xsl:otherwise>
    500       <xsl:call-template name="space">
    501 	<xsl:with-param name="repeat" select="$diff"/>
    502       </xsl:call-template>
    503       <xsl:value-of select="$str"/>
    504     </xsl:otherwise>
    505   </xsl:choose>
    506 </xsl:template>
    507 
    508 <xsl:template name="rpad">
    509   <xsl:param name="str" select="''"/>
    510   <xsl:param name="pad" select="0"/>
    511   <xsl:variable name="diff" select="$pad - string-length($str)"/>
    512   <xsl:choose>
    513     <xsl:when test="$diff &lt; 0">
    514       <xsl:value-of select="$str"/>
    515     </xsl:when>
    516     <xsl:otherwise>
    517       <xsl:value-of select="$str"/>
    518       <xsl:call-template name="space">
    519 	<xsl:with-param name="repeat" select="$diff"/>
    520       </xsl:call-template>
    521     </xsl:otherwise>
    522   </xsl:choose>
    523 </xsl:template>
    524 
    525 <xsl:template name="line-wrap">
    526   <xsl:param name="line-length"/> <!-- required -->
    527   <xsl:param name="first-line-length" select="$line-length"/>
    528   <xsl:param name="text"/> <!-- required -->
    529   <xsl:choose>
    530     <xsl:when test="normalize-space($text) = ''" />
    531     <xsl:when test="string-length($text) &lt;= $first-line-length">
    532       <xsl:value-of select="concat($text, '&#10;')" />
    533     </xsl:when>
    534     <xsl:otherwise>
    535       <xsl:variable name="break-pos">
    536         <xsl:call-template name="ws-search">
    537           <xsl:with-param name="text" select="$text" />
    538           <xsl:with-param name="start" select="$first-line-length+1" />
    539         </xsl:call-template>
    540       </xsl:variable>
    541       <xsl:value-of select="substring($text, 1, $break-pos - 1)" />
    542       <xsl:text>&#10;</xsl:text>
    543       <xsl:call-template name="line-wrap">
    544         <xsl:with-param name="line-length" select="$line-length" />
    545         <xsl:with-param
    546           name="text" select="concat('    ', substring($text, $break-pos+1))"
    547         />
    548       </xsl:call-template>
    549     </xsl:otherwise>
    550   </xsl:choose>
    551 </xsl:template>
    552 
    553 <xsl:template name="ws-search">
    554   <xsl:param name="text"/> <!-- required -->
    555   <xsl:param name="start"/> <!-- required -->
    556   <xsl:variable name="search-text" select="substring($text, $start)" />
    557   <xsl:choose>
    558     <xsl:when test="not(contains($search-text, ' '))">
    559       <xsl:value-of select="string-length($text)+1" />
    560     </xsl:when>
    561     <xsl:otherwise>
    562       <xsl:value-of
    563         select="$start + string-length(substring-before($search-text, ' '))"
    564       />
    565     </xsl:otherwise>
    566   </xsl:choose>
    567 </xsl:template>
    568 
    569 </xsl:stylesheet>
    570