pentext/xml/xslt/auto.xslt
2019-06-21 15:23:23 +02:00

728 lines
37 KiB
HTML

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"
xmlns:fo="http://www.w3.org/1999/XSL/Format" version="2.0">
<xsl:template match="generate_targets">
<xsl:call-template name="targets"/>
</xsl:template>
<xsl:template name="targets">
<xsl:param name="Ref" select="@Ref"/>
<fo:list-block xsl:use-attribute-sets="list">
<xsl:for-each
select="/*/meta/targets/target[@Ref = $Ref] | /*/meta/targets/target[not(@Ref)]">
<fo:list-item xsl:use-attribute-sets="li">
<!-- insert a bullet -->
<fo:list-item-label end-indent="label-end()">
<fo:block>
<fo:inline>&#8226;</fo:inline>
</fo:block>
</fo:list-item-label>
<!-- list text -->
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
<xsl:template match="generate_teammembers">
<xsl:call-template name="teammembers"/>
</xsl:template>
<xsl:template name="teammembers">
<fo:list-block xsl:use-attribute-sets="list" provisional-distance-between-starts="0.75cm"
provisional-label-separation="2.5mm" space-after="12pt" start-indent="1cm">
<xsl:for-each select="//activityinfo//team/member">
<fo:list-item>
<!-- insert a bullet -->
<fo:list-item-label end-indent="label-end()">
<fo:block>
<fo:inline>&#8226;</fo:inline>
</fo:block>
</fo:list-item-label>
<!-- list text -->
<fo:list-item-body start-indent="body-start()">
<fo:block>
<fo:inline xsl:use-attribute-sets="bold"><xsl:apply-templates
select="name"/>: </fo:inline>
<xsl:apply-templates select="expertise"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
<xsl:template match="generate_findings">
<xsl:variable name="Ref" select="@Ref"/>
<xsl:variable name="statusSequence" as="item()*">
<xsl:for-each select="@status">
<xsl:for-each select="tokenize(., ' ')">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<fo:block>
<fo:table xsl:use-attribute-sets="fwtable table borders">
<xsl:call-template name="checkIfLast"/>
<fo:table-column column-width="proportional-column-width(12)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(22)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(50)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(16)"
xsl:use-attribute-sets="borders"/>
<fo:table-body>
<fo:table-row keep-with-next.within-column="always">
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block>ID</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block>Type</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block>Description</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block>Threat level</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:choose>
<xsl:when test="@status and @Ref">
<!-- Only generate a table for findings in the section with this status AND this Ref -->
<xsl:for-each
select="$findingSummaryTable/findingEntry[@status = $statusSequence][ancestor::*[@id = $Ref]]">
<xsl:call-template name="findingsSummaryContent"/>
</xsl:for-each>
</xsl:when>
<xsl:when test="@status and not(@Ref)">
<!-- Only generate a table for findings in the section with this status -->
<xsl:for-each
select="$findingSummaryTable/findingEntry[@status = $statusSequence]">
<xsl:call-template name="findingsSummaryContent"/>
</xsl:for-each>
</xsl:when>
<xsl:when test="@Ref and not(@status)">
<!-- Only generate a table for findings in the section with this Ref -->
<xsl:for-each
select="$findingSummaryTable/findingEntry[ancestor::*[@id = $Ref]]">
<xsl:call-template name="findingsSummaryContent"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="$findingSummaryTable/findingEntry">
<xsl:call-template name="findingsSummaryContent"/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template name="findingsSummaryContent">
<fo:table-row xsl:use-attribute-sets="TableFont">
<xsl:if test="position() mod 2 != 0">
<xsl:attribute name="background-color">#ededed</xsl:attribute>
</xsl:if>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<!-- attach id to first finding of each threatLevel so pie charts can link to it -->
<xsl:if test="@id">
<xsl:attribute name="id">
<xsl:value-of select="@id"/>
</xsl:attribute>
</xsl:if>
<fo:basic-link xsl:use-attribute-sets="link">
<xsl:attribute name="internal-destination">
<xsl:value-of select="@findingId"/>
</xsl:attribute>
<xsl:value-of select="findingNumber"/>
</fo:basic-link>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:value-of select="findingType"/>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:value-of select="findingDescription"/>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:value-of select="findingThreatLevel"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
<xsl:template match="generate_recommendations">
<xsl:variable name="Ref" select="@Ref"/>
<xsl:variable name="statusSequence" as="item()*">
<xsl:for-each select="@status">
<xsl:for-each select="tokenize(., ' ')">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<fo:block>
<fo:table xsl:use-attribute-sets="fwtable table borders">
<xsl:call-template name="checkIfLast"/>
<fo:table-column column-width="proportional-column-width(12)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(22)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(66)"
xsl:use-attribute-sets="borders"/>
<fo:table-body>
<fo:table-row keep-with-next.within-column="always">
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block>ID</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block>Type</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block>Recommendation</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:choose>
<xsl:when test="@status and @Ref">
<!-- Only generate a table for findings in the section with this status AND this Ref -->
<xsl:for-each
select="/pentest_report/descendant::finding[@status = $statusSequence][ancestor::*[@id = $Ref]]">
<xsl:call-template name="recommendationsSummaryContent"/>
</xsl:for-each>
</xsl:when>
<xsl:when test="@status and not(@Ref)">
<!-- Only generate a table for findings in the section with this status -->
<xsl:for-each
select="/pentest_report/descendant::finding[@status = $statusSequence]">
<xsl:call-template name="recommendationsSummaryContent"/>
</xsl:for-each>
</xsl:when>
<xsl:when test="@Ref and not(@status)">
<!-- Only generate a table for findings in the section with this Ref -->
<xsl:for-each
select="/pentest_report/descendant::finding[ancestor::*[@id = $Ref]]">
<xsl:call-template name="recommendationsSummaryContent"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="/pentest_report/descendant::finding">
<xsl:call-template name="recommendationsSummaryContent"/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template name="recommendationsSummaryContent">
<fo:table-row xsl:use-attribute-sets="TableFont">
<xsl:if test="position() mod 2 != 0">
<xsl:attribute name="background-color">#ededed</xsl:attribute>
</xsl:if>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<fo:basic-link xsl:use-attribute-sets="link">
<xsl:attribute name="internal-destination">
<xsl:value-of select="@id"/>
</xsl:attribute>
<xsl:apply-templates select="." mode="number"/>
</fo:basic-link>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:value-of select="@type"/>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:choose>
<xsl:when test="recommendation_summary">
<xsl:apply-templates select="recommendation_summary" mode="summarytable"
/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="recommendation" mode="summarytable"/>
</xsl:otherwise>
</xsl:choose>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
<xsl:template match="generate_testteam">
<fo:block>
<fo:table xsl:use-attribute-sets="fwtable borders">
<fo:table-column column-width="proportional-column-width(25)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(75)"
xsl:use-attribute-sets="borders"/>
<fo:table-body>
<xsl:for-each select="/pentest_report/meta/collaborators/pentesters/pentester">
<xsl:if
test="not(./name = /pentest_report/meta/collaborators/approver/name)">
<fo:table-row xsl:use-attribute-sets="borders">
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:apply-templates select="name"/>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:apply-templates select="bio"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="/pentest_report/meta/collaborators/approver">
<fo:table-row xsl:use-attribute-sets="borders">
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:apply-templates select="name"/>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:apply-templates select="bio"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template match="generate_offer_signature_box">
<xsl:call-template name="generateSignatureBox">
<xsl:with-param name="latestVersionDate" select="$latestVersionDate"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="generateSignatureBox">
<xsl:param name="latestVersionDate"/>
<fo:block keep-together.within-page="always" xsl:use-attribute-sets="signaturebox">
<fo:block xsl:use-attribute-sets="title-client">
<xsl:call-template name="getString">
<xsl:with-param name="stringID" select="'signed_dupe'"/>
</xsl:call-template>
</fo:block>
<fo:block>
<fo:table xsl:use-attribute-sets="fwtable borders">
<fo:table-column column-width="proportional-column-width(50)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(50)"
xsl:use-attribute-sets="borders"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:value-of select="$latestVersionDate"/>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:value-of select="$latestVersionDate"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:value-of select="/*/meta/permission_parties/client/city"/>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:value-of select="/*/meta/company/city"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>&#160;</fo:block>
<fo:block>&#160;</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>&#160;</fo:block>
<fo:block>&#160;</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:choose>
<xsl:when test="/offerte">
<xsl:value-of
select="/*/meta/permission_parties/client/legal_rep"/>
</xsl:when>
<xsl:when test="/quickscope">
<xsl:value-of select="/*/customer/legal_rep"/>
</xsl:when>
</xsl:choose>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:choose>
<xsl:when test="/offerte">
<xsl:value-of select="/*/meta/company/legal_rep"/>
</xsl:when>
<xsl:when test="/quickscope">
<xsl:value-of select="/*/company/legal_rep"/>
</xsl:when>
</xsl:choose>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block xsl:use-attribute-sets="bold">
<xsl:choose>
<xsl:when test="/offerte">
<xsl:value-of
select="/*/meta/permission_parties/client/full_name"/>
</xsl:when>
<xsl:when test="/quickscope">
<xsl:value-of select="/*/customer/full_name"/>
</xsl:when>
</xsl:choose>
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block xsl:use-attribute-sets="bold">
<xsl:choose>
<xsl:when test="/offerte">
<xsl:value-of select="/*/meta/company/full_name"/>
</xsl:when>
<xsl:when test="/quickscope">
<xsl:value-of select="/*/company/full_name"/>
</xsl:when>
</xsl:choose>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
</fo:block>
</xsl:template>
<xsl:template match="generate_permission_parties">
<xsl:for-each select="/*/meta/permission_parties/client | /*/meta/permission_parties/party">
<xsl:if test="self::party and not(following-sibling::party)">
<xsl:call-template name="getString">
<xsl:with-param name="stringID" select="'permission_and'"/>
</xsl:call-template>
<xsl:text>&#x20;</xsl:text>
</xsl:if>
<xsl:value-of select="full_name"/>
<xsl:if test="../party[2]">, </xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="generate_service_breakdown">
<xsl:choose>
<xsl:when test="@format = 'list'">
<fo:list-block xsl:use-attribute-sets="list">
<xsl:for-each select="$serviceNodeSet/entry[@type = 'service']">
<xsl:if test="d">
<fo:list-item xsl:use-attribute-sets="li">
<!-- insert a bullet -->
<fo:list-item-label end-indent="label-end()">
<fo:block>
<fo:inline>&#8226;</fo:inline>
</fo:block>
</fo:list-item-label>
<!-- list text -->
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:value-of select="desc"/>
<xsl:text>: </xsl:text>
<xsl:value-of select="d"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:if>
</xsl:for-each>
<fo:list-item xsl:use-attribute-sets="li">
<!-- insert a bullet -->
<fo:list-item-label end-indent="label-end()">
<fo:block>
<fo:inline>&#8226;</fo:inline>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block xsl:use-attribute-sets="bold">
<xsl:text>Total effort: </xsl:text>
<xsl:call-template name="calculatePersonDays"/>
<xsl:text> days</xsl:text>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</xsl:when>
<xsl:when test="@format = 'table'">
<fo:block xsl:use-attribute-sets="keep-together"><fo:table xsl:use-attribute-sets="breakdowntable">
<fo:table-column column-width="proportional-column-width(6)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(2)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(3)"
xsl:use-attribute-sets="borders"/>
<fo:table-column column-width="proportional-column-width(4)"
xsl:use-attribute-sets="borders"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block> Description </fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block> Effort </fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block> Hourly rate </fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="th">
<fo:block> Fee </fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:for-each select="$serviceNodeSet/entry">
<fo:table-row>
<xsl:if test="position() mod 2 != 0">
<xsl:attribute name="background-color">#ededed</xsl:attribute>
</xsl:if>
<fo:table-cell xsl:use-attribute-sets="td">
<xsl:if
test="not(normalize-space(d)) and not(normalize-space(h))">
<xsl:attribute name="number-columns-spanned"
>3</xsl:attribute>
</xsl:if>
<fo:block>
<xsl:value-of select="desc"/>
</fo:block>
</fo:table-cell>
<xsl:if test="d">
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block>
<xsl:value-of select="d"/>
</fo:block>
</fo:table-cell>
<xsl:choose>
<xsl:when test="normalize-space(h)">
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block text-align="right">
<xsl:call-template name="getDenomination">
<xsl:with-param name="placeholderElement"
select="."/>
</xsl:call-template>
<xsl:call-template name="prettyMissingDecimal">
<xsl:with-param name="n" select="h"/>
</xsl:call-template>
<xsl:text> excl. VAT</xsl:text>
</fo:block>
</fo:table-cell>
</xsl:when>
<xsl:otherwise>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block text-align="right">-</fo:block>
</fo:table-cell>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<fo:table-cell xsl:use-attribute-sets="td">
<fo:block text-align="right">
<xsl:choose>
<xsl:when test="not(f/min = f/max)">
<xsl:call-template name="getDenomination">
<xsl:with-param name="placeholderElement"
select="."/>
</xsl:call-template>
<xsl:number value="f/min" grouping-separator=","
grouping-size="3"/>
<xsl:text> - </xsl:text>
<xsl:call-template name="getDenomination">
<xsl:with-param name="placeholderElement"
select="."/>
</xsl:call-template>
<xsl:call-template name="prettyMissingDecimal">
<xsl:with-param name="n" select="f/max"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="getDenomination">
<xsl:with-param name="placeholderElement"
select="."/>
</xsl:call-template>
<xsl:call-template name="prettyMissingDecimal">
<xsl:with-param name="n" select="f/min"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
<xsl:text> excl. VAT</xsl:text>
<xsl:if test="@estimate = true()">*</xsl:if>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
<fo:table-row xsl:use-attribute-sets="totalRow">
<fo:table-cell number-columns-spanned="4" xsl:use-attribute-sets="td">
<fo:block xsl:use-attribute-sets="totalcell">
<xsl:text>Total</xsl:text>
<xsl:if test="$serviceNodeSet/entry/@estimate">
(estimate)</xsl:if>
<xsl:text>:</xsl:text>
<fo:leader leader-pattern="space"/>
<xsl:call-template name="calculateTotal"/>
<xsl:text> excl. VAT</xsl:text>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table></fo:block>
<xsl:if test="$serviceNodeSet/entry/@estimate = true()">
<fo:block text-align="right">
<xsl:text>* Estimate</xsl:text>
</fo:block>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="displayErrorText">
<xsl:with-param name="string">ERROR: unknown service breakdown format (use
'list' or 'table')</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="calculateTotal">
<xsl:param name="denoms" tunnel="yes">
<xsl:for-each-group select="$serviceNodeSet/entry" group-by="@denomination">
<denom denomination="{current-grouping-key()}"/>
</xsl:for-each-group>
</xsl:param>
<xsl:variable name="allDenominationsAreEqual" select="count($denoms/denom) = 1"/>
<xsl:variable name="minmaxesPresent"
select="boolean($serviceNodeSet/entry/f/min and $serviceNodeSet/entry/f/max)"/>
<xsl:variable name="estimatePresent" select="$serviceNodeSet/entry/@estimate"/>
<xsl:variable name="totalMinFees" select="sum($serviceNodeSet/entry/f/min)"/>
<xsl:variable name="totalMaxFees" select="sum($serviceNodeSet/entry/f/max)"/>
<xsl:choose>
<xsl:when test="not($totalMinFees = $totalMaxFees)">
<!-- We have different min and max fees, print range -->
<xsl:call-template name="checkDenomination">
<xsl:with-param name="allDenominationsAreEqual"
select="$allDenominationsAreEqual"/>
<xsl:with-param name="denoms" select="$denoms"/>
</xsl:call-template>
<xsl:number value="$totalMinFees" grouping-separator="," grouping-size="3"/>
<xsl:text> - </xsl:text>
<xsl:call-template name="checkDenomination">
<xsl:with-param name="allDenominationsAreEqual"
select="$allDenominationsAreEqual"/>
<xsl:with-param name="denoms" select="$denoms"/>
</xsl:call-template>
<xsl:call-template name="prettyMissingDecimal">
<xsl:with-param name="n" select="$totalMaxFees"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- Min and max are equal; print single price -->
<xsl:call-template name="checkDenomination">
<xsl:with-param name="allDenominationsAreEqual"
select="$allDenominationsAreEqual"/>
<xsl:with-param name="denoms" select="$denoms"/>
</xsl:call-template>
<xsl:call-template name="prettyMissingDecimal">
<xsl:with-param name="n" select="$totalMinFees"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="checkDenomination">
<xsl:param name="allDenominationsAreEqual"/>
<xsl:param name="denoms"/>
<xsl:choose>
<xsl:when test="$allDenominationsAreEqual">
<xsl:call-template name="getDenomination">
<xsl:with-param name="placeholderElement" select="$denoms/denom"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="displayErrorText">
<xsl:with-param name="string">Cannot print denomination: not all fees in
service_breakdown have an equal denomination (tip: if most services are in
eur but one is in usd, add the usd fee to the description for that service
and use an estimated eur for the hourly rate or fee).</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="calculatePersonDays">
<xsl:variable name="totalMinDurations"
select="sum($serviceNodeSet/entry[@type = 'service']/dh/min)"/>
<xsl:variable name="totalMaxDurations"
select="sum($serviceNodeSet/entry[@type = 'service']/dh/max)"/>
<xsl:choose>
<xsl:when test="not($totalMinDurations = $totalMaxDurations)">
<xsl:value-of select="sum($totalMinDurations) div 8"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="sum($totalMaxDurations) div 8"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="sum($totalMinDurations) div 8"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="prettyMissingDecimal">
<xsl:param name="n"/>
<xsl:if test="floor($n) = $n">
<xsl:number value="$n" grouping-separator="," grouping-size="3"/>
<xsl:text>.-</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>