3.3  Namespaces

Wenn man XML Instanzen aus unterschiedlichen Quellen mit XSLT verarbeiten will, wird man sich wohl oder übel mit dem Thema Namespaces auseinander setzen müssen, um Konflikte in den Elementselektoren zu vermeiden.
Gerade bei hintereinandergeschalteten Transformationen kann es auch passieren, dass unerwartet ein Namespace in die Ausgabe generiert wird, den der folgende Prozesschritt nicht versteht, weil er dort nicht deklariert wurde.
Es gibt meherere Möglichkeiten einen Namespace im Stylesheet zu deklarieren. Gehen wir davon aus, dass in einem Transformationsschritt genau eine Quelle und max. eine Konfigurationsdatei verarbeitet wird, dann kann das Stylsheet-Element bspw. so aussehen:
<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:tektur="https://namespace-eigener-xslt-funktionen"
  xmlns="http://namespace-in-der-xml-eingabe.com/"
  xpath-default-namespace="https://namespace-der-konfigdatei.com/"
  exclude-result-prefixes="#all">
  • Der xsl Namespace ist natürlich der Namespace für die XSLT Answeisungen und muss deklariert werden.
  • Der xs Namespace ist notwendig, wenn man typisiert arbeiten will. Er erlaubt das Einbinden von Datentypen nach der XML Schema Spezifikation ↗↗ und somit die bessere Validierung des Stylesheets zur Compile-Zeit.
  • Die Deklaration eines eigenen geprefixten Namespaces erlaubt das Einbinden von eigenen XSLT Funktionen, wie z.B. auch das Einbinden der FunctX Bibliothek ↗↗
  • Der Nicht-geprefixte Namespace ist der Default-Namespace und kann einen Namespace aus der Eingabe behandeln
  • Das Attribut xpath-default-namespace gibt einen weiteren Namespace an, der in XPath Funktionen verwendet werden kann. In diesem Feld würde ich den Namespace einer Konfigurations- oder separaten Datendatei angeben.
Mehr als einen Namespace in der Eingabe sollte man aus meiner Sicht bei der XML Verarbeitung mit XSLT vermeiden - wenn es geht. Ggf. empfiehlt es sich, die Eingabe vor der Verarbeitung zu normalisieren und Elemente ggf. umzubenennen. Ansonsten kann man auch eigene Namespace-Prefixes deklarieren, wie z.B.:
xmlns:ext="https://www.tekturcms.de/external-tools"
und diesen in XPath Selektionen und Match-Regeln verwenden.
GEFAHR!
Befinden sich in den Eingabedaten Namespaces, die man in den XSLT Stylesheets nicht handelt - der Namespace kann auch nur an einem ganz bestimmten Element hängen - so kann es bei der Transformation - ohne Fehlermeldung - zu unerwarteten Ergebnissen kommen.
Deshalb sollte man die Daten im Vorfeld bzgl. Namespaces sehr genau analysieren.
Namespaces in der Eingabe werden also meistens über die Kopfdeklaration in der Stylesheetdatei gehandelt. Welcher Namespace schliesslich in die Ausgabe geschrieben wird, hängt vom aktuell verarbeiteten Kontextknoten ab:
  • Elemente, die man erzeugt, erhalten automatisch den Default-Namespace (wenn man nicht explizit einen Namespace angibt).
  • Elemente, die man kopiert, transportieren den Namespace, den sie in der Eingabe hatten (wenn man dies nicht explizit verhindert).
Um diese beiden Default Einstellungen zu steuern (bzw. zu überschreiben) gibt es mehrere Möglichkeiten:
<xsl:element name="{local-name()}" namespace="{namespace-uri()}">
Hier wird ein Element mit dem un-geprefixten Namespace des Kontextknotens deklariert. Wenn der Kontextknoten keinen anderen Namespace hat, so wird hierdurch sichergestellt, dass der Default-Namespace auch tatsächlich in die Ausgabe kommt.
<xsl:element name="meinelement" namespace="mein-namespace">
Hier wird ein Element mit eigener Namespace Angabe in die Ausgabe geschrieben. Einfacher geschrieben:
<mein-element xmlns="mein-namespace">
Es gibt auch ein Attribut am xsl:copy Element, das den Vorgang des Namespace-Kopierens steuern kann:
<xsl:template match="p">
  <xsl:copy copy-namespaces="no">
     <xsl:apply-templates/>
   </xsl:copy>
</xsl:template>
Hier wird der Namespace am p Element nicht in die Ausgabe geschrieben. Ggf. funktioniert diese Funktion aber mit unerwarteten Ergebnissen, deshalb sollte man sich ohne genauen Test nicht darauf verlassen.
Ebenso kann eine Default-Kopierregel verwendet werden, die es verbietet einen Namespace weiterzuvererben:
<xsl:template match="@* | node()">
   <xsl:copy inherit-namespaces="no">
     <xsl:apply-templates select="@* | node()"/>
   </xsl:copy>
</xsl:template>

3.3.1  Freie Wildbahn

In der freien Wildbahn bin ich erst kürzlich über folgendes Problem gestolpert:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xpath-default-namespace="https://tekturcms.de/schema/x12-xml/1.0"
                exclude-result-prefixes="#all"
                version="3.0">

  <xsl:template match="my-element">
    <neuer-name>
      <xsl:apply-templates>
    </neuer-name>
  </xsl:template>

  [...]
So deklariert würde das neue Element my-element mit einem leeren Namespace in die Ausgabe gesetzt, so <neuer-name xmlns=""/> . Das kann ein nachfolgender Transformationsschritt nicht lesen. Aus diesem Grund setze ich neue Elemente immer mit dem Element-Konstruktor in die Ausgabe, so:
<xsl:template match="my-element">
    <xsl:element name="neuer-name" namespace="{namespace-uri()}">
      <xsl:apply-templates>
    </xsl:element>
  </xsl:template>

3.3.2  Namespaces in XQuery

Während XSLT dazu dienen sollte, XML Daten in andere (XML-) Formate zu transformieren, dient XQuery z.B. dazu auf einer NoSQL Datenbank Daten aus unterschiedlichen Quellen zu selektieren, zu harmonisieren und an verarbeitende Prozesse weiterzugeben.
Deshalb ist es für mich nicht so erstaunlich, dass das Namespace Konzept in XQuery irgendwie besser funktioniert.
Damit man überhaupt Daten auf einem mit Namespaces versehenen XML Dokument selektieren kann, müssen alle Namspaces am Anfang des XQuery Ausdrucks angegeben werden, das sieht so aus:
xquery version "1.0-ml";

import module namespace tektur = "http://www.teturcms.de/xquery/common" 
                                  at "common.xqy";
import module namespace mem = "http://xqdev.com/in-mem-update" 
                                  at '/MarkLogic/appservices/utils/in-mem-update.xqy';
declare namespace local = "https://tekturcms.de/code/alex-sandbox/1.0";
declare namespace weiredns = "https://weired-ns-in-input-data.com/weired/ns";
declare namespace xs = "http://www.w3.org/2001/XMLSchema"; 
Hier werden zuerst Funktionen aus anderen Modulen eingebunden. Diejenigen in einer eigenen Datei common.xqy , sowie aus der Bibliothek mem in der MarkLogic Umgebung. Danach wird ein Namespace local für eigene Funktionen innerhalb der Quelldatei deklariert, sowie der Namespace weiredns , der in den Eingabedaten vorhanden ist. Der Namespace xs ist analog zum XSLT Beispiel gesetzt.
Previous Page Next Page
Version: 93
Jan 25 2021