我们将Peppol供应商发票导入ERP系统,然后使用xslt转换为另一种xml格式。这样的发票示例如下:Github:OpenPEPPOL/peppol-bis-invoice-3
我想让我的会计师在每个ERP供应商发票日记账字段中填充哪些字段方面有充分的自由。我想让他们从预定义的一组节点中进行选择,例如:
/Invoice/ID /Invoice/IssueDate
/Invoice/AccountingSupplierParty/Party/PartyName/Name
/Invoice/InvoiceLine/InvoicedQuantity
/Invoice/InvoiceLine/Item/Name
我从ERP系统导入特定的供应商信息,以便在转换过程中使用,例如查找供应商帐户:
<vendors>
<vendor>
<administration>YIT</administration>
<FISCALCODE>04705810150</FISCALCODE>
<accountNumber>20003</accountNumber>
<Offset_LedgerAccount>67123</Offset_LedgerAccount>
<name>A.Manzoni&C. Spa</name>
</vendor>
<vendors>
我使用下面的xslt在供应商xml表中查找这些信息:
<xsl:variable name="LegalEntity">
<xsl:choose>
<xsl:when test="contains(cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc:Name, 'Italia')">YIT</xsl:when>
<xsl:otherwise>'UNKNOWN LegalEntity'</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="current-vendor-name" select="cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name"/>
<xsl:variable name="vendor-data" select="document('Vendors.xml')/vendors/vendor[name=$current-vendor-name and administration=$LegalEntity]"/>
转换的输出(当应用于链接中的示例输入文件时(当前如下:
<?xml version="1.0" encoding="utf-8"?>
<PurchaseInvoices_version_1.0>
<PurchaseInvoice>
<LegalEntity>YIT</LegalEntity>
<SupplierAccountNum>20202</SupplierAccountNum>
<SupplierBankAccount>IBAN32423940</SupplierBankAccount>
<SupplierName>SupplierTradingName Ltd.</SupplierName>
<SupplierCity>London</SupplierCity>
<CurrencyCode>EUR</CurrencyCode>
<AmountExclTax>1325</AmountExclTax>
<AmountInclTax>1656.25</AmountInclTax>
<TaxAmount>331.25</TaxAmount>
<InvoiceId>Snippet1</InvoiceId>
<InvoiceDate>13-11-2017</InvoiceDate>
<PaymentNote>Payment within 10 days, 2% discount</PaymentNote>
<TaxCode>S</TaxCode>
<Lines>
<Line>
<Item>|Description of item</Item>
<Quantity>7</Quantity>
<UnitPrice>400</UnitPrice>
<LineAmount>2800</LineAmount>
<AmountIncl>3500</AmountIncl>
<AmountExcl>2800</AmountExcl>
<TaxAmount>700</TaxAmount>
<TaxCode>S</TaxCode>
<Description>Description of item|2017-11-13</Description>
<Unit>pcs</Unit>
</Line>
<Line>
<Item>|Description 2</Item>
<Quantity>-3</Quantity>
<UnitPrice>500</UnitPrice>
<LineAmount>-1500</LineAmount>
<AmountIncl>-1875</AmountIncl>
<AmountExcl>-1500</AmountExcl>
<TaxAmount>-375</TaxAmount>
<TaxCode>S</TaxCode>
<Description>Description 2|2017-11-13</Description>
<Unit>pcs</Unit>
</Line>
</Lines>
</PurchaseInvoice>
</PurchaseInvoices_version_1.0>
我想在输入xml中的哪些文本(节点(用于描述字段以及显示它们的顺序方面创造更多的自由度。这应该在供应商卡上按供应商定义,并导入到vendors.xml文件中,上面显示了该文件的示例。
例如,对于供应商A,描述可以是所有节点的串联:
/Invoice/ID /Invoice/IssueDate
/Invoice/InvoiceLine/Item/Name
/Invoice/InvoiceLine/InvoicedQuantity
/Invoice/AccountingSupplierParty/Party/PartyName/Name
而对于供应商B,描述只能是:
/Invoice/InvoiceLine/Item/Name
问题是如何从这里开始。
我目前的想法是基于固定数量的变量创建一个描述:
<Description><xsl:value-of select="$A"/><xsl:value-of select="$B"/><xsl:value-of select="$C"/><xsl:value-of select="$D"/></Description>
并根据Vendor卡上的某种输入在每个变量中放置正确的节点,Vendor卡被导入vendors.xml文件并在xslt脚本中使用。
根据您最初的想法,使用数字代码来确定描述中包含的值的顺序,请考虑以下简化的示例。
XML
<Invoice>
<ID>001</ID>
<DueDate>2002-01-01</DueDate>
<LineItem>
<Name>Widget</Name>
<Quantity>5</Quantity>
<Description>Description of widget</Description>
</LineItem>
<LineItem>
<Name>Gadget</Name>
<Quantity>17</Quantity>
<Description>Description of gadget</Description>
</LineItem>
</Invoice>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="reorder">030102</xsl:param>
<xsl:template match="/Invoice">
<PurchaseInvoice Id="{ID}">
<!-- ... -->
<xsl:for-each select="LineItem">
<Line>
<!-- ... -->
<Description>
<xsl:call-template name="reorder">
<xsl:with-param name="nodes" select="../DueDate | Name | Description"/>
<xsl:with-param name="order" select="$reorder"/>
</xsl:call-template>
</Description>
</Line>
</xsl:for-each>
</PurchaseInvoice>
</xsl:template>
<xsl:template name="reorder">
<xsl:param name="nodes" select="/.."/>
<xsl:param name="order"/>
<xsl:value-of select="$nodes[number(substring($order, 1 , 2))]"/>
<xsl:if test="string-length($order) > 2">
<xsl:text> | </xsl:text>
<!-- recursive call -->
<xsl:call-template name="reorder">
<xsl:with-param name="nodes" select="$nodes"/>
<xsl:with-param name="order" select="substring($order, 3)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="UTF-8"?>
<PurchaseInvoice Id="001">
<Line>
<Description>Description of widget | 2002-01-01 | Widget</Description>
</Line>
<Line>
<Description>Description of gadget | 2002-01-01 | Gadget</Description>
</Line>
</PurchaseInvoice>
为了保持简单,必须将数字代码按照它们在输入XML中的显示顺序分配给nodes
参数中列出的值。
在本例中,代码是一个全局参数;在您的实现中,您将希望从供应商文档中检索它。
添加:
如果愿意,可以使用描述性字符串而不是数字代码来选择顺序。但是样式表变得更加复杂:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="reorder">description|due date|name</xsl:param>
<xsl:template match="/Invoice">
<PurchaseInvoice Id="{ID}">
<!-- ... -->
<xsl:for-each select="LineItem">
<Line>
<!-- ... -->
<Description>
<xsl:call-template name="reorder">
<xsl:with-param name="order" select="$reorder"/>
</xsl:call-template>
</Description>
</Line>
</xsl:for-each>
</PurchaseInvoice>
</xsl:template>
<xsl:template name="reorder">
<xsl:param name="order"/>
<xsl:param name="delimiter" select="'|'"/>
<xsl:variable name="token" select="substring-before(concat($order, $delimiter), $delimiter)" />
<xsl:choose>
<xsl:when test="$token='due date'">
<xsl:value-of select="../DueDate"/>
</xsl:when>
<xsl:when test="$token='name'">
<xsl:value-of select="Name"/>
</xsl:when>
<xsl:when test="$token='description'">
<xsl:value-of select="Description"/>
</xsl:when>
</xsl:choose>
<xsl:if test="contains($order, $delimiter)">
<xsl:text> | </xsl:text>
<!-- recursive call -->
<xsl:call-template name="reorder">
<xsl:with-param name="order" select="substring-after($order, $delimiter)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>