In another article, *Digital invoice processing in combination with XML invoices*, the benefits of receiving and processing XML invoices were described. In order to read an XML invoice, an existing XML invoice field layout must be available. In the menu item 'Application Management / Invoice Processing / XML Invoice Field Layout', you will find all XML field layouts, also known as XML mappings, available in your environment.
There is a standard set of XML field layouts available for all customer environments. This set is managed by Visma | ProActive, and this is indicated by the fact that these XML field layouts cannot be edited or deleted. Additionally, it is possible to create your own XML field layout. This might be considered if the XML invoice:
First, investigate whether the XML file for which you want to add a field layout has field names that correspond to an existing XML field layout. If you want to create a more specific XML field layout where the XML is based on an already existing XML format, it is advisable to copy an existing XML field layout. For example, copy the mapping 'Standard UBL invoice field layout' by clicking the three dots at the end of the row and choosing to copy:
You can upload an XML file you received from the creditor.
To process an XML invoice, a Recognition String must be present. This is a string of characters based on which the file is recognized by Spend Cloud as an invoice. For UBL invoices, it boils down to any XML file containing one of the following strings being processable from the mailbox:
Once setting the recognition string is successful, a line identifier must be set. This is a field within the XML file that reads each invoice line. By default, this is //cac:InvoiceLine, and in the case of UBL invoices, no changes are needed. If the creditor delivers an XML invoice not structured according to the UBL format, it is important that each invoice line in the file is opened and closed with the same tag.
An XML file is attached containing the standard structure according to UBL, with a short explanation of the information typically included in these fields. An XML invoice is almost always structured with a general part first, the invoice header (invoice date, total amount, IBAN, etc.), followed by the specification per invoice line (item 1 on line 1, item 2 on line 2, etc.) with, per line, among other things, the price and description.
In the header of the invoice, you will find data that can be used in mapping for the sections 'Invoice Information', 'Relation/Creditor Information', and 'Recipient Information'.
For example, to recognize the correct creditor, Spend Cloud primarily looks for the bank account number (IBAN). By default, this is included in the UBL format in the field: //cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:ID . If the creditor is not recognized, a possible cause is that the bank account number does not match the one registered for the creditor in Spend Cloud or that the creditor, for example, did not include it in the XML file.
Here is an example of the XML path used to read an IBAN from a UBL-format XML invoice. Pay particular attention to the notation method. You must map a field by starting with '//' and each further level (indent or tab) is mapped with a slash '/' followed by the underlying field.
Does your creditor provide specific data, such as the general ledger account number, cost center, or costunit? Then you can read these fields for as fully automatically filled-in invoice coding as possible. Suppose the creditor provides a cost center number in the field <cbc:AccountingCost>, then you could map this. Since this field is at invoice line level and a line identifier is specified at the top of the XML field layout (//cac:InvoiceLine), you do not need to include that part again in the field mapping cbc:AccountingCost suffices as a field value in this case.
In this way, you can coordinate with suppliers on which data you would like to see included in the XML file, and you can configure Spend Cloud to correctly interpret that data. This enables the automation of the invoice processing for those suppliers. You may need to get used to how XML files are structured, but once you understand it, you can use a custom XML field mapping to have invoice coding largely filled in automatically.
Did you know that instead of a string, you can also enter a specific number? When a specific XML invoice field arrangement always pertains to, for example, the same cost center or general ledger account, but the supplier of these invoices is unable to include this in the invoice, you enter the number here, and the Spend Cloud automatically fills it in the invoice. Keep in mind that this value can be overridden by a default value at the relation, template, or matched procurement order level.
If the XML
invoice line fields are provided correctly by the supplier, you should edit the supplier (relation) in Spend Cloud and change the type of “
XML invoice grouping.” By default, only the XML invoice
header data is read, and
all XML invoice lines are grouped into a single invoice line. This is because some suppliers include a very large number of invoice lines, which would otherwise result in many separate lines in the “Coding” menu in Spend Cloud, even though the coding would be the same for each line. For this reason, the setting “Include lines from XML invoice” is not recommended. For example, if 15 different items are listed in the XML invoice, 15 invoice lines would be created. A better option at the relation level is “
Custom grouping,” where you can group the XML invoice lines based on a specific field such as general ledger account or a combination of fields like general ledger account, cost center, and VAT percentage (if VAT is applicable). See below how this can be configured at the relation level:

Caution: If you work with the
Procurement module, the
purchase order match takes precedence over the XML invoice line data. For these suppliers, it's better to focus on as complete a purchase order coding as possible. What’s important for such suppliers is that the purchase order number is included in the XML file so that an automatic match can be made. By default, the purchase order number is included in the UBL format within the XML invoice lines (`cac:InvoiceLine`) in the field
cac:OrderLineReference/cac:OrderReference/cbc:ID, and it can be configured in the “
Order data” section. Optionally, the order number can also be included in the invoice header, but this is only possible if only one purchase order number applies per invoice. If you want to perform a more specific match, you could also map the fields Item
Number and
Quantity in the “
Order data” section to allow for partial deliveries at the item level in the matching process.
Mutation log
It is possible to view a change overview for the XML field mapping. If any changes have been made and are not working as expected, you can see who made what changes here and easily copy the string to adjust the field mapping again.
Tips & Tricks for creating a mapping
Creating a Field Layout Using AI
Creating an XML field mapping and writing XPath code can quickly become quite complex. Additionally, because not every XML invoice is the same, there are various ways to approach extracting invoice data. AI makes this significantly easier. Large Language Models (LLMs) are exceptionally good at assisting with XML-related queries. For example, you can use our own DIRK Chat Help, which uses information from this article to provide answers on how to extract data from an XML. External models like ChatGPT and Gemini can also be very helpful in this regard.
Provide the AI with context. The more information the AI has about the situation, the better it can assist you. See the example prompt below:
"I work for a [sector] organization and receive and process invoices in XML format. My task is to provide these invoices with financial coding. To do this as efficiently as possible, I want to extract data automatically. The invoice includes [your desired data], and I want to extract this using XPath 1.0*. Please see (part of) the XML invoice layout here: [insert your XML invoice with the desired data here]."
*The Spend Cloud extracts XML data exclusively using XPath 1.0. If you do not mention this to the AI, it may attempt to help you using higher versions of XPath or other programming languages like Python.
**Important: Ensure that any data traceable to a person or entity is anonymized or removed beforehand! You want the invoice to remain as "intact" as possible so the AI gets an accurate picture of the structure, but you obviously do not want to share personal data. Change details to something fictitious, or simply use [vendor name] or [client name]. Particularly when extracting parts of a description, it is vital that the formatting remains the same; do not remove spaces, hyphens, or other characters that affect the length or layout of the invoice.
If you prefer to write your own question, it isn’t strictly necessary to send a long story with every prompt. However, explaining what you are doing and your specific goal in a few short sentences at the start of your conversation will help the AI better understand your request.
Custom Field Mapping Based on a Specific Situation
Sometimes a supplier cannot provide the specific information in the XML in a way that Spend Cloud can interpret. Consider the following examples:
1. Instead of just the cost center number, the number and name are always included, like “1000 - Cost Center A.”
2. The supplier provides the cost center and cost object numbers in a single field, for example: “1000-4800.”
3. The supplier includes the number in a field that contains other variable information, for example: “Streetname 12B 1000,” where it always ends with the cost center number.
4. The supplier includes a description per invoice line, but for processing you want the combination “Supplier Name - Description” to appear in the line.
5. The supplier includes an element multiple times per invoice line, so you can't target the element directly, but need to use a parent element. For example:<cac:AdditionalItemProperty>
<cbc:Item>Cost Center Code</cbc:Item>
<cbc:Value>1000</cbc:Item>
</cac:AdditionalItemProperty>
<cac:AdditionalItemProperty>
<cbc:Item>General Ledger</cbc:Item>
<cbc:Value>4400</cbc:Item>
</cac:AdditionalItemProperty>
6. The supplier includes an element multiple times, making it impossible to target the element itself directly, for example:
<cac:InvoiceLine>
<cac:Item>
<cbc:Name>Item Description</cbc:Name>
</cac:Item>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cac:Item>
<cbc:Name>I.1.24.123456</cbc:Name>
</cac:Item>
</cac:InvoiceLine>
7. The creditor provides a specific value that determines the cost type. Based on this value, you want to automatically populate a cost allocation (dimension). For example, when hiring healthcare personnel, you may want to distinguish between the healthcare worker’s hourly rate and the recruitment agency’s fees.
8. The creditor does not provide "inclusive of VAT" (gross) amounts at the invoice line level. However, when an "exclusive of VAT" (net) amount and a VAT percentage are provided in the XML invoice at the line level, it is possible to calculate the gross amount.
9. The creditor includes quantities in the invoice—for instance, the number of products delivered or hours worked by external hires. You can extract these quantities from all invoice lines and sum them into a single total.
With certain functions, it is still possible to extract the correct values. Below are a few functions that help retrieve the correct values:
1. <cbc:AccountingCost>1000 - Cost center A</cbc:AccountingCost> → Cost center 1000 needs to be extracted
Function: substring(cbc:AccountingCost,0,4) → this function extracts a portion of the value; starting at position 0, it reads the next 4 characters
2. <cbc:AccountingCost>1000-4800</cbc:AccountingCost> → Cost center 1000 and cost carrier 4800 need to be extracted
Function for cost center: substring-before(cbc:AccountingCost,'-') → extracts the portion before the hyphen
Function for cost unit : substring-after(cbc:AccountingCost,'-') → extracts the portion after the hyphen
3. <cbc:AccountingCost>Richard Holkade 9 1000</cbc:AccountingCost> → Cost center number 1000 needs to be extracted. The address before the number can vary per invoice, so you can't rely on a fixed value like with the substring-before or substring-after functions.
Function: substring(//cbc:AccountingCost, string-length(//cbc:AccountingCost) - 3) → this function calculates the total number of characters within the cbc:AccountingCost element and then extracts the last character plus the three characters before it. So, in total, four characters — the length of the cost center number in this example.
4. <cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name>Visma|ProActive</cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name> &
<cac:InvoiceLine/cac:Item/cbc:Description>Factuur Kwartaal 1</cac:InvoiceLine/cac:Item/cbc:Description> → Description should be *Visma|ProActive - Factuur Kwartaal 1*
Function: concat(//cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name,' - ',cac:InvoiceLine/cac:Item/cbc:Description) → The concatenate function combines different values, separating them with a comma. By using quotation marks, plain text can be added — in this case, a dash is used.
5. <cac:AdditionalItemProperty><cbc:Item>Costcenter code</cbc:Item><cbc:Value>1000</cbc:Value></cac:AdditionalItemProperty>
The invoice line contains multiple elements like this, so you can’t simply rely on `cbc:Value`, since it’s not unique. However, you can make it unique by using the element above it, *Kostenplaatscode*. This value is unique, and we know that under the *Cost center code*, the corresponding code will always be provided.
Function: //cac:AdditionalItemProperty[cbc:Name='Cost center code']/cbc:Value` → In this string, we specify that we want to extract the value from `cbc:Value` only if the parent element contains a `cbc:Name` with the value 'Cost center code'.
6. <cac:InvoiceLine><cac:Item><cbc:Name>I.1.24.123456</cbc:Name></cac:Item></cac:InvoiceLine>
The invoice contains multiple `cbc:Name` elements where the supplier includes unique values. However, the parent element is not unique, making them hard to distinguish at first. In this example, we want to extract a purchase order number from the invoice.
Function: //cac:Item/cbc:Name[starts-with(., 'I.') and string-length(.) = 13] → In this case, we want to extract the value from `cbc:Name` only if it starts with an *I* and has a total length of 13 characters. This is a unique sequence used only for the order number and always has the same structure.
If you want to extract a cost center code, you can also target values in `cbc:Name` that consist only of digits and have a specific length. For example:
//cbc:Name[string-length(translate(., '0123456789', '')) = 0 and string-length(.) = 6] → in this example, the cost center code is 6 characters long. You can also apply this logic if you want to extract a certain reference number on an invoice, for example the AE-number from Albert Heijn: //cac:PaymentMeans[starts-with(cbc:PaymentID, 'AE')]/cbc:PaymentID
7. <cac:InvoiceLine><cac:Item><cbc:Description>Bemiddeling zorgpersoneel</cbc:Description></cac:Item></cac:InvoiceLine>
In this example, we assume the invoice contains no more than two invoice lines: one for the healthcare worker’s costs and one for the agency fees. The XPath statement used here can be expanded based on various conditions. Naturally, this increases processing complexity; we therefore recommend keeping invoices as "small" as possible, limiting them to a single healthcare worker or cost center.
There are two solutions based on conditional logic:
Option 1: "If the description contains X, use GL account 1; if it contains Y, use GL account 2."
Option 2: "If the description contains X, use GL account 1; if it does not contain X, use GL account 2."
Option 1 function: concat(substring('12345', 1, count(//cac:Item/cbc:Description[text() = 'bemiddeling'])*6), substring('67890', 1, count(//cac:Item/cbc:Description[text() = 'Uurtarief zorgpersoneel'])*5))
In this example, if the Description contains 'bemiddeling', GL account 12345 is populated. If it contains 'Uurtarief zorgpersoneel', account 67890 is used. Note: Adjust the *5 multiplier to match the character length of your GL account (e.g., use *6 for a six-digit account).
Option 2 function: concat(substring('12345', 1, count((//cac:Item/cbc:Description)[2][contains(., 'Bemiddeling')]) * 5), substring('67890', 1, count((//cac:Item/cbc:Description)[2][not(contains(., 'Bemiddeling'))]) * 5))
Here, if the Description of the second line [2] contains 'Bemiddeling', use GL 12345; otherwise, use 67890. Again, adjust *5 to your account length. Crucially, this example specifically targets the second invoice line via [2]. For this solution to work, the creditor must bill as simply as possible (one location, one employee) and maintain a consistent XML structure.
8. round(cbc:LineExtensionAmount * (1 + cac:Item/cac:ClassifiedTaxCategory/cbc:Percent div 100) * 100) div 100
The gross amount ("Invoice Line - Incl. VAT") must be calculated from the net amount. In this example, the net amount is found in LineExtensionAmount and the VAT percentage in cac:Item/cac:ClassifiedTaxCategory/cbc:Percent, but the gross amount is missing. The VAT amount itself ("Invoice Line - VAT Amount") can be determined similarly via: round((cbc:LineExtensionAmount * (cac:Item/cac:ClassifiedTaxCategory/cbc:Percent) div 100) * 100) div 100
9. Summing Quantities In this example, we assume the creditor provides the quantity per invoice line. While the XML contains multiple lines, you are grouping them in Spend Cloud. You then use the following XPath: sum(//cbc:InvoicedQuantity). The sum function adds all found values together. By starting the element with //, you specify that the value within InvoicedQuantity should be retrieved for every invoice line in the XML and totaled. If you are importing all invoice lines individually into Spend Cloud, you only need to provide InvoicedQuantity.
Testing the XML Field Mapping
If you’ve created or modified a custom XML field mapping, you can test whether the XML file is read as expected. When you open an XML field mapping, click the **“Test Mapping”** button. Then upload an XML invoice and click the green button to apply the mapping. You will now see an overview of all fields that have a recognition string defined, and on the right side what was actually found in the XML. If nothing is found, this is shown in red. In that case, the recognition string may need to be adjusted. If you see an error message, it means the recognition string cannot be applied to the invoice. Adjust it or create a new field mapping with the correct recognition string.