I am using the Saxon XsltTransformer to transform the XML of electronic invoices ("XRechnungen", the German adaption). The invoices are XML files with "un/cefact CII" or "UBL" syntax and both need to be translated in the same XR syntax.
For UBL I use the files "ubl_invoice_xr.xsl" and "ubl_creditnore_xr.xsl" and this works without any problems.
For CII I use the "cii_xr.xsl" from https://github.com/itplr-kosit/xrechnung-visualization/tree/master/src/xsl but the result omits the allowances and charges (both on invoice_line-level and document-level).
At https://github.com/itplr-kosit/xrechnung-testsuite/tree/master/src/test/business-cases/standard I found a lot of test invoices ("uncefact" suffix) bot none of them is transformed correctly.
Looking at the "cii-xr.xsl" you find:
<xsl:template mode="BG-20"
match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge[ram:ChargeIndicator='false']">
<xsl:variable name="bg-contents" as="item()*"><!--Der Pfad /rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge[ram:ChargeIndicator='false'] der Instanz in konkreter Syntax wird auf 7 Objekte der EN 16931 abgebildet. -->
<xsl:apply-templates mode="BT-92" select="./ram:ActualAmount"/>
<xsl:apply-templates mode="BT-93" select="./ram:BasisAmount"/>
<xsl:apply-templates mode="BT-94" select="./ram:CalculationPercent"/>
<xsl:apply-templates mode="BT-95" select="./ram:CategoryTradeTax/ram:CategoryCode"/>
<xsl:apply-templates mode="BT-96" select="./ram:CategoryTradeTax/ram:RateApplicablePercent"/>
<xsl:apply-templates mode="BT-97" select="./ram:Reason"/>
<xsl:apply-templates mode="BT-98" select="./ram:ReasonCode"/>
</xsl:variable>
<xsl:if test="$bg-contents">
<xr:DOCUMENT_LEVEL_ALLOWANCES>
<xsl:attribute name="xr:id" select="'BG-20'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:sequence select="$bg-contents"/>
</xr:DOCUMENT_LEVEL_ALLOWANCES>
</xsl:if>
</xsl:template>
<xsl:template mode="BT-92"
match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:ActualAmount">
<xr:Document_level_allowance_amount>
<xsl:attribute name="xr:id" select="'BT-92'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:call-template name="amount"/>
</xr:Document_level_allowance_amount>
</xsl:template>
<xsl:template mode="BT-93"
match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:BasisAmount">
<xr:Document_level_allowance_base_amount>
<xsl:attribute name="xr:id" select="'BT-93'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:call-template name="amount"/>
</xr:Document_level_allowance_base_amount>
</xsl:template>
<xsl:template mode="BT-94"
match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:CalculationPercent">
<xr:Document_level_allowance_percentage>
<xsl:attribute name="xr:id" select="'BT-94'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:call-template name="percentage"/>
</xr:Document_level_allowance_percentage>
</xsl:template>
<xsl:template mode="BT-95"
match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:CategoryTradeTax/ram:CategoryCode">
<xr:Document_level_allowance_VAT_category_code>
<xsl:attribute name="xr:id" select="'BT-95'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:call-template name="code"/>
</xr:Document_level_allowance_VAT_category_code>
</xsl:template>
<xsl:template mode="BT-96"
match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:CategoryTradeTax/ram:RateApplicablePercent">
<xr:Document_level_allowance_VAT_rate>
<xsl:attribute name="xr:id" select="'BT-96'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:call-template name="percentage"/>
</xr:Document_level_allowance_VAT_rate>
</xsl:template>
<xsl:template mode="BT-97"
match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:Reason">
<xr:Document_level_allowance_reason>
<xsl:attribute name="xr:id" select="'BT-97'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:call-template name="text"/>
</xr:Document_level_allowance_reason>
</xsl:template>
<xsl:template mode="BT-98"
match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:ReasonCode">
<xr:Document_level_allowance_reason_code>
<xsl:attribute name="xr:id" select="'BT-98'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:call-template name="code"/>
</xr:Document_level_allowance_reason_code>
</xsl:template>
So the output file should contain "<xr:DOCUMENT_LEVEL_ALLOWANCES>" tags with (for example) "</xr:Document_level_allowance_amount>" children, but it does not. No matter if the input file has allowances/charges in the "invoice_lines" or at "document_level".
Since I use vb.NET I use the .NET wrapper of saxon-HE:
Public Shared Function Cii2UnifiedXML(ByVal vsXmlFilePath As String) As Result
Dim cproc As New Saxon.Api.Processor
Dim cComp As Saxon.Api.XsltCompiler = cproc.NewXsltCompiler
Dim exe As Saxon.Api.XsltExecutable
Dim inputStream As New StreamReader(vsXmlFilePath)
#Disable Warning BC40000 ' I know, XmlDataDocument is deprecated
Dim xmldoc As New XmlDataDocument()
#Enable Warning BC40000
Dim cResult As New Result
Dim ctrans As Saxon.Api.XsltTransformer
Dim seri As Saxon.Api.Serializer
Dim sPath As String = String.Empty
Dim sFilename As String = String.Empty
Dim outStream As FileStream = Nothing
Try
exe = cComp.Compile(New MemoryStream(Encoding.UTF8.GetBytes(My.Resources.cii_xr)))
ctrans = exe.Load
seri = cproc.NewSerializer
sPath = Path.GetDirectoryName(vsXmlFilePath)
sFilename = Path.Combine(sPath, $"{Path.GetFileNameWithoutExtension(vsXmlFilePath)}_Unified.xml")
outStream = New FileStream(sFilename, FileMode.Create, FileAccess.Write)
ctrans.SetInputStream(inputStream.BaseStream, New Uri(sPath))
seri.SetOutputStream(outStream)
ctrans.Run(seri)
cResult.Success = True
cResult.Obj = sFilename
Catch ex As Exception
cResult.Exception = ex
cResult.Success = False
cResult.ErrorMsg = ex.Message
Finally
xmldoc = Nothing
If outStream IsNot Nothing Then outStream.Close()
If inputStream IsNot Nothing Then inputStream.Close()
End Try
Return cResult
End Function
I don't know if I don't understand how the XsltCompiler works (and therefore I am too stupid) or if it's a bug, since the translation of UBL invoices works great. The output file of UBL translations contains the elements "DOCUMENT_LEVEL_ALLOWANCES", "DOCUMENT_LEVEL_CHARGES", "INVOICE_LINE_ALLOWANCES" and "INVOICE_LINE_CHARGES".
All files can be found at https://github.com/itplr-kosit
Thanks a lot