Skip to content

EBV-BXA

The EBV-BXA processes XML documents conforming to the EBV schema definitions.

The foundation for the EBV-BXA is the German official document: Verordnung zur Einführung einer Ersatzbaustoffverordnung.

Note

Prior to using the integration package you need to obtain a valid license from ZEDAL. This license, as well as the binary package (current version: 1.0.54), is available on request. Please send an e-mail with your inquiry to erp-tools@zedal.de.

Contents

The package contains:

  • A binary shared object for incorporating the functionality into third-party applications.
  • A header file to simplify inclusion into other C++ projects (lib.h).
  • A Directory schema containing the schema definitions.
  • The mapping directory contains PDFs illustrating which fields in the printouts correspond to which field id used by the EBV-BXA.

Technical info

The shared object (DLL for Windows, x86 and x64 platforms) is statically linked and provides a C interface for easy integration into most languages. On Windows it is built with Microsoft Visual Studio 2022, with the VC runtime also being statically linked in.

The file lib.h in the includes directory defines all function declarations to get the functionality by LoadLibrary / GetProcAddress on Windows, or dlopen / dlsym on Linux systems.

If targetting for C++11 or higher, the file xsd_names.h contains the constexpr variable linking namespaces and names corresponding to the element names in the XML. This will prevent mistyped names.

All library functions expect UTF-8 encoded strings and return UTF-8 encoded strings. The same applies to the XML files itself. Any other encoding may lead to errors or to incorrectly encoded content.

The header bxa_interface.h contains constants for common return values of the EBV functions and identifier strings for document and layer types.

The EBV-BXA can manage multiple XML documents in separate workspaces. Operations on multiple workspaces is thread safe. In the reference section the C type of every parameter is listed. For non C/C++ programmers:

  • const char* refers to a string which is zero-terminated
  • const char** expects a memory block large enough for an address (pointer). The library stores the address where the result can be fetched into this block. The memory area where the result resides is controlled by the library itself.
  • std::size is used for memory blocks of specified lengths, in case they are not zero-terminated.
  • std::size* means a pointer to std::size. The EBV-BXA will provide the length of the returned block.

Prerequisites

License

Using the EBV-BXA requires a license key which can be obtained from ZEDAL. The license consists of the vendor id and the license key. The vendor id will be written into the XML to identify which vendor / software has created /modified the layer. This potentially accelerates the troubleshooting process if interoperability problems should occur.

Document types

The XML specification defines three document types: Lieferschein, Anlage8 and Trägerdokument. The XML definition is designed with respect to the official forms. Because the electronic processing needs more information than the paper documents, the XML contains additional data.

ReferenzNr

The documents and the participants have optional fields to store a user defined ID for their purposes.

Zusatzdaten

Zusatzdaten contain additional fields for every participant mentioned in the documents. They take up to 60 characters each and could be used for storing IDs for linking to datasets in other IT systems.

Layers

The documents are organized into individual layers. This allows for changes even if a document was electronically signed. By adding a new layer, the old (signed) layer will be encapsulated without changing it. By design the EBV-BXA can only modify values in the top layer to avoid breaking electronic signatures unintentionally. In theory, layers can stack unlimited, but with electronic signatures on each layer, the verification of those will take more and more time, as each signature must be checked, including an OCSP check, which involves a remote call. The number of layers should be kept as small as possible. If a layer is not electronically signed it may be deliberately edited as many times as necessary. The Lieferschein document only has a single layer type, LieferscheinLayer. The Anlage8 document on the other hand provides two distinct workflows. One consists of layers exclusively of type DeckblattLayer. The second workflow makes use of the VoranzeigeLayer type, ultimatively followed by the AbschlussanzeigeLayer. Please consult the official EBV legal documents for when to use the different types of workflows.

Transparency

The layer structure is used by the EBV-BXA to compute the difference between two layers and only save values that actually have been changed. The exceptions to this rule are tables (e.g., Gemisch / MEB) which are completely rewritten even if only a single cell changes. When a value is written to a layer, the outcome will be influenced by the value in the previous layer(s). The following rules apply:

  • If an empty (“”) string is written and there exists no value in an older layer, nothing will be written, the value remains non existing.
  • If an empty (“”) string is written and a value from an older layer exists, the empty string will be written, which practically deletes the value from the new layer on.
  • If the same value already existing on the previous layer is written, nothing will be written, because there is no change.
  • All other cases: The newly set values will be written.

Dissemination

The Lieferschein document contains the XML block BeteiligtenListe, which defines how data transport should be carried out by the ZEDAL server.

Currently, two options exist:

  • Email – the document will be converted to a PDF, electronic signatures included as printed info, and the results being sent as an email to the specified receiver.
  • ZEDAL (only available if the receiver has a ZEDAL account, too) – direct transfer of the XML document to the receiver’s ZEDAL account.

Note: The BeteiligtenListe is not secured if an electronic signature is applied to the layer, as it defines the means of data transport only.

Mode of Operation

The EBV-BXA manages multiple workspaces. Each workspace can process a single XML document. Before a document can be processed, a workspace must be created with a call to ebv_initialize.

To initialize the EBV-BXA, a vendor id and license key as already mentioned under prerequisites must be provided. The vendor id will be part of the created layer element.

Here is an example of creating a Lieferschein document from scratch:

#include <bxa_interface.h>
#include <lib.h>
#include <stdio.h>

// example C++11 program creating a 'Lieferschein' from scratch, only writing the field
// ReferenzNr and outputting the generated XML to the file 'example.xml'
int main(int argc, char** argv)
{
    if (!LoadDll("ebvxba_shared.dll"))
        return 5; // dll load failed

    const auto workspace_id = ebv_initialize("your_vendor_id", "your_license_key");

    if (workspace_id > 0)
    {
        if (ebv_create(workspace_id, DT_LIEFERSCHEIN) == EBVBXA_OK)
        {
            const std::string field_list = R"(ReferenzNr=REF-001
)"; // this syntax includes a line-feed which is required

            if (ebv_set_field_list(workspace_id, field_list.c_str(), field_list.length()) == EBVBXA_OK)
            {
                const char* buffer = nullptr;

                if (ebv_get_xml(workspace_id, &buffer) == EBVBXA_OK)
                {
                    FILE* f = fopen("example.xml", "wb");
                    fwrite(buffer, 1, strlen(buffer), f);
                    fclose(f);
                }
                else
                {
                    return 3; // generating resulting xml failed
                }
            }
            else
            {
                return 2; // setting the field list failed
            }
        }
    }
    else
    {
        return 1; // error: initialize failed
    }

    return 0;    // success
}

The next code sample demonstrates the loading and extraction of the complete field list of an XML file.

#include <bxa_interface.h>
#include <lib.h>

// example C++11 program reading the contents of an EBV XML file and printing it to the console
int main(int argc, char** argv)
{
    if (!LoadDll("ebvxba_shared.dll"))
        return 2; // dll load failed

    const auto workspace_id = ebv_initialize("your_vendor_id", "your_license_key");

    if (workspace_id > 0)
    {
      if (ebv_load(workspace_id, "lieferschein.xml") == EBVBXA_OK)
      {
          const char* buf = nullptr;
          size_t size;

          if (ebv_get_field_list(workspace_id, 0, true, &buf, &size, true) == EBVBXA_OK)
          {
              printf("%s\n", buf);
          }
          else
          {
              return 3; // getting the field list failed
          }
      }
      else
      {
        return 2; // loading the XML failed
      }
    else
    {
      return 1; // error: initialize failed
    }

    return 0;    // success
}

Attachments

Every layer can contain binary attachments like PDF or DOCX files. These can be obtained through special functions in the EBV-BXA.

Content

The function ebv_get_field_list gets the content of the XML file in text format.

A sample output:

+Anlage8Nummer=
+Inverkehrbringer.Adresse.Name=Name
+Inverkehrbringer.Adresse.Strasse=Strasse
+Inverkehrbringer.Adresse.Hausnummer=42
+Inverkehrbringer.Adresse.Plz=12345
+Inverkehrbringer.Adresse.Ort=Ort
+Inverkehrbringer.Adresse.Staat=DE
+Inverkehrbringer.Kommunikation.Telefon=01234/56789
 Gemische.size=2
+Gemische[1].Bezeichnung=1. Bezeichnung des mineralischen Ersatzbaustoffs
+Gemische[1].Bemerkung=1. Bemerkung zum mineralischen Ersatzbaustoff
+Gemische[2].Bezeichnung=2. Bezeichnung des mineralischen Ersatzbaustoffs
+Gemische[2].Bemerkung=2. Bemerkung zum mineralischen Ersatzbaustoff
 Abfallschluessel.size=0

Every line consists of a single character indicating if the value is in the current layer (+) or in a historical layer (-), a field id, followed by an “equals” sign and the UTF-8 encoded value, and ends with a line feed character (Linux style line endings). If a field is not in the list, the corresponding element in the XML is also not present.

Line breaks inside the contents of a field are encoded as '\n'. In C++, a corresponding definition might be const char* line_break = "\\n";.

If there is no value after the “equals” sign the value is intentionally empty.

The field list contains meta fields like Gemische.size (preceded by a space by design) to simplify the handling of tables, by providing the size beforehand, even if the table is empty (see above example Abfallschluessel).

The package contains PDFs which illustrate the mapping from the paper printout to the path names expected by the EBV-BXA.

The ebv_get_field_list function has two different modes: view and layer. Both need a reference layer as an additional parameter.

In view mode the content is accumulated from the reference layer to the oldest (most inner) layer. Contents from a newer layer overrides contents from older layers.

In layer mode only the distinct reference layer is extracted.

In view mode the text format is slightly extended by a character before the actual path and value. A “plus” sign indicates that the value is changed in the reference layer, and a “minus” sign indicates content from an older layer.

Metainformation

Layers and signatures can be extracted to get insight to existing layers and check if they are electronically signed. ebv_get_field_list provides this information if the last parameter (includeMeta) of the call is equal to true.

The following table maps the XML paths to the field ids without the obligatory Meta prefix (e.g. Meta.Storniert):

field id xml path / value
.Storniert ebv:Lieferschein/@Storniert or ebv:Anlage8/@Storniert indcate the cancellation of the document
.Layer[] contains the list of layers from current to oldest in chronological order
.Layer[].Type Lieferschein:{LieferscheinLayer}, Anlage8: {DeckblattLayer} or {VoranzeigeLayer, AbschlussanzeigeLayer}
.Layer[].Role Lieferschein: INV, Anlage8: VER
.Layer[].Signatures[] list of signatures in order of appearance
.Layer[].Signatures[].Role role of signature encoded into the first three characters of id, always SNT. This stems from the re-using of the BMU signature schemes
.Layer[].Signatures[].Id envelope
.Layer[].Signatures[].Index consecutive number of signature in layer
.Layer[].Signatures[].XmlId ds:Signature/@Id
.Layer[].Signatures[].XmlPath xml path to node with signature, e.g. ebv:Lieferschein/ebv:Layer/ebv:LieferscheinLayer/ds:Signature[1]
.Layer[].Signatures[].DistinguishedName not available, always empty
.Layer[].Signatures[].SubjectName ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509SubjectName
.Layer[].Signatures[].Certificate ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate
.Layer[].Signatures[].SigningTime ds:Signature/ds:Object/dsx:QualifyingProperties/dsx:SignedProperties/dsx:SignedSignatureProperties/dsx:SigningTime
.Layer[].Attachments[] list of binary attachments in the corresponding layer
.Layer[].Attachments[].File File elements; only in field list if the attachment is a file (e.g. PDF)
.Layer[].Attachments[].Xml Xml indicates an arbitrary XML node as attachment
.Layer[].Attachments[].IsSigned indicate if attachment is secured by an electronic signature
.Layer[].Attachments[].File.Id always signiert
.Layer[].Attachments[].File.Index consecutive number of attachment in corresponding layer
.Layer[].Attachments[].Filename ebv:Dateianhang/@dateiname
.Layer[].Attachments[].Mime ebv:Dateianhang/@inhaltsTyp denotes the type of attachment Lieferschein: {Sonstiges}, Anlage8: {Lageskizze, Nachweis, Sonstiges}
.Layer[].Attachments[].Size ebv:Dateianhang/@dateigroesse size of the attachment in bytes
.Layer[].Attachments[].File.XmlId ebv:Dateianhang/@id
.Layer[].Attachments[].Remark ebv:Dateianhang/ebv:Bemerkung optional description of the contents
.Layer[].Attachments[].Xml.id ebv:FreieXMLStruktur/@id
.Layer[].Attachments[].Xml.Uri ebv:FreieXMLStruktur/@NamespaceURI identifies an XML structure not defined by the specification
.FollowupLayer Lieferschein: {LieferscheinLayer}, Anlage8: {DeckblattLayer}, oder {VoranzeigeLayer, AbschlussanzeigeLayer}/{AbschlussanzeigeLayer} this indicates possible next layers used in _ebv_add_layer`
.SignaturePositions[] List of signature positions, contains exactly one element
.SignaturePositions[0].id envelope
.SignaturePositions[0].inner_positions empty list
.AttachmentPositions[] List of possible attachment locations:
1. binary attachments: {id:”signiert”, attachmentType:File, is_signed:true},
2: arbitrary XML: {id:”signiert”, attachmentType:Xml, is_signed:true}
.CurrentSignatures[] List of top-level signatures, which may also be on older layers
.CurrentSignatures[].InLayer indicates if a signature is in the current layer, or on an older one
.CurrentSignatures[].Id INV if the document is of type Lieferschein, else VER
.CurrentSignatures[].Signatures[] single signature
.CurrentSignatures[].Signatures[].Felder see structure of Layer[].Signatures[]

Cancellation

The attribute Storniert set to true on the document root element indicates a cancelled document.

Signatures

The specification allows for optional electronic signatures adhering to the eIDAS regulation of the EU, and thus conforming to XAdES Baseline Signatures B-B. The specification supports the use of XMLDsig and XAdES compliant electronic signatures, used for qualified electronic signatures as defined in the EU eIDAS regulation. Regardless of whether a party uses electronic signatures, received documents may contain them. Recommendations regarding the treatment of signed documents also apply to parties which do not sign documents themselves. In the processing of signed documents, the following points must be respected in order to avoid breaking signatures accidently:

  • To allow electronic signatures to be verified later, the stored representation must yield the same content after canonicalization as the canonicalization did when the document was signed. The simplest way of achieving this is by storage of the unmodified message.
  • Validating XML parsers modify XML documents implicitly (Normalization). Therefore they must not be used to process the messages. It may be possible to instruct validation parsers to skip the whitespace normalization but this is non-standard behaviour and there is no guarantee that every parser provides this feature.

In the process of creating electronic signatures, several parameters define how the signature is applied and which algorithm may be used. The definition of XMLDsig is very flexible, but to achieve good interoperability the following parameters from the specification must be used: * CanonicalizationMethod’s Algorithm attribute must be set to http://www.w3.org/2001/10/xmlexc-c14n (exclusive c14n ignoring comments) * The ds:Signature Element must contain the Id Attribute, its value beginning with SNT- followed by an UUID. This ID must be globally unique. * SignatureMethod’s Algorithm attribute must be set to: http://www.w3.org/2001/04/xmldsigmore#rsa-sha256"/ * The first Reference-Element must be set as URI=”” - the empty URI. This takes the document as context for the signature while ignoring XML comments. * The Transforms element defines in more detail which part of the XML instance is taken into account. The complete Transforms Block must be:

<ds:Transforms>
  <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
  <ds:Transform Algorithm="http://www.w3.org/2002/06/xmldsig-filter2">
    <xpf:XPath Filter="intersect" xmlns:xpf="http://www.w3.org/2002/06/xmldsig-filter2">here()/ancestor::*[6]
    </xpf:XPath>
  </ds:Transform>
  <ds:Transform Algorithm="http://www.w3.org/2002/06/xmldsig-filter2">
    <xpf:XPath Filter="subtract" xmlns:xpf="http://www.w3.org/2002/06/xmldsig-filter2">here()/ancestor::*[6]/*[local-name()='Signature']
    </xpf:XPath>
  </ds:Transform>
  <ds:Transform Algorithm="http://www.w3.org/2002/06/xmldsig-filter2">
    <xpf:XPath Filter="subtract" xmlns:xpf="http://www.w3.org/2002/06/xmldsig-filter2">here()/ancestor::*[6]/*[local-name()='BeteiligtenListe' and namespace-uri()='http://www.infotech.de/zedal/ebv.xsd']
    </xpf:XPath>
  </ds:Transform>
  <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>

  • Performance considerations:
  • DigestValue’s Algorithm must be set to http://www.w3.org/2001/04/xmlenc#sha256
  • KeyInfo/X509Data/X509Certificate must contain the certificate used in signing the document.

Attachments

The EBV document is capable of transporting binary BASE64 encoded content to the participants in the electronic process. Information about the attachments can be obtained with ebv_get_field_list and the parameter includeMeta set to true. Managing attachments is possible through the ebv_***_attachment functions.

Attachments can be classified into the following categories:

  • Sonstige (others)
  • Nachweis (notification, proof)
  • Lageskizze (location sketch)

Mapping reference

This section contains PDF files which illustrate the mappings from the official documents (with additions for the electronic processing in ZEDAL) to the field ids utilized by the EBV-BXA.

XML examples

Version history

1.0.44

First public release

1.0.45

  • Added new field WiegescheinNr to the Anlage 7 (Lieferschein) document

1.0.54

  • Added new document type Trägerdokument