<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/pool/xslt_ht.xslt" type="application/xml"?>
<xsl:stylesheet
  xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
  xmlns:xi = "http://www.w3.org/2003/XInclude"
  xmlns:d = "http://herbaer.de/xmlns/20051201/doc"
  xmlns:tm = "http://herbaer.de/xmlns/20130628/transformation_attributes"
  xmlns:li = "http://herbaer.de/xmlns/20141210/localization"
  xmlns:h = "http://herbaer.de/xmlns/20121015/hash"
  exclude-result-prefixes = "d li h"
  version = "1.0"
>
<d:info xmlns="http://herbaer.de/xmlns/20051201/doc">
  <title>styleincl_step_1.xslt</title>
  <subtitle>XInclude - Elemente für CSS- und Javascript-Verweise einsetzen</subtitle>
  <date>2013-06-27</date>
  <author>
    <personname>
      <firstname>Herbert</firstname>
      <surname>Schiemann</surname>
    </personname>
    <email>h.schiemann@herbaer.de</email>
  </author>
</d:info>

<d:section xmlns="http://herbaer.de/xmlns/20051201/doc" role="stylesheet">
<para>
Die Zahl der Requests kann veringert werden,
indem CSS-Regeln und Javascript direkt in die Transformtion eingebunden werden.
</para>
<section>
  <title>Script einfügen</title>
  <para>
An der Stelle von Elementen der Form
  </para>
  <programlisting>
  &lt;xsl:element name = "script"&gt;
    &lt;xsl:attribute name = "src"&gt;
      &lt;xsl:value-of select = "concat ($p_styleprefix, 'common.js')"/&gt;
    &lt;/xsl:attribute&gt;
  &lt;/xsl:element&gt;</programlisting>
  <para>
soll eingefügt werden:
  </para>
  <programlisting>
  &lt;xsl:element name = "script"&gt;
    &lt;xsl:text&gt;&lt;xi:include href = "tmpmin/common.js" parse = "text" encoding = "utf-8"
    /&gt;&lt;/xsl:text&gt;
  &lt;/xsl:element&gt;</programlisting>
</section>
<section>
  <title>CSS-Regeln einfügen</title>
  <para>
An der Stelle von Elementen der Form
  </para>
  <programlisting>
  &lt;xsl:element name = "link"&gt;
    &lt;xsl:attribute name = "href"&gt;
      &lt;xsl:value-of select = "concat ($p_styleprefix, 'ixdesk.css')"/&gt;
    &lt;/xsl:attribute&gt;
    &lt;xsl:attribute name = "rel"&gt;stylesheet&lt;/xsl:attribute&gt;
  &lt;/xsl:element&gt;</programlisting>
  <para>
soll eingefügt werden:
  </para>
  <programlisting>
  &lt;xsl:element name = "style"&gt;
    &lt;xsl:text tm:placeholder="imageprefix"&gt;&lt;xi:include
      href = "tmpmin/ixdesk.css" parse = "text" encoding = "utf-8"
    /&gt;&lt;/xsl:text&gt;
  &lt;/xsl:element&gt;</programlisting>
</section>
<section>
  <title>Platzhalter für Text</title>
  <para>
Platzhalter für Text werden durch XSLT-Elemente ersetzt,
die den Text einsetzen.
  </para>
</section>
</d:section><!-- role = 'stylesheet' -->

<d:para>Vorlagen für einfachen Text</d:para>
<xsl:include href="/pool/txt.xslt"/>

<d:para>Vorlagen für Listen</d:para>
<xsl:include href="/pool/list.xslt"/>

<d:para>
Komma-getrennte Liste der Namen der Dateien,
die nicht mit <d:tag class="element">xi:include</d:tag> eingebunden werden sollen
</d:para>
<xsl:param name="p_exclude" select="'common.js'"/>

<d:para>Präfix des Pfades von temporären JavaScript- und CSS-Dateien</d:para>
<xsl:param name="p_tmpprefix" select="'tmpmin/'"/>

<d:para>
Pfad des XML-Dokuments mit den kurzen IDs der Platzhalter
</d:para>
<xsl:param name="p_shortids" select="concat ($p_tmpprefix, 'shortids.xml')"/>

<d:para>
Das Wurzelelement der kurzen ID-Werte
</d:para>
<xsl:variable name="g_shortids" select="document ($p_shortids)/h:hash"/>

<xsl:output indent="yes"/>

<d:para>
Die Zeichenkette zwischen den letzten beiden einfachen Anführungszeichen:
Die Eingabe <d:literal>concat ($p_styleprefix, 'ixdesk.css')</d:literal>
ergibt <d:literal>ixdesk.css</d:literal>
</d:para>
<xsl:template name="last_literal">
  <!-- Die Eingabe-Zeichenkette -->
  <xsl:param name="txt" select="."/>
  <!-- Das Anführungszeichen -->
  <xsl:param name="quoter" select="&quot;'&quot;"/>
  <xsl:choose>
    <xsl:when test="not (contains ($txt, $quoter))"/>
    <xsl:otherwise>
      <xsl:variable name="after" select="substring-after ($txt, $quoter)"/>
      <xsl:choose>
        <xsl:when test="not (contains ($after, $quoter))">
          <xsl:value-of select="substring-before ($txt, $quoter)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="last_literal">
            <xsl:with-param name="txt" select="$after"/>
            <xsl:with-param name="quoter" select="$quoter"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<d:para>
Die Wurzel
</d:para>
<xsl:template match="/">
  <xsl:apply-templates select="processing-instruction() | *"/>
</xsl:template>

<d:para>
Verarbeitungsanweisungen auf Wurzel-Ebene werden kopiert.
</d:para>
<xsl:template match="processing-instruction()">
  <xsl:copy-of select="."/>
</xsl:template>

<d:para>
Elemente werden kopiert.
</d:para>
<xsl:template match="*">
  <xsl:copy>
    <xsl:apply-templates select="*|@*|text()"/>
  </xsl:copy>
</xsl:template>

<d:para>
Attribute werden kopiert.
</d:para>
<xsl:template match="@*">
  <xsl:copy-of select="."/>
</xsl:template>

<d:para>Vorlage für ein Script-Element</d:para>
<xsl:template match="xsl:element[@name = 'script' and xsl:attribute[@name = 'src']]">
  <xsl:variable name="scriptname">
    <xsl:apply-templates select="xsl:attribute [@name = 'src']" mode="scriptname"/>
  </xsl:variable>
  <xsl:choose>
    <xsl:when test="string-length ($scriptname) = 0">
      <xsl:copy-of select="."/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:apply-templates select="xsl:attribute [not (@name = 'src')]"/>
        <xsl:call-template name="include">
          <xsl:with-param name="scriptname" select="$scriptname"/>
        </xsl:call-template>
      </xsl:copy>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<d:para>
Der Name einer Script-Datei (Javascript, CSS),
die aber nicht in der Liste $p_exclude enthalten ist.
</d:para>
<xsl:template match="xsl:attribute" mode="scriptname">
  <!-- der Name der Datei -->
  <xsl:variable name="script">
    <xsl:call-template name="txt.filename">
      <xsl:with-param name="txt">
        <xsl:choose>
          <xsl:when test="xsl:value-of">
            <!-- select = "concat ($p_styleprefix, 'ixdesk.css')" -->
            <xsl:call-template name="last_literal">
              <xsl:with-param name="txt" select="xsl:value-of[last()]/@select"/>
            </xsl:call-template>
          </xsl:when>
          <xsl:when test="xsl:text">
            <xsl:for-each select="xsl:text">
              <xsl:value-of select="."/>
            </xsl:for-each>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="text()"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="exclude">
    <xsl:call-template name="list.entry_by_key">
      <xsl:with-param name="list" select="$p_exclude"/>
      <xsl:with-param name="key" select="$script"/>
      <xsl:with-param name="sep" select="','"/>
    </xsl:call-template>
  </xsl:variable>
  <xsl:choose>
    <xsl:when test="string-length ($exclude) &gt; 0"/>
    <xsl:otherwise>
      <xsl:value-of select="$script"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<d:para>
Fügt ein xsl:text-Element mit einem xi:include-Element ein,
um eine Scriptdatei einzubinden.
</d:para>
<xsl:template name="include">
  <!-- Name der Scriptdatei -->
  <xsl:param name="scriptname"/>
  <!-- Name eines Platzhalters, optional -->
  <xsl:param name="placeholder"/>
  <xsl:element name="xsl:text">
    <xsl:if test="string-length ($placeholder) &gt; 0">
      <xsl:attribute name="tm:placeholder">
        <xsl:value-of select="$placeholder"/>
      </xsl:attribute>
    </xsl:if>
    <!--
        <xi:include href = "tmpmin/common.js" parse = "text" encoding = "utf-8"/>
    -->
    <xsl:element name="xi:include">
      <xsl:attribute name="href">
        <xsl:value-of select="concat ($p_tmpprefix, $scriptname)"/>
      </xsl:attribute>
      <xsl:attribute name="parse">text</xsl:attribute>
      <xsl:attribute name="encoding">utf-8</xsl:attribute>
    </xsl:element>
  </xsl:element>
</xsl:template>

<d:para>
Vorlage für einen Stylesheet-Verweis
</d:para>
<xsl:template match="xsl:element [@name = 'link' and xsl:attribute [@name = 'rel'] = 'stylesheet']"
>
  <xsl:variable name="scriptname">
    <xsl:apply-templates select="xsl:attribute [@name = 'href']" mode="scriptname"/>
  </xsl:variable>
  <xsl:choose>
    <xsl:when test="string-length ($scriptname) = 0">
      <xsl:copy-of select="."/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:element name="xsl:element">
        <xsl:attribute name="name">style</xsl:attribute>
        <xsl:apply-templates select="xsl:attribute [@name = 'media']"/>
        <xsl:call-template name="include">
          <xsl:with-param name="scriptname" select="$scriptname"/>
          <xsl:with-param name="placeholder" select="'imageprefix'"/>
        </xsl:call-template>
      </xsl:element>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<d:section xmlns="http://herbaer.de/xmlns/20051201/doc">
<para>
Platzhalter für Text (in verschiedenen Sprachen) werden trickreich behandelt.
Wo ein Platzhalter <tag class="element">l:ph</tag> erscheint,
muss die Variable <varname>g_l</varname> (Wurzelelement der Lokalisierungsdatei)
definiert sein. Normalerweise ist es eine Top-Level-Variable,
aber es kann auch nötig sein, die Variable lokal zu deefinieren,
wenn nämlich die Sprache auf der obersten Ebene nicht feststeht.
Deswegen prüft diese Transformation, ob überhaupt irgendwo
eine Variable <varname>g_l</varname> existiert.
Wenn nicht, wird eine Top-Level-Variable eingefügt,
deren Wert das Wurzelelement der Lokalisierungsdatei ist.
</para>
<para>
Für die Lokalisierungsdaten und Platzhalter für Texte sollten im Idealfall
verschiedene Namensräume benutzt werden.
Wenn das Wurzelelement der Quelle einen Namensraumknoten für die Platzhalter enthält,
dann sollte das Wurzelelement der Ausgabe
einen Namensraumknoten für die Lokalisierungsdaten enthalten.
Da Namensraumknoten mittels XSTL umständlich zu handhaben sind,
benutze ich hier ein anderes Namensraumpräfix <literal>li</literal> (für Platzhalter),
das in der Ausgabe nicht erscheinen soll.
</para>
</d:section>
<xsl:template match="xsl:stylesheet">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:if test="//li:ph and not (//xsl:variable [@name = 'g_l'])">
      <xsl:if test="not (xsl:variable [@name = 'g_lang'])">
        <xsl:element name="xsl:variable">
          <xsl:attribute name="name">g_lang</xsl:attribute>
          <xsl:element name="xsl:variable">
            <xsl:attribute name="name">l</xsl:attribute>
            <xsl:attribute name="select">/*/@xml:lang</xsl:attribute>
          </xsl:element>
          <xsl:element name="xsl:choose">
            <xsl:element name="xsl:when">
              <xsl:attribute name="test">contains($l, '-')</xsl:attribute>
              <xsl:element name="xsl:value-of">
                <xsl:attribute name="select">substring-before ($l, '-')</xsl:attribute>
              </xsl:element>
            </xsl:element>
            <xsl:element name="xsl:otherwise">
              <xsl:element name="xsl:value-of">
                <xsl:attribute name="select">$l</xsl:attribute>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:element>
      </xsl:if>
      <xsl:element name="xsl:variable">
        <xsl:attribute name="name">g_l</xsl:attribute>
        <xsl:attribute name="select">
          <xsl:text>document(concat('/local/local.xml.', $g_lang))</xsl:text>
          <xsl:text>/l:localization</xsl:text>
        </xsl:attribute>
      </xsl:element>
    </xsl:if>
    <xsl:apply-templates select="*"/>
  </xsl:copy>
</xsl:template>

<d:para>
Platzhalter für Texte
</d:para>
<xsl:template match="li:ph">
  <xsl:variable name="id" select="@id"/>
  <xsl:element name="xsl:value-of">
    <xsl:attribute name="select">
      <xsl:text>$g_l/l:t[@id='</xsl:text>
      <xsl:choose>
        <xsl:when test="$p_shortids = 'none'">
          <xsl:value-of select="$id"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$g_shortids/h:value[@key = $id]"/>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text>']</xsl:text>
    </xsl:attribute>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>
