<
xsl:
stylesheet xmlns:xd="
http://www.pnp-software.com/XSLTdoc"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"
xmlns:tei="
http://www.tei-c.org/ns/1.0"
xmlns="
http://www.tei-c.org/ns/1.0"
version="
1.0"
exclude-result-prefixes="
xd tei">
<
xd:
doc type="
stylesheet">
<
xd:
short>
Expands a list of MSDs according to the morphosyntactic specifications.</
xd:
short>
<
xd:
author>
Tomaž Erjavec, <
A href="
http://nl.ijs.si/et/">
http://nl.ijs.si/et/</
A></
xd:
author>
<
xd:
date>
2008-04-15</
xd:
date>
<
xd:
detail>
With TEI P5 MULTEXT-East type morphosyntactic specification as input XML converts a
list of MSDs to various formats and localisations. If xsl:output is set to text, the output is
a tab-separated file, if to xml, the output is a TEI table. </
xd:
detail>
<
xd:
copyright>
This library is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software Foundation;
either version 2.1 of the License, or (at your option) any later version. This library is
distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
General Public License for more details. You should have received a copy of the GNU Lesser
General Public License along with this library; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA </
xd:
copyright>
</
xd:
doc>
<
xd:
doc type="
string">
If xsl:output/@method is xml outputs TEI table,
if to text a tab separated file</
xd:
doc>
<
xsl:
output method="
text" />
<
xd:
doc type="
string">
What to output. Modes should be given as space separated list. id = input
MSD; msd = output MSD; collate = output collation (sort key) of MSD, e.g. 1S120200, hyphen maps
to 00. cat = category (part-of-speech) att = attributes and category val = values attval = pairs
attribute=value brief = decorated values, for readibility, e.g. +animate </
xd:
doc>
<
xsl:
param name="
modes">
verbose</
xsl:
param>
<
xd:
doc type="
string">
Output header row in table? NOT YET!! </
xd:
doc>
<
xsl:
param name="
header">
yes</
xsl:
param>
<
xd:
doc type="
string">
Which cannonical form to produce. Features can be unspecified (have as
their value a hyphen, '-', meaning "non-applicable"), and this parameters determines if and
which such features should be output. Valid values are: none = only features where value is
specified. cat = all features valid for the category full = all features regardless of the
category The effect of this parameter is mode dependent, e.g. hyphens cannot be deleted in the
middle of the output MSD string. </
xd:
doc>
<
xsl:
param name="
canonical">
none</
xsl:
param>
<
xd:
doc type="
string">
Language of input MSDs.</
xd:
doc>
<
xsl:
param name="
lang-in">
en</
xsl:
param>
<
xd:
doc type="
string">
Language of output MSDs.</
xd:
doc>
<
xsl:
param name="
lang-out">
en</
xsl:
param>
<
xd:
doc type="
string">
List of input MSDs, separated by spaces. If parameter is not set, the MSDs
are taken from the specifications. NOT YET!!</
xd:
doc>
<
xsl:
param name="
msds" />
<
xd:
doc type="
string">
Primary separator between input MSD and result.</
xd:
doc>
<
xsl:
variable name="
primary-separator">
<
xsl:
text>
</
xsl:
text>
</
xsl:
variable>
<
xd:
doc type="
string">
Secondary separator between features.</
xd:
doc>
<
xsl:
variable name="
secondary-separator">
<
xsl:
text>
</
xsl:
text>
</
xsl:
variable>
<!---->
<
xd:
doc>
Output expanded MSD list as table. </
xd:
doc>
<
xsl:
template match="
/">
<
xsl:
if test="
not(normalize-space($msds))">
<
xsl:
message terminate="
yes">
Need MSD list! (for now)</
xsl:
message>
</
xsl:
if>
<
table n="
msd-expand {$modes}">
<
xsl:
text>
</
xsl:
text>
<
xsl:
call-template name="
expand-msds">
<
xsl:
with-param name="
msds"
select="
concat(normalize-space($msds),' ')" />
</
xsl:
call-template>
</
table>
</
xsl:
template>
<
xd:
doc>
Split the list of MSDs and process each. <
xd:
param name="
msds"
type="
string">
MSDs to
process.</
xd:
param>
</
xd:
doc>
<
xsl:
template name="
expand-msds">
<
xsl:
param name="
msds" />
<
xsl:
if test="
normalize-space($msds)">
<
row>
<
xsl:
call-template name="
expand-msd">
<
xsl:
with-param name="
msd"
select="
substring-before($msds,' ')" />
<
xsl:
with-param name="
modes"
select="
concat(normalize-space($modes),' ')" />
</
xsl:
call-template>
</
row>
<
xsl:
text>
</
xsl:
text>
<
xsl:
call-template name="
expand-msds">
<
xsl:
with-param name="
msds"
select="
substring-after($msds,' ')" />
</
xsl:
call-template>
</
xsl:
if>
</
xsl:
template>
<
xd:
doc>
Expand one MSD. <
xd:
param name="
msd"
type="
string">
MSD to process.</
xd:
param>
<
xd:
param name="
modes"
type="
string">
Output modes.</
xd:
param>
</
xd:
doc>
<
xsl:
template name="
expand-msd">
<
xsl:
param name="
msd" />
<
xsl:
param name="
modes" />
<
xsl:
if test="
normalize-space($modes)">
<
xsl:
variable name="
mode"
select="
substring-before($modes,' ')" />
<
cell>
<
xsl:
variable name="
result">
<
xsl:
call-template name="
expand-msd-mode">
<
xsl:
with-param name="
msd"
select="
$msd" />
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
call-template>
</
xsl:
variable>
<
xsl:
choose>
<
xsl:
when test="
$mode='msd' or $mode='collate'">
<
xsl:
value-of select="
translate($result,$secondary-separator,'')" />
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
value-of select="
normalize-space($result)" />
</
xsl:
otherwise>
</
xsl:
choose>
</
cell>
<
xsl:
if test="
normalize-space(substring-after($modes,' '))">
<
xsl:
value-of select="
$primary-separator" />
<
xsl:
call-template name="
expand-msd">
<
xsl:
with-param name="
msd"
select="
$msd" />
<
xsl:
with-param name="
modes"
select="
substring-after($modes,' ')" />
</
xsl:
call-template>
</
xsl:
if>
</
xsl:
if>
</
xsl:
template>
<
xd:
doc>
Expand one MSD for given mode <
xd:
param name="
msd"
type="
string">
MSD to process.</
xd:
param>
<
xd:
param name="
mode"
type="
string">
Output mode.</
xd:
param>
</
xd:
doc>
<
xsl:
template name="
expand-msd-mode">
<
xsl:
param name="
msd" />
<
xsl:
param name="
mode" />
<
xsl:
choose>
<
xsl:
when test="
$mode='id'">
<
xsl:
value-of select="
$msd" />
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
variable name="
result">
<
xsl:
call-template name="
expand-feat-mode">
<
xsl:
with-param name="
n">
0</
xsl:
with-param>
<
xsl:
with-param name="
cat"
select="
substring($msd,1,1)" />
<
xsl:
with-param name="
codes"
select="
$msd" />
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
call-template>
</
xsl:
variable>
<
xsl:
choose>
<
xsl:
when test="
$canonical='full'">
<
xsl:
variable name="
atts">
<
xsl:
call-template name="
all-atts" />
</
xsl:
variable>
<
xsl:
variable name="
msd-atts">
<
xsl:
call-template name="
expand-feat-mode">
<
xsl:
with-param name="
n">
0</
xsl:
with-param>
<
xsl:
with-param name="
cat"
select="
substring($msd,1,1)" />
<
xsl:
with-param name="
codes"
select="
$msd" />
<
xsl:
with-param name="
mode">
att</
xsl:
with-param>
</
xsl:
call-template>
</
xsl:
variable>
<
xsl:
value-of select="
substring-before($result,$secondary-separator)" />
<
xsl:
value-of select="
$secondary-separator" />
<
xsl:
call-template name="
canon">
<
xsl:
with-param name="
atts"
select="
$atts" />
<
xsl:
with-param name="
msd-atts"
select="
concat(substring-after(normalize-space($msd-atts),$secondary-separator),$secondary-separator)" />
<
xsl:
with-param name="
result"
select="
concat(substring-after(normalize-space($result),$secondary-separator),$secondary-separator)" />
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
call-template>
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
value-of select="
normalize-space($result)" />
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
template>
<!---->
<
xsl:
template name="
all-atts">
<
xsl:
for-each select="
//tei:table[@n='msd.cat']/ tei:row[@role='attribute']">
<
xsl:
variable name="
att"
select="
tei:cell[@role='name'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
<
xsl:
if test="
not(parent::tei:table/preceding::tei:table[@n='msd.cat']/ tei:row[@role='attribute'] [tei:cell[@role='name'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out] = $att] )">
<
xsl:
value-of select="
$att" />
<
xsl:
value-of select="
$secondary-separator" />
</
xsl:
if>
</
xsl:
for-each>
</
xsl:
template>
<
xsl:
template name="
canon">
<
xsl:
param name="
atts" />
<
xsl:
param name="
msd-atts" />
<
xsl:
param name="
result" />
<
xsl:
param name="
mode" />
<
xsl:
if test="
normalize-space($atts)">
<
xsl:
variable name="
att"
select="
substring-before($atts,$secondary-separator)" />
<
xsl:
choose>
<
xsl:
when test="
contains( concat($secondary-separator,$msd-atts,$secondary-separator), concat($secondary-separator,$att,$secondary-separator))">
<
xsl:
call-template name="
canon-output">
<
xsl:
with-param name="
att"
select="
$att" />
<
xsl:
with-param name="
msd-atts"
select="
$msd-atts" />
<
xsl:
with-param name="
result"
select="
$result" />
</
xsl:
call-template>
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
call-template name="
not-applicable">
<
xsl:
with-param name="
mode"
select="
$mode" />
<
xsl:
with-param name="
att"
select="
$att" />
</
xsl:
call-template>
<
xsl:
value-of select="
$secondary-separator" />
</
xsl:
otherwise>
</
xsl:
choose>
<
xsl:
call-template name="
canon">
<
xsl:
with-param name="
atts"
select="
substring-after($atts,$secondary-separator)" />
<
xsl:
with-param name="
msd-atts"
select="
$msd-atts" />
<
xsl:
with-param name="
result"
select="
$result" />
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
call-template>
</
xsl:
if>
</
xsl:
template>
<
xsl:
template name="
canon-output">
<
xsl:
param name="
att" />
<
xsl:
param name="
msd-atts" />
<
xsl:
param name="
result" />
<
xsl:
if test="
not(normalize-space($msd-atts))">
<
xsl:
text>
Can't find </
xsl:
text>
<
xsl:
value-of select="
$att" />
<
xsl:
text>
attribute in canonical string for </
xsl:
text>
<
xsl:
value-of select="
$msd-atts" />
<
xsl:
text>
in </
xsl:
text>
<
xsl:
value-of select="
$result" />
<
xsl:
message terminate="
yes">
<
xsl:
text>
Can't find </
xsl:
text>
<
xsl:
value-of select="
$att" />
<
xsl:
text>
attribute in canonical string for </
xsl:
text>
<
xsl:
value-of select="
$msd-atts" />
<
xsl:
text>
in </
xsl:
text>
<
xsl:
value-of select="
$result" />
</
xsl:
message>
</
xsl:
if>
<
xsl:
variable name="
msd-att"
select="
substring-before($msd-atts,$secondary-separator)" />
<
xsl:
choose>
<
xsl:
when test="
starts-with($msd-atts,concat($att,$secondary-separator))">
<
xsl:
value-of select="
substring-before($result,$secondary-separator)" />
<
xsl:
value-of select="
$secondary-separator" />
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
call-template name="
canon-output">
<
xsl:
with-param name="
att"
select="
$att" />
<
xsl:
with-param name="
msd-atts"
select="
substring-after($msd-atts,$secondary-separator)" />
<
xsl:
with-param name="
result"
select="
substring-after($result,$secondary-separator)" />
</
xsl:
call-template>
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
template>
<!---->
<
xd:
doc>
Expand one feature for given mode <
xd:
param name="
n"
type="
string">
Position in MSD
string, category=0.</
xd:
param>
<
xd:
param name="
cat"
type="
string">
Category key for table.</
xd:
param>
<
xd:
param name="
codes"
type="
string">
MSD suffix to process.</
xd:
param>
<
xd:
param name="
mode"
type="
string">
Output mode.</
xd:
param>
</
xd:
doc>
<
xsl:
template name="
expand-feat-mode">
<
xsl:
param name="
n" />
<
xsl:
param name="
cat" />
<
xsl:
param name="
codes" />
<
xsl:
param name="
mode" />
<
xsl:
if test="
normalize-space($codes) or (($canonical='cat' or $mode='collate') and //tei:table[@n='msd.cat'] [tei:row[@role='type']/tei:cell[@role='code'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-in]=$cat]/tei:row[@role='attribute']/tei:cell[@role='position']=$n )">
<!---->
<
xsl:
apply-templates mode="
expand"
select="
//tei:table[@n='msd.cat'][tei:row[@role='type']/tei:cell[@role='code'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-in]=$cat]/tei:row[tei:cell[@role='position']=$n]">
<
xsl:
with-param name="
code"
select="
substring($codes,1,1)" />
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
apply-templates>
<
xsl:
call-template name="
expand-feat-mode">
<
xsl:
with-param name="
n"
select="
$n+1" />
<
xsl:
with-param name="
cat"
select="
$cat" />
<
xsl:
with-param name="
codes"
select="
substring($codes,2)" />
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
call-template>
</
xsl:
if>
</
xsl:
template>
<
xd:
doc>
Expand category value.
<
xd:
param name="
code"
type="
string">
Category code to process.</
xd:
param>
<
xd:
param name="
mode"
type="
string">
Output mode.</
xd:
param>
</
xd:
doc>
<
xsl:
template mode="
expand"
match="
tei:row[@role='type']">
<
xsl:
param name="
code" />
<
xsl:
param name="
mode" />
<
xsl:
choose>
<
xsl:
when test="
$mode='msd'">
<
xsl:
value-of select="
tei:cell[@role='code'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
</
xsl:
when>
<
xsl:
when test="
$mode='collate'">
<
xsl:
apply-templates mode="
position"
select="
//tei:table[@n='msd.cat']">
<
xsl:
with-param name="
code"
select="
$code" />
</
xsl:
apply-templates>
<
xsl:
value-of select="
tei:cell[@role='code'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
value-of select="
tei:cell[@role='name'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
</
xsl:
otherwise>
</
xsl:
choose>
<
xsl:
value-of select="
$secondary-separator" />
</
xsl:
template>
<
xd:
doc>
Expand one feature.
<
xd:
param name="
code"
type="
string">
Value code to process.</
xd:
param>
<
xd:
param name="
mode"
type="
string">
Output mode.</
xd:
param>
</
xd:
doc>
<
xsl:
template mode="
expand"
match="
tei:row[@role='attribute']">
<
xsl:
param name="
code" />
<
xsl:
param name="
mode" />
<
xsl:
choose>
<
xsl:
when test="
not(normalize-space($code))">
<
xsl:
if test="
$canonical='cat' or $canonical='full' or $mode='collate'">
<
xsl:
call-template name="
expand">
<
xsl:
with-param name="
code">
-</
xsl:
with-param>
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
call-template>
</
xsl:
if>
</
xsl:
when>
<
xsl:
when test="
$code = '-'">
<
xsl:
if test="
$canonical='cat' or $canonical='full' or $mode='collate' or $mode='msd'">
<
xsl:
call-template name="
expand">
<
xsl:
with-param name="
code">
-</
xsl:
with-param>
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
call-template>
</
xsl:
if>
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
call-template name="
expand">
<
xsl:
with-param name="
code"
select="
$code" />
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
call-template>
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
template>
<
xsl:
template name="
expand">
<
xsl:
param name="
code" />
<
xsl:
param name="
mode" />
<
xsl:
choose>
<
xsl:
when test="
$code = '-'">
<
xsl:
call-template name="
not-applicable">
<
xsl:
with-param name="
mode"
select="
$mode" />
<
xsl:
with-param name="
att"
select="
tei:cell[@role='name'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
</
xsl:
call-template>
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
if test="
$mode='att' or $mode='attval'">
<
xsl:
value-of select="
tei:cell[@role='name'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
</
xsl:
if>
<
xsl:
if test="
$mode='attval'">
<
xsl:
text>
=</
xsl:
text>
</
xsl:
if>
<
xsl:
if test="
$mode='msd' or $mode='collate' or $mode='val' or $mode='attval' or $mode='brief'">
<
xsl:
apply-templates mode="
expand"
select="
tei:cell/tei:table/tei:row[@role='value']">
<
xsl:
with-param name="
code"
select="
$code" />
<
xsl:
with-param name="
mode"
select="
$mode" />
</
xsl:
apply-templates>
</
xsl:
if>
</
xsl:
otherwise>
</
xsl:
choose>
<
xsl:
value-of select="
$secondary-separator" />
</
xsl:
template>
<
xsl:
template name="
not-applicable">
<
xsl:
param name="
mode" />
<
xsl:
param name="
att" />
<
xsl:
if test="
$mode='msd'">
<
xsl:
text>
-</
xsl:
text>
</
xsl:
if>
<
xsl:
if test="
$mode='collate'">
<
xsl:
text>
00</
xsl:
text>
</
xsl:
if>
<
xsl:
if test="
$mode='brief'">
<
xsl:
text>
0</
xsl:
text>
</
xsl:
if>
<
xsl:
if test="
$mode='att' or $mode='attval' or $mode='brief'">
<
xsl:
value-of select="
$att" />
</
xsl:
if>
<
xsl:
if test="
$mode='attval'">
<
xsl:
text>
=</
xsl:
text>
</
xsl:
if>
<
xsl:
if test="
$mode='val' or $mode='attval'">
<
xsl:
text>
0</
xsl:
text>
</
xsl:
if>
</
xsl:
template>
<
xd:
doc>
Expand attribute value. <
xd:
param name="
code"
type="
string">
Code to process.</
xd:
param>
<
xd:
param name="
mode"
type="
string">
Output mode.</
xd:
param>
</
xd:
doc>
<
xsl:
template mode="
expand"
match="
tei:row[@role='value']">
<
xsl:
param name="
code" />
<
xsl:
param name="
mode" />
<
xsl:
if test="
tei:cell[@role='code'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-in] = $code">
<
xsl:
choose>
<
xsl:
when test="
$mode='msd'">
<
xsl:
value-of select="
tei:cell[@role='code'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
</
xsl:
when>
<
xsl:
when test="
$mode='collate'">
<
xsl:
apply-templates mode="
position"
select="
parent::tei:table/tei:row[@role='value']">
<
xsl:
with-param name="
code"
select="
$code" />
</
xsl:
apply-templates>
</
xsl:
when>
<
xsl:
when test="
$mode='val' or $mode='attval'">
<
xsl:
value-of select="
tei:cell[@role='name'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
</
xsl:
when>
<
xsl:
when test="
$mode='brief'">
<
xsl:
variable name="
binary"
select="
tei:cell[@role='name'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang='en']" />
<
xsl:
choose>
<
xsl:
when test="
$binary = 'no' or $binary = 'yes'">
<
xsl:
if test="
$binary = 'no'">
-</
xsl:
if>
<
xsl:
if test="
$binary = 'yes'">
+</
xsl:
if>
<
xsl:
value-of select="
ancestor::tei:row[@role='attribute']/ tei:cell[@role='name'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
</
xsl:
when>
<
xsl:
otherwise>
<
xsl:
value-of select="
tei:cell[@role='name'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-out]" />
</
xsl:
otherwise>
</
xsl:
choose>
</
xsl:
when>
</
xsl:
choose>
<
xsl:
value-of select="
$secondary-separator" />
</
xsl:
if>
</
xsl:
template>
<!---->
<
xsl:
template mode="
position"
match="
tei:table[@n='msd.cat']">
<
xsl:
param name="
code" />
<
xsl:
if test="
tei:row[@role='type']/tei:cell[@role='code'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-in]=$code">
<
xsl:
number value="
position()"
format="
01" />
</
xsl:
if>
</
xsl:
template>
<!---->
<
xsl:
template mode="
position"
match="
tei:row">
<
xsl:
param name="
code" />
<
xsl:
if test="
tei:cell[@role='code'][ancestor-or-self::tei:*[@xml:lang][1]/@xml:lang=$lang-in]=$code">
<
xsl:
number value="
position()"
format="
01" />
</
xsl:
if>
</
xsl:
template>
</
xsl:
stylesheet>
v