Altova MapForce 2027 Enterprise Edition

In diesem Kapitel erfahren Sie, wie Sie ein Python-Modul in MapForce importieren. Ein Python-Modul ist eine Python-Datei (.py), die Python-Code wie z.B. Funktionen, Klassen und Variablen enthält.

 

Im Modul definierte Python-Funktionen, -Klassen und-Variablen können im Fenster "Bibliotheken" angezeigt werden, wenn sie die in diesem Kapitel beschriebenen Voraussetzungen erfüllen. Anschließend können die Python-Funktionen wie jede andere MapForce-Funktion in einem Mapping verwendet werden.

 

Anmerkung: Auf Ihrem Rechner muss Python 3.6 oder höher installiert sein. Die MapForce -Plattform (32-Bit, 64-Bit) muss mit der von Python übereinstimmen.

 

Achtung

 

•Um Python-Funktionen importieren und ausführen zu können, benötigen Sie die MapForce Professional oder Enterprise Edition.

•Python-Funktionen werden von der Transformationssprache Built-In ausgeführt. Sie stehen nicht im generierten C#-, C++- oder XSLT-Code zur Verfügung.

•MapForce verwendet die unter Extras | Optionen | Python konfigurierte Python-Installation. Wenn im Dialogfeld Optionen kein Pfad definiert ist, versucht MapForce mit Hilfe der Umgebungsvariablen PYTHONHOME und PATH  eine Python-Installation zu finden.

•Es werden nur Mitglieder importiert, deren Parameter und Rückgabewerte mit einer Annotation über den unterstützten Typ versehen sind (siehe unterstützte Typen weiter unten). Die folgenden Mitglieder werden nicht importiert:

 

oMitglieder, deren Namen mit einem Unterstrich beginnen

oMitglieder, die von einer außerhalb des Moduls definierten Klasse stammen

 

•Wenn die .py-Datei geändert wird, informiert Sie MapForce darüber, sodass Sie diese neu laden können. Wenn Sie das Modul neu laden, werden alle Funktionen erneut importiert.

 

Automatisierung mit MapForce Server

Wenn Sie ein Mapping, das benutzerdefinierte Python-Funktionen enthält, mit MapForce Server ausführen, müssen Sie eventuell einen Pfad zum Python-Home-Verzeichnis definieren. Nähere Informationen dazu finden Sie in der MapForce Server-Dokumentation unter der Beschreibung des run-Befehls (https://www.altova.com/de/documentation#mapforceserver).

 

Automatisierung mit FlowForce Server

Wenn Sie ein Mapping, das benutzerdefinierte Python-Funktionen enthält, mit FlowForce Server ausführen, müssen Sie eventuell in der .tool-Datei die Python-Umgebungs konfigurieren und das Python-Modul auf dem Rechner, auf dem FlowForce ausgeführt wird, verfügbar machen. Nähere Informationen dazu finden Sie in der FlowForce Server-Dokumentation (https://www.altova.com/de/documentation#flowforceserver) im Kapitel Tool-Dateien.

 

Beispieldateien

Sie können zu Testzwecken ein Beispiel unter MapForceExamples\Python\FormatNumber.mfd verwenden, in dem die in Python\Format\Format.py definierte Funktion aufgerufen wird.

 

Die Beispiele in diesem Kapitel stammen aus dem Ordner MapForceExamples\Python\Sales\Sales.py.

 

Import eines Python-Moduls

Um ein Python-Modul als MapForce-Bibliothek zu importieren, gehen Sie folgendermaßen vor:

 

1.Klicken Sie im unteren Bereich des Fensters "Bibliotheken" auf die Schaltfläche Bibliotheken hinzufügen/entfernen. Daraufhin wird das Fenster "Bibliotheken verwalten" geöffnet.

2.Um Funktionen als lokale Bibliothek (nur im Geltungsbereich des aktuellen Dokuments) zu importieren, klicken Sie auf die Schaltfläche Hinzufügen unterhalb des aktuellen Mapping-Namens. Um Funktionen als globale Bibliothek (auf Programmebene) zu importieren, klicken Sie auf die Schaltfläche Hinzufügen neben "Globale Bibliotheksimporte".

3.Suchen Sie nach der gewünschten .py-Datei, z.B. MapForceExamples\Python\Sales\Sales.py. Die importierte Bibliothek wird nun im Fenster "Bibliotheken" angezeigt. Doppelklicken Sie alternativ dazu im Projektfenster auf eine .py-Datei, um sie als Bibliothek hinzuzufügen.

 

Wenn die neu importierte Bibliothek im Fenster Bibliotheken nicht angezeigt wird, vergewissern Sie sich, dass als Transformationssprache Built-In eingestellt ist. Um eine Funktion zum Mapping hinzuzufügen, ziehen Sie diese aus dem Fenster "Bibliotheken" in den Mapping-Bereich.

 

Unterstützte Python-Typen

In der nachstehenden Tabelle sind die Entsprechungen zwischen den unterstützten XML-Schema- und Python-Typen aufgelistet:

 

Schema-Typ

Python-Typ

xs:string

str

xs:integer

int

xs:double

float

xs:boolean

bool

xs:decimal

decimal.Decimal

xs:base64Binary

bytes

 

MapForce unterstützt die Übergabe von Werten von XML-Schema an Python und von Python zurück an XML-Schema und verwendet dazu die Typ-Entsprechungen aus der Tabelle. Die Python-Typen können für Parameter, Rückgabewerte und Module oder Klassenattribute verwendet werden. Zusätzlich dazu unterstützt MapForce im selben Modul definierte Klassen, vorausgesetzt, die Klassen können von MapForce verwendet werden (siehe "Objekte" weiter unten).

 

Funktionen und Methoden müssen für ihre Parameter und Rückgabewerte Typ-Annotationen haben (wie z.B. a: int oder -> int). Wenn ein Parameter oder Rückgabewert keine Annotation oder einen nicht unterstützten Typ hat, wird die entsprechende Funktion oder Methode nicht importiert.

 

Nicht unterstützte Python-Typen

Andere Python-Typen, wie z.B. die unten angeführten, werden nicht unterstützt:

 

•Importierte Klassen und andere Typen als decimal.Decimal

•list, dict, tuple, set und andere Container-Typen

•Generische Typen wie list[int]

•Optional[T] und Union[...]

•PEP 604 Unions wie z.B. int | str

•Iteratoren und Generatoren

•Asynchrone Funktionen und Generatoren

•Argumentlisten mit variabler Länge (*args, **kwargs)

 

Objekte

MapForce unterstützt Objekte, die Instanzen von im importierten Modul definierten verwendbaren Klassen sind. MapForce kann eine solche Instanz über einen Konstruktor, einen Wert auf Modulebene oder eine Factory-Funktion abrufen und die Instanz anschließend an Funktionen übergeben oder sie zum Aufrufen von Instanzmethoden und zum Auslesen von Instanzeigenschaften verwenden.

 

Im Codefragment unten sehen Sie die in Sales.py definierte Klasse CurrencyFormatter.

 

class CurrencyFormatter:

   DEFAULT_PATTERN: str = ",.2f"

 

   def __init__(self, prefix: str, pattern: str):

       self._prefix = prefix

       self._pattern = pattern

 

   @property

   def prefix(self) -> str:

       return self._prefix

 

   def format_amount(self, amount: Decimal) -> str:

       return self._prefix + format(amount, self._pattern)

 

   @staticmethod

   def plain(amount: Decimal) -> str:

       return format(amount, CurrencyFormatter.DEFAULT_PATTERN)

 

Fünf Einträge aus dieser Klasse werden im Fenster "Bibliotheken" angezeigt:

 

•CurrencyFormatter(): der Konstruktur, der eine neue CurrencyFormatter-Instanz erstellt..

•CurrencyFormatter.DEFAULT_PATTERN: ein Klassenattribut, das ohne eine Instanz gelesen werden kann.

•CurrencyFormatter.format_amount: eine Instanzmethode die auf eine CurrencyFormatter-Instanz angewendet wird.

•CurrencyFormatter.prefix: eine Eigenschaft, die aus einer CurrencyFormatter-Instanz ausgelesen werden kann.

•CurrencyFormatter.plain: eine statische Methode, die ohne eine Instanz aufgerufen werden kann. Klassenmethoden werden auf dieselbe Art importiert.

 

Abrufen und Übergeben von Instanzen

MapForce kann eine Instanz einer verwendbaren Klasse durch Aufruf ihres Konstruktors oder über ein anderes verwendbares Mitglied, das eine Instanz zurückgibt, abrufen. So kann eine Instanz etwa durch einen Wert auf Modulebene oder eine Factory-Funktion bereitgestellt werden.

 

EURO: CurrencyFormatter = CurrencyFormatter("EUR ", CurrencyFormatter.DEFAULT_PATTERN)

 

 

def formatter_for(prefix: str) -> CurrencyFormatter:

   return CurrencyFormatter(prefix, CurrencyFormatter.DEFAULT_PATTERN)

 

 

def format_with(formatter: CurrencyFormatter, amount: Decimal) -> str:

   return formatter.format_amount(amount)

 

Im obigen Codefragment ist EURO ein Wert auf Modulebene, der eine CurrencyFormatter-Instanz enthält, und formatter_for() ist eine Factory-Funktion, die eine CurrencyFormatter-Instanz zurückgibt. Die format_with()-Funktion nimmt eine CurrencyFormatter-Instanz als Parameter entgegen.

 

Aufrufbare Objekte

Ein Wert, der eine Instanz einer Klasse enthält, die __call__ definiert, kann wie eine Funktion aufgerufen werden (Codefragment unten). MapForce importiert einen solchen Wert daher als Funktion und hängt im Fenster "Bibliotheken" ein () an seinen Namen an. ROUND_CENTS im Beispiel unten ist ein Wert, der wie eine Funktion aufgerufen werden kann. MapForce importiert ihn als ROUND_CENTS() in das Fenster "Bibliotheken".

 

class Rounder:

   def __init__(self, places: int):

       self._places = places

 

   def __call__(self, amount: Decimal) -> Decimal:

       return round(amount, self._places)

 

 

ROUND_CENTS: Rounder = Rounder(2)

 

Funktionen und Werte

Eine Funktion auf Modulebene wird als Funktion importiert. Ein Wert auf Modulebene wird als Funktion ohne Parameter, die einen Wert zurückgibt, importiert.

 

Im nachstehenden Codefragment wird die Definition von Werten auf Modulebene (VAT_RATE und REPORT_TITLE) und Funktionen auf Modulebene (net_amount und period) gezeigt.

 

VAT_RATE: Decimal = Decimal("0.20")

REPORT_TITLE: str = "Regional sales"

 

 

def net_amount(gross: Decimal) -> Decimal:

   """Removes VAT from a gross amount."""

   return gross / (1 + VAT_RATE)

 

 

def period(start: str, end: str) -> str:

   return start + " - " + end

 

Das Modul enthält auch eine Funktion, die mit @functools.lru_cache dekoriert ist. MapForce importiert solche Funktionen wie gewohnt und ermittelt deren Schnittstelle anhand der Parameter und des Rückgabetyps der ursprünglichen Funktion. Der Dekorator ändert die Parameter und den Rückgabetyp, die MapForce für die Funktion ausgibt, nicht.

 

@functools.lru_cache(maxsize=None)
def region_name(code: str) -> str:
    """Expands a region code. The lookup table is built on first use only."""
    return _region_names().get(code, code)

 

Wiederverwenden von Objekten und Zwischenspeichern

Wenn eine Funktion oder ein Konstruktor in einem Mapping verwendet wird, ruft MapForce diese/diesen für jede Zeile auf, die das Mapping durchläuft. Wenn ein Konstruktor ein Objekt erstellt, dessen Initialisierung zeitaufwendig ist, kann es ineffizient sein, für jede Zeile eine neue Instanz zu erstellen.

 

Um dasselbe Objekt wiederzuverwenden, erstellen Sie es einmal auf Modulebene und verbinden Sie diesen Wert, wo die Instanz benötigt wird.

 

EURO: CurrencyFormatter = CurrencyFormatter("EUR ", CurrencyFormatter.DEFAULT_PATTERN)

 

Wenn Sie EURO mit dem ersten Parameter von CurrencyFormatter.format_amount verbinden, wird das Objekt einmal beim Laden des Moduls erstellt und für jede Zeile wiederverwendet. Werte auf Modulebene werden jedes Mal, wenn Sie verwendet werden, erneut ausgelesen. Wenn daher im Python-Code ein Wert auf Modulebene aktualisiert wird, liest MapForce den aktualisierten Wert bei der nächsten Verwendung aus.

 

Sie können die Ergebnisse von speicherintensiven Funktionsaufrufen auch zwischenspeichern. Ein Wörterbuch auf Modulebene oder @functools.lru_cache speichert zuvor zurückgegebene Ergebnisse:

 

@functools.lru_cache(maxsize=None)

def region_name(code: str) -> str:

   """Expands a region code. The lookup table is built on first use only."""

   return _region_names().get(code, code)

 

Aufgrund des @functools.lru_cache-Dekorators wird region_name() einmal pro eindeutigem Regionscode ausgeführt. Wenn in nachfolgenden Zeilen ein bereits verarbeiteter Code verwendet wird, gibt die zwischengespeicherte Funktion das Ergebnis aus dem Cache zurück, anstatt die Funktion erneut auszuführen.

 

Funktionen und andere Namen, an deren Beginn ein Unterstrich steht, wie z.B. _region_names, werden als nur zu diesem Modul gehörig betrachtet und nicht von MapForce importiert.

 

Beachten Sie die folgenden Punkte:

 

•Objekte auf Modulebene und zwischengespeicherte Werte stehen für die Dauer des Mappings zur Verfügung. Sie werden erneut geladen, wenn die Bibliothek erneut importiert werden.

•MapForce wertet ein Mapping in einem einzigen Thread aus, sodass für einen Cache auf Modulebene keine Sperre erforderlich ist.

•Vermeiden Sie, @functools.lru_cache in einer Instanzmethode zu verwenden, wenn für jede Zeile eine neue Instanz erstellt wird. In diesem Fall wird der Cache mit den Instanzen verknüpft und wächst immer weiter. Verwenden Sie stattdessen für die Zwischenspeicherung eine Funktion auf Modulebene.

•MapForce kann Attribute auf Modul- und Klassenebene lesen, ihnen jedoch keine Werte zuweisen. Aktualisieren Sie diese Werte mit Hilfe von Python-Code.

 

© 2020-2026 Altova GmbH