map: Add transformation support

* src/current/compiler/map.xsl
  (lvmc:get-method-func, lvmc:value-ref, lvmc:transformation-wrap): New
    functions, partyl extracted from below.
  (lvmc:compile)[lvm:map//lvm:from]: Use `lvmc:value-ref'.
    [lvm:map//lvm:from/lvm:translate]: Add `[@key]' to match.
    [lvm:map//lvm:transform]: New match.  Ignore node entirely.
  (lvmc:concat-compile): Propagate symtable to `lvmc:compile'.
master
Mike Gerwitz 2018-05-29 10:53:48 -04:00
parent 2a9196d940
commit 3f7e1fc9b8
1 changed files with 112 additions and 20 deletions

View File

@ -2,7 +2,7 @@
<!--
Compiles map fragments to produce a map from source data to a destination
Copyright (C) 2016 R-T Specialty, LLC.
Copyright (C) 2016, 2018 R-T Specialty, LLC.
This file is part of TAME.
@ -270,6 +270,36 @@
</template>
<!--
Get name of function associated with mapping method
Note that this expands to an empty string if no processing is
needed. Since functions are applied using parenthesis, this has the
effect of creating either a function application or a parenthesized
expression, the latter of which simply returns the expression untouched.
-->
<function name="lvmc:get-method-func" as="xs:string">
<param name="method" as="xs:string?" />
<choose>
<!-- default -->
<when test="not( $method ) or ( $method = 'translate' )">
<sequence select="''" />
</when>
<when test="$method = ( 'hash', 'uppercase' )">
<sequence select="concat( 'map_method_', $method )" />
</when>
<otherwise>
<message terminate="yes"
select="concat( 'error: unknown map method `',
$method, '''' )" />
</otherwise>
</choose>
</function>
<!--
Directly map an input to the output
-->
@ -752,27 +782,71 @@
<template match="lvm:map//lvm:from" mode="lvmc:compile" priority="2">
<variable name="nested" as="xs:boolean"
select="exists( ancestor::lvm:from )" />
<text>input['</text>
<value-of select="@name" />
<text>']</text>
<choose>
<when test="@index">
<text>[</text>
<value-of select="@index" />
<text>]</text>
</when>
<when test="$nested">
<text>[curindex]</text>
</when>
</choose>
<sequence select="lvmc:value-ref( . )" />
</template>
<function name="lvmc:value-ref" as="xs:string">
<param name="from" as="element( lvm:from )" />
<variable name="nested" as="xs:boolean"
select="exists( $from/ancestor::lvm:from )" />
<variable name="name" as="xs:string"
select="$from/@name" />
<variable name="index" as="xs:string?"
select="$from/@index" />
<!-- index reference, if applicable -->
<variable name="index-ref" as="xs:string"
select="if ( $index ) then
concat( '[', $index, ']' )
else
''" />
<!-- additional index, if nested within another from -->
<variable name="nested-ref" as="xs:string"
select="if ( $nested ) then
'[curindex]'
else
''" />
<!-- compiled reference, including index and nested -->
<variable name="ref" as="xs:string"
select="concat(
'input[''', $name, ''']', $index-ref, $nested-ref )" />
<!-- finally, wrap in any transformations -->
<sequence select="lvmc:transformation-wrap(
$ref, $from/ancestor::lvm:transform )" />
</function>
<function name="lvmc:transformation-wrap" as="xs:string">
<param name="value" as="xs:string" />
<param name="transform" as="element( lvm:transform )*" />
<!-- transformations (if any) as function applications -->
<variable name="transform-methods" as="xs:string*"
select="for $method in $transform/@method
return concat(
lvmc:get-method-func( $method ),
'(' )" />
<!-- closing parenthesis for each -->
<variable name="transform-close" as="xs:string*"
select="for $_ in $transform-methods
return ')'" />
<!-- wrap $ref in methods and closing parentheses -->
<sequence select="concat(
string-join( $transform-methods, '' ),
$value,
string-join( $transform-close, '' ) )" />
</function>
<template match="lvm:from/lvm:default"
mode="lvmc:compile" priority="5">
<param name="symtable" as="element( preproc:symtable )"
@ -794,7 +868,11 @@
</template>
<template match="lvm:map//lvm:from/lvm:translate" mode="lvmc:compile" priority="5">
<!--
Key/value mapping
-->
<template mode="lvmc:compile" priority="5"
match="lvm:map//lvm:from/lvm:translate[ @key ]">
<param name="type" as="xs:string" />
<text>case '</text>
@ -807,6 +885,18 @@
</template>
<!--
Skip transformations during initial encounter
Transformations are applied within certain contexts; let those contexts
apply them when ready.
-->
<template mode="lvmc:compile" priority="3"
match="lvm:map//lvm:transform">
<apply-templates mode="lvmc:compile" />
</template>
<template match="lvm:translate[ element() ]"
mode="lvmc:compile-translate" priority="5">
<param name="symtable" as="element( preproc:symtable )"
@ -838,6 +928,8 @@
<apply-templates mode="lvmc:compile" select=".">
<with-param name="type" select="$type" />
<with-param name="symtable" select="$symtable"
tunnel="yes"/>
</apply-templates>
</for-each>
<text>;</text>