editoria-basic.xsl 5.64 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xsw="http://coko.foundation/xsweet"
  xpath-default-namespace="http://www.w3.org/1999/xhtml"
  xmlns="http://www.w3.org/1999/xhtml"
  exclude-result-prefixes="#all">

  <!-- Note the default namespace for matching (given above) is
     "http://www.w3.org/1999/xhtml" -->


  <xsl:output method="xml" indent="no" omit-xml-declaration="yes"/>

  <!-- By default (when not matched with a template of higher priority)
       copy any element and its attributes. -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="body">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
      <xsl:for-each-group select="child::div[tokenize(@class,'\s+')=('docx-footnotes','docx-endnotes')]/*" group-by="true()">
        <div id="notes">
          <xsl:apply-templates select="current-group()"/>
        </div>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="key('elements-by-class', 'docx-footnotes') | key('elements-by-class', 'docx-endnotes')"/>
    
  <xsl:template match="div[@id='docx-body'] | key('elements-by-class','docx-body')">
    <container id="main">
      <xsl:apply-templates/>  
    </container>
  </xsl:template>
  
  <xsl:template match="key('elements-by-class', 'docx-footnote') | key('elements-by-class', 'docx-endnote')">
    <note-container id="container-{@id}">
      <xsl:apply-templates/>
    </note-container>
  </xsl:template>
  
  <xsl:template match="key('elements-by-class','FootnoteReference') | key('elements-by-class','EndnoteReference')">
     <xsl:apply-templates/>
  </xsl:template>
  
<!-- matches the 'a' element inside a reference (span) -->
  <xsl:template match="key('elements-by-class','footnoteReference') | key('elements-by-class','endnoteReference')">
    <note data-id="{replace(@href,'^#','')}">
      <xsl:comment> implicit </xsl:comment>    
    </note>
  </xsl:template>

<!-- target element types are -after- mapping of inlines as elsewhere in this XSLT
     i -> em, b -> strong etc. -->
  <xsl:variable as="element()+" name="mapped-styles">
    <em>font-style: italic</em>
    <strong>font-weight: bold</strong>
    <i>text-decoration: underline</i>
  </xsl:variable>
  
  <xsl:template match="p">
    <xsl:variable name="signals" select="xsw:style-propertyValues(.)[.=$mapped-styles]"/>
    <xsl:variable name="me" select="."/>
    <xsl:variable name="mine">
      <xsl:apply-templates/>
    </xsl:variable>
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      
        <xsl:iterate select="$mapped-styles[. = $signals]">
          <xsl:param name="contents" select="$mine"/>
          <xsl:on-completion>
            <xsl:sequence select="$contents"/>
          </xsl:on-completion>
          <xsl:next-iteration>
            <xsl:with-param name="contents">
              <xsl:element name="{name(.)}" namespace="http://www.w3.org/1999/xhtml">
                <xsl:sequence select="$contents"/>
              </xsl:element>
            </xsl:with-param>
          </xsl:next-iteration>
        </xsl:iterate>
    </xsl:copy>
  </xsl:template>
  
  <!-- Any 'i' element becomes an 'em' element; its attributes are copied. -->
  <!-- (Unwanted attributes can be removed in a subsquent step.) -->
  <xsl:template match="i">
    <em>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
    </em>
  </xsl:template>

  <!-- Any 'b' element becomes a 'strong' element; its attributes are copied. -->
  <!-- NB note that inline elements may be modified further or stripped in a subsequent 'reduce' step:
       the story is not over. -->
  <xsl:template match="b">
    <strong>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
    </strong>
  </xsl:template>

  <!-- 'u' becomes 'i' for Editoria.... -->
  <xsl:template match="u">
    <i>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
    </i>
  </xsl:template>

  <!-- Explicit end notes given in source are dropped for Editoria -->
  <xsl:template priority="10" match="span[@class=('footnoteRef','endnoteRef')]"/>
  
  
  <!-- We declare a key that enables us to match elements based on 'class' (attribute) values.
  Any element with a non-ws @class may be so matched (and retrieved).
  Since 'class' may be overloaded this is a many-to-many match, so template
  priority will be important.
  i.e. <p class="Quote Special"> matches with both 'Quote' and 'Special' key values.
  Note the key matches elements of any type (p, h1, span etc.) so no worries about that; only
  as assigned 'class' value (delimited by whitespace) will count. -->
  <xsl:key name="elements-by-class"
    match="*[matches(@class,'\S')]" use="tokenize(@class,'\s+')"/>

  <!-- Calling the key() function, match any element .Quote and emit 'extract', copying attributes.
       Explicit @priority assignments prevent template collisions and let us control
       the order of preference. -->
  <xsl:template match="key('elements-by-class','Quote')" priority="100">
    <extract>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
    </extract>
  </xsl:template>


  <xsl:function name="xsw:style-propertyValues" as="xs:string*">
    <!-- Returns 'font-family: Helvetica','font-size: 10pt' whatever
         properties are defined on @style -->
    <xsl:param name="e" as="element()"/>
    <xsl:sequence select="tokenize($e/@style/normalize-space(.),'\s*;\s*')"/>
  </xsl:function>
  
  <xsl:key name="elements-by-propertyValue" match="*[matches(@style,'\S')]" use="xsw:style-propertyValues(.)"/>
  
</xsl:stylesheet>