Bedingte Trennung im XML-Roundtripping

Die meisten typographischen Textzeichen werden von FrameMaker 8 und FrameMaker 9 korrekt nach XML transportiert, zum Beispiel die verschiedenen Leerzeichen (normal, dünn, geschützt, ziffernbreit, en, em). Um allerdings ein Sonderzeichen wie den bedingten Trennstrich erfolgreich nach XML zu schreiben und nach einer angenommenen Verarbeitung durch andere Systeme auch wieder einzulesen, dazu braucht es zusätzliche Maßnahmen.

In den Lese/Schreibregeln benötigen Sie folgende Anweisung:

entity "softhyphen" is fm char "\x04";

Damit das klappt, muss die angegebene Entität auch in der externen DTD spezifiziert sein (hier mit dem dafür zuständigen Unicode-Zeichen):

<!ENTITY softhyphen "&#xAD;">

Jetzt landet jedes mit Strg+Bindestrich eingegebene bedingte Trennzeichen im XML-Code als Entität &softhyphen;.

Wenn Sie aber eine XSL-Verarbeitung vornehmen, bevor die XML-Datei wieder von FrameMaker geöffnet wird, dann wird diese Entität durch ihren in der DTD festgelegten Wert ersetzt, hier also das korrekte Unicode-Zeichen &#xAD;. Nur leider klappt die Umsetzung seitens FrameMaker nun nicht mehr, die Zuordnung zu dem internen Zeichen \x04 fehlt. Dem kann man dann mit einem XSL-Preprocessing nachhelfen, dass alle &#xAD; wieder in &softhyphen; umwandelt und dann greift auch die oben angegebene Lese/Schreibregel wieder. Der relevante XSL-Ausschnitt sieht so aus:

<xsl:template match="text()" name="insert-entities" priority="2">
    <xsl:param name="string" select="." />
    <xsl:variable name="shy" select="'&#xAD;'" />
    <xsl:choose>
        <xsl:when test="not(contains($string , $shy))">
            <xsl:value-of select="$string"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="substring-before($string, $shy)"/>
            <xsl:text disable-output-escaping="yes">&amp;softhyphen;</xsl:text>
            <xsl:call-template name="insert-entities">
                <xsl:with-param name="string" select="substring-after($string, $shy)" />
            </xsl:call-template>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

August 2009, Michael Müller-Hillebrand

Nachtrag 2016, XSLT 2

Die oben genannte Lösung mit eine Template für text() und dem nicht empfohlenen disable-output-escaping="yes" ist eine Konsequenz daraus, dass FrameMaker ursprünglich nur XSLT 1 unterstützt hat.

Mit XSLT 2 kann das wesentlich eleganter gelöst werden. Sie können über eine „character-map“ für jedes Unicode-Zeichen einen beliebigen String für die Ausgabe festlegen:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="2.0">

    <xsl:output use-character-maps="desired-entities"/>

    <xsl:character-map name="desired-entities">
        <xsl:output-character character="&#x00AD;" string="&amp;softhyphen;"/>
        <xsl:output-character character="&#xE005;" string="&amp;suprhy;"/>
        <!-- weitere Einträge -->
    </xsl:character-map>

    <!-- weitere Templates -->

</xsl:stylesheet>

Ein Kommentar

  1. 5.5.2011, 12:15h | Permalink

    Analoge Maßnahmen müssen wohl für das Sonderzeichen Trennunterdrückung getroffen werden, wobei es hier kein Unicode-Zeichen gibt, so dass ich einfach eines aus der Private Use Area (PUA) ausgesucht habe:

    entity "suprhy" is fm char "\x05";

    <!ENTITY suprhy "&#xE005;">