|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<xsl:stylesheet xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:saxon="http://saxon.sf.net/" xmlns:schold="http://www.ascc.net/xml/schematron" xmlns:u="utils" xmlns:ubl-creditnote="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2" xmlns:ubl-invoice="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
|
|
<!--Implementers: please note that overriding process-prolog or process-root is
|
|
the preferred method for meta-stylesheets to use where possible. -->
|
|
|
|
<xsl:param name="archiveDirParameter" />
|
|
<xsl:param name="archiveNameParameter" />
|
|
<xsl:param name="fileNameParameter" />
|
|
<xsl:param name="fileDirParameter" />
|
|
<xsl:variable name="document-uri">
|
|
<xsl:value-of select="document-uri(/)" />
|
|
</xsl:variable>
|
|
|
|
<!--PHASES-->
|
|
|
|
|
|
<!--PROLOG-->
|
|
<xsl:output indent="yes" method="xml" omit-xml-declaration="no" standalone="yes" />
|
|
|
|
<!--XSD TYPES FOR XSLT2-->
|
|
|
|
|
|
<!--KEYS AND FUNCTIONS-->
|
|
<xsl:function as="xs:boolean" name="u:slack">
|
|
<xsl:param as="xs:decimal" name="exp" />
|
|
<xsl:param as="xs:decimal" name="val" />
|
|
<xsl:param as="xs:decimal" name="slack" />
|
|
|
|
<xsl:value-of select="xs:decimal($exp + $slack) >= $val and xs:decimal($exp - $slack) <= $val" />
|
|
</xsl:function>
|
|
|
|
<!--DEFAULT RULES-->
|
|
|
|
|
|
<!--MODE: SCHEMATRON-SELECT-FULL-PATH-->
|
|
<!--This mode can be used to generate an ugly though full XPath for locators-->
|
|
<xsl:template match="*" mode="schematron-select-full-path">
|
|
<xsl:apply-templates mode="schematron-get-full-path" select="." />
|
|
</xsl:template>
|
|
|
|
<!--MODE: SCHEMATRON-FULL-PATH-->
|
|
<!--This mode can be used to generate an ugly though full XPath for locators-->
|
|
<xsl:template match="*" mode="schematron-get-full-path">
|
|
<xsl:apply-templates mode="schematron-get-full-path" select="parent::*" />
|
|
<xsl:text>/</xsl:text>
|
|
<xsl:choose>
|
|
<xsl:when test="namespace-uri()=''">
|
|
<xsl:value-of select="name()" />
|
|
</xsl:when>
|
|
<xsl:otherwise>
|
|
<xsl:text>*:</xsl:text>
|
|
<xsl:value-of select="local-name()" />
|
|
<xsl:text>[namespace-uri()='</xsl:text>
|
|
<xsl:value-of select="namespace-uri()" />
|
|
<xsl:text>']</xsl:text>
|
|
</xsl:otherwise>
|
|
</xsl:choose>
|
|
<xsl:variable name="preceding" select="count(preceding-sibling::*[local-name()=local-name(current()) and namespace-uri() = namespace-uri(current())])" />
|
|
<xsl:text>[</xsl:text>
|
|
<xsl:value-of select="1+ $preceding" />
|
|
<xsl:text>]</xsl:text>
|
|
</xsl:template>
|
|
<xsl:template match="@*" mode="schematron-get-full-path">
|
|
<xsl:apply-templates mode="schematron-get-full-path" select="parent::*" />
|
|
<xsl:text>/</xsl:text>
|
|
<xsl:choose>
|
|
<xsl:when test="namespace-uri()=''">@<xsl:value-of select="name()" />
|
|
</xsl:when>
|
|
<xsl:otherwise>
|
|
<xsl:text>@*[local-name()='</xsl:text>
|
|
<xsl:value-of select="local-name()" />
|
|
<xsl:text>' and namespace-uri()='</xsl:text>
|
|
<xsl:value-of select="namespace-uri()" />
|
|
<xsl:text>']</xsl:text>
|
|
</xsl:otherwise>
|
|
</xsl:choose>
|
|
</xsl:template>
|
|
|
|
<!--MODE: SCHEMATRON-FULL-PATH-2-->
|
|
<!--This mode can be used to generate prefixed XPath for humans-->
|
|
<xsl:template match="node() | @*" mode="schematron-get-full-path-2">
|
|
<xsl:for-each select="ancestor-or-self::*">
|
|
<xsl:text>/</xsl:text>
|
|
<xsl:value-of select="name(.)" />
|
|
<xsl:if test="preceding-sibling::*[name(.)=name(current())]">
|
|
<xsl:text>[</xsl:text>
|
|
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1" />
|
|
<xsl:text>]</xsl:text>
|
|
</xsl:if>
|
|
</xsl:for-each>
|
|
<xsl:if test="not(self::*)">
|
|
<xsl:text />/@<xsl:value-of select="name(.)" />
|
|
</xsl:if>
|
|
</xsl:template>
|
|
<!--MODE: SCHEMATRON-FULL-PATH-3-->
|
|
<!--This mode can be used to generate prefixed XPath for humans
|
|
(Top-level element has index)-->
|
|
|
|
<xsl:template match="node() | @*" mode="schematron-get-full-path-3">
|
|
<xsl:for-each select="ancestor-or-self::*">
|
|
<xsl:text>/</xsl:text>
|
|
<xsl:value-of select="name(.)" />
|
|
<xsl:if test="parent::*">
|
|
<xsl:text>[</xsl:text>
|
|
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1" />
|
|
<xsl:text>]</xsl:text>
|
|
</xsl:if>
|
|
</xsl:for-each>
|
|
<xsl:if test="not(self::*)">
|
|
<xsl:text />/@<xsl:value-of select="name(.)" />
|
|
</xsl:if>
|
|
</xsl:template>
|
|
|
|
<!--MODE: GENERATE-ID-FROM-PATH -->
|
|
<xsl:template match="/" mode="generate-id-from-path" />
|
|
<xsl:template match="text()" mode="generate-id-from-path">
|
|
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
|
|
<xsl:value-of select="concat('.text-', 1+count(preceding-sibling::text()), '-')" />
|
|
</xsl:template>
|
|
<xsl:template match="comment()" mode="generate-id-from-path">
|
|
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
|
|
<xsl:value-of select="concat('.comment-', 1+count(preceding-sibling::comment()), '-')" />
|
|
</xsl:template>
|
|
<xsl:template match="processing-instruction()" mode="generate-id-from-path">
|
|
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
|
|
<xsl:value-of select="concat('.processing-instruction-', 1+count(preceding-sibling::processing-instruction()), '-')" />
|
|
</xsl:template>
|
|
<xsl:template match="@*" mode="generate-id-from-path">
|
|
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
|
|
<xsl:value-of select="concat('.@', name())" />
|
|
</xsl:template>
|
|
<xsl:template match="*" mode="generate-id-from-path" priority="-0.5">
|
|
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
|
|
<xsl:text>.</xsl:text>
|
|
<xsl:value-of select="concat('.',name(),'-',1+count(preceding-sibling::*[name()=name(current())]),'-')" />
|
|
</xsl:template>
|
|
|
|
<!--MODE: GENERATE-ID-2 -->
|
|
<xsl:template match="/" mode="generate-id-2">U</xsl:template>
|
|
<xsl:template match="*" mode="generate-id-2" priority="2">
|
|
<xsl:text>U</xsl:text>
|
|
<xsl:number count="*" level="multiple" />
|
|
</xsl:template>
|
|
<xsl:template match="node()" mode="generate-id-2">
|
|
<xsl:text>U.</xsl:text>
|
|
<xsl:number count="*" level="multiple" />
|
|
<xsl:text>n</xsl:text>
|
|
<xsl:number count="node()" />
|
|
</xsl:template>
|
|
<xsl:template match="@*" mode="generate-id-2">
|
|
<xsl:text>U.</xsl:text>
|
|
<xsl:number count="*" level="multiple" />
|
|
<xsl:text>_</xsl:text>
|
|
<xsl:value-of select="string-length(local-name(.))" />
|
|
<xsl:text>_</xsl:text>
|
|
<xsl:value-of select="translate(name(),':','.')" />
|
|
</xsl:template>
|
|
<!--Strip characters--> <xsl:template match="text()" priority="-1" />
|
|
|
|
<!--SCHEMA SETUP-->
|
|
<xsl:template match="/">
|
|
<svrl:schematron-output schemaVersion="iso" title="Rules for PEPPOL BIS 3.0 Billing">
|
|
<xsl:comment>
|
|
<xsl:value-of select="$archiveDirParameter" />
|
|
<xsl:value-of select="$archiveNameParameter" />
|
|
<xsl:value-of select="$fileNameParameter" />
|
|
<xsl:value-of select="$fileDirParameter" />
|
|
</xsl:comment>
|
|
<svrl:ns-prefix-in-attribute-values prefix="cbc" uri="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" />
|
|
<svrl:ns-prefix-in-attribute-values prefix="cac" uri="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" />
|
|
<svrl:ns-prefix-in-attribute-values prefix="ubl-creditnote" uri="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2" />
|
|
<svrl:ns-prefix-in-attribute-values prefix="ubl-invoice" uri="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" />
|
|
<svrl:ns-prefix-in-attribute-values prefix="xs" uri="http://www.w3.org/2001/XMLSchema" />
|
|
<svrl:ns-prefix-in-attribute-values prefix="u" uri="utils" />
|
|
<svrl:active-pattern>
|
|
<xsl:attribute name="document">
|
|
<xsl:value-of select="document-uri(/)" />
|
|
</xsl:attribute>
|
|
<xsl:apply-templates />
|
|
</svrl:active-pattern>
|
|
<xsl:apply-templates mode="M8" select="/" />
|
|
</svrl:schematron-output>
|
|
</xsl:template>
|
|
|
|
<!--SCHEMATRON PATTERNS-->
|
|
<svrl:text>Rules for PEPPOL BIS 3.0 Billing</svrl:text>
|
|
|
|
<!--PATTERN -->
|
|
|
|
|
|
<!--RULE -->
|
|
<xsl:template match="cac:InvoiceLine | cac:CreditNoteLine" mode="M8" priority="1000">
|
|
<svrl:fired-rule context="cac:InvoiceLine | cac:CreditNoteLine" />
|
|
<xsl:variable name="mySlack-R120" select="0.00" />
|
|
<xsl:variable name="lineExtensionAmount" select="1.00" /> <!-- if (cbc:LineExtensionAmount) then xs:decimal(cbc:LineExtensionAmount) else 0" /> -->
|
|
<xsl:variable name="quantity" select=" if (/ubl-invoice:Invoice) then (if (cbc:InvoicedQuantity) then xs:decimal(cbc:InvoicedQuantity) else 1) else (if (cbc:CreditedQuantity) then xs:decimal(cbc:CreditedQuantity) else 1)" />
|
|
<xsl:variable name="priceAmount" select=" if (cac:Price/cbc:PriceAmount) then xs:decimal(cac:Price/cbc:PriceAmount) else 0" />
|
|
<xsl:variable name="baseQuantity" select=" if (cac:Price/cbc:BaseQuantity and xs:decimal(cac:Price/cbc:BaseQuantity) != 0) then xs:decimal(cac:Price/cbc:BaseQuantity) else 1" />
|
|
<xsl:variable name="allowancesTotal" select=" if (cac:AllowanceCharge[normalize-space(cbc:ChargeIndicator) = 'false']) then round(sum(cac:AllowanceCharge[normalize-space(cbc:ChargeIndicator) = 'false']/cbc:Amount/xs:decimal(.)) * 10 * 10) div 100 else 0" />
|
|
<xsl:variable name="chargesTotal" select=" if (cac:AllowanceCharge[normalize-space(cbc:ChargeIndicator) = 'true']) then round(sum(cac:AllowanceCharge[normalize-space(cbc:ChargeIndicator) = 'true']/cbc:Amount/xs:decimal(.)) * 10 * 10) div 100 else 0" />
|
|
|
|
<!--ASSERT -->
|
|
<xsl:choose>
|
|
<xsl:when test="true" />
|
|
<xsl:otherwise>
|
|
<svrl:failed-assert test="true">
|
|
<xsl:attribute name="id">R1</xsl:attribute>
|
|
<xsl:attribute name="flag">fatal</xsl:attribute>
|
|
<xsl:attribute name="location">
|
|
<xsl:apply-templates mode="schematron-select-full-path" select="." />
|
|
</xsl:attribute>
|
|
<svrl:text>Calculation results | Line <xsl:text />
|
|
<xsl:value-of select="(cbc:ID)" />
|
|
<xsl:text /> || LineExtentionAmount <xsl:text />
|
|
<xsl:value-of select="($lineExtensionAmount)" />
|
|
<xsl:text /> || <xsl:text />
|
|
<xsl:value-of select="($quantity * ($priceAmount div $baseQuantity))" />
|
|
<xsl:text /> | <xsl:text />
|
|
<xsl:value-of select="($quantity * $priceAmount div $baseQuantity)" />
|
|
<xsl:text /> | <xsl:text />
|
|
<xsl:value-of select="(($quantity * $priceAmount) div $baseQuantity)" />
|
|
<xsl:text /> | </svrl:text>
|
|
</svrl:failed-assert>
|
|
</xsl:otherwise>
|
|
</xsl:choose>
|
|
<xsl:apply-templates mode="M8" select="*|comment()|processing-instruction()" />
|
|
</xsl:template>
|
|
<xsl:template match="text()" mode="M8" priority="-1" />
|
|
<xsl:template match="@*|node()" mode="M8" priority="-2">
|
|
<xsl:apply-templates mode="M8" select="*|comment()|processing-instruction()" />
|
|
</xsl:template>
|
|
</xsl:stylesheet>
|