Re: type-of() function and data type module
"Dimitre Novatchev" <[email protected]>
| Newsgroups | gmane.text.xml.xslt.extensions |
|---|---|
| Message-ID | <[email protected]> |
A type object must contain information about the following:
1. Type name, such as "xs:decimal"
2. Constructor function that can be invoked (that is a higher order
function) on any value (value tuples) of the type -- see later in this
message an implementation in FXSL.
3. A sequence of "type methods" that can can be invoked (that is higher
order functions) on any value (value tuples) of the type
4. The type this type inherits from -- thus only "its own" type methods
need to be declared, the rest are inherited from the super-type.
All this can be implemented in a programming system that supports higher
order functions (HOF).
At present FXSL implements 1 and 2 for all xml-schema basic types.
FXSL also implements a function, which given two arguments, obtains the
constructor function of the first arg and applies it on the second arg to
construct the first type from it.
Here's an example of performing the transformation:
testFunc-type.xsl
on
numList.xml
==========
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>010</num>
</nums>
The result of the transformation is:
f:apply(f:typeConstructor(11),'03'): 3
f:apply(f:typeConstructor('xxx'),'03'): 03
f:apply(f:typeConstructor(11),'03') gt 4: false
f:type(f:apply(f:typeConstructor(11),'03')): xs:integer
f:type(f:apply(f:typeConstructor('string'), 3)): xs:string
xs:token('abc') :
-1 : xs:integer
xs:negativeInteger(-1) :
xs:nonPositiveInteger(0) :
0 : xs:integer
3 : xs:integer
3. : xs:decimal
3.0E1 : xs:double
xs:float(3) : xs:float
xs:positiveInteger(3) :
'3' : xs:string
(/*/*/text())[1] : 01: xml:node
data((/*/*/text())[1]) : xs:string
Some of the types are not produced, because I only have the Basic Saxon
8.6.1 xslt processor.
For completeness, here's the code of the test transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xdt="http://www.w3.org/2005/04/xpath-datatypes"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="f xs xdt"
>
<xsl:import href="../f/func-type.xsl"/>
<!-- To be applied on ../data/numList.xml -->
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="/">
f:apply(f:typeConstructor(11),'03'): <xsl:value-of
select="f:apply(f:typeConstructor(11),'03')"/>
f:apply(f:typeConstructor('xxx'),'03'): <xsl:value-of
select="f:apply(f:typeConstructor('xxx'),'03')"/>
f:apply(f:typeConstructor(11),'03') gt 4: <xsl:value-of
select="f:apply(f:typeConstructor(11),'03') gt 4"/>
f:type(f:apply(f:typeConstructor(11),'03')): <xsl:value-of
select="f:type(f:apply(f:typeConstructor(11),'03'))"/>
f:type(f:apply(f:typeConstructor('string'), 3)): <xsl:value-of
select="f:type(f:apply(f:typeConstructor('string'),'03'))"/>
<!-- Supported only by a SA Processor -->
xs:token('abc') : <xsl:value-of select="f:type(xs:token('abc'))"
use-when="system-property('xsl:is-schema-aware')='yes'"/>
-1 : <xsl:value-of select="f:type(-1)"/>
<!-- Supported only by a SA Processor -->
xs:negativeInteger(-1) : <xsl:value-of
select="f:type(xs:negativeInteger(-1))"
use-when="system-property('xsl:is-schema-aware')='yes'" />
xs:nonPositiveInteger(0) : <xsl:value-of
select="f:type(xs:nonPositiveInteger(0))"
use-when="system-property('xsl:is-schema-aware')='yes'" />
0 : <xsl:value-of select="f:type(0)"/>
3 : <xsl:value-of select="f:type(3)"/>
3. : <xsl:value-of select="f:type(3.)"/>
3.0E1 : <xsl:value-of select="f:type(3.0E1)"/>
xs:float(3) : <xsl:value-of select="f:type(xs:float(3))"/>
<!-- Supported only by a SA Processor -->
xs:positiveInteger(3) : <xsl:value-of
select="f:type(xs:positiveInteger(3))"
use-when="system-property('xsl:is-schema-aware')='yes'" />
'3' : <xsl:value-of select="f:type('3')"/>
(/*/*/text())[1] : <xsl:value-of select="f:type((/*/*/text())[1])"/>
data((/*/*/text())[1]) : <xsl:value-of
select="f:type(data((/*/*/text())[1]))"/>
</xsl:template>
</xsl:stylesheet>
and here's the code for the functions
f:type()
and
f:typeConstructor(11)
func-type.xsl
=========
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xdt="http://www.w3.org/2005/04/xpath-datatypes"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="f xs xdt"
>
<xsl:import href="../f/func-XpathConstructors.xsl"/>
<xsl:output omit-xml-declaration="yes"/>
<xsl:key name="kConstructor" match="*" use="@t"/>
<xsl:variable name="f:vTypeConstructors">
<f:unsignedByte t="xs:unsignedByte"/>
<f:unsignedShort t="xs:unsignedShort"/>
<f:unsignedInt t="xs:unsignedInt"/>
<f:unsignedLong t="xs:unsignedLong"/>
<f:positiveInteger t="xs:positiveInteger"/>
<f:nonNegativeInteger t="xs:nonNegativeInteger"/>
<f:nonPositiveInteger t="xs:nonPositiveInteger"/>
<f:byte t="xs:byte"/>
<f:short t="xs:short"/>
<f:int t="xs:int"/>
<f:long t="xs:long"/>
<f:integer t="xs:integer"/>
<f:decimal t="xs:decimal"/>
<f:double t="xs:double"/>
<f:float t="xs:float"/>
<f:NMTOKEN t="xs:NMTOKEN"/>
<f:NMTOKENS t="xs:NMTOKENS"/>
<f:ENTITIES t="xs:ENTITIES"/>
<f:ENTITY t="xs:ENTITY"/>
<f:IDREFS t="xs:IDREFS"/>
<f:ID t="xs:ID"/>
<f:NCName t="xs:NCName"/>
<f:Name t="xs:Name"/>
<f:language t="xs:language"/>
<f:token t="xs:token"/>
<f:normalizedString t="xs:normalizedString"/>
<f:boolean t="xs:boolean"/>
<f:duration t="xs:duration"/>
<f:dateTime t="xs:dateTime"/>
<f:time t="xs:time"/>
<f:date t="xs:date"/>
<f:gYearMonth t="xs:gYearMonth"/>
<f:gYear t="xs:gYear"/>
<f:gMonthDay t="xs:gMonthDay"/>
<f:gDay t="xs:gDay"/>
<f:gMonth t="xs:gMonth"/>
<f:base64Binary t="xs:base64Binary"/>
<f:hexBinary t="xs:hexBinary"/>
<f:anyURI t="xs:anyURI"/>
<f:QName t="xs:QName"/>
<f:NOTATION t="xs:NOTATION"/>
<f:string t="xs:string"/>
<f:yearMonthDuration t="xdt:yearMonthDuration"/>
<f:dayTimeDuration t="xdt:dayTimeDuration"/>
</xsl:variable>
<xsl:function name="f:Constructor" as="element()">
<xsl:param name="pTypename" as="xs:string"/>
<xsl:sequence select="key('kConstructor',
$pTypename,$f:vTypeConstructors)"/>
</xsl:function>
<xsl:function name="f:typeConstructor" as="element()">
<xsl:param name="pThis"/>
<xsl:sequence select="key('kConstructor',
f:type($pThis),$f:vTypeConstructors)"/>
</xsl:function>
<xsl:function name="f:type" as="xs:string">
<xsl:param name="pThis"/>
<xsl:choose>
<xsl:when test="$pThis instance of xs:decimal">
<xsl:choose>
<!-- Not supported by a Basic XSLT Processor -->
<xsl:when test="$pThis instance of
xs:unsignedByte">xs:unsignedByte</xsl:when>
<xsl:when test="$pThis instance of
xs:unsignedShort">xs:unsignedShort</xsl:when>
<xsl:when test="$pThis instance of
xs:unsignedInt">xs:unsignedInt</xsl:when>
<xsl:when test="$pThis instance of
xs:unsignedLong">xs:unsignedLong</xsl:when>
<xsl:when test="$pThis instance of
xs:positiveInteger">xs:positiveInteger</xsl:when>
<xsl:when test="$pThis instance of
xs:nonNegativeInteger">xs:nonNegativeInteger</xsl:when>
<xsl:when test="$pThis instance of
xs:negativeInteger">xs:negativeInteger</xsl:when>
<xsl:when test="$pThis instance of
xs:nonPositiveInteger">xs:nonPositiveInteger</xsl:when>
<xsl:when test="$pThis instance of xs:byte">xs:byte</xsl:when>
<xsl:when test="$pThis instance of xs:short">xs:short</xsl:when>
<xsl:when test="$pThis instance of xs:int">xs:int</xsl:when>
<xsl:when test="$pThis instance of xs:long">xs:long</xsl:when>
<!-- End of SA only types -->
<xsl:when test="$pThis instance of
xs:integer">xs:integer</xsl:when>
<xsl:otherwise>xs:decimal</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$pThis instance of xs:double">xs:double</xsl:when>
<xsl:when test="$pThis instance of xs:float">xs:float</xsl:when>
<xsl:when test="$pThis instance of xs:string">
<!-- Not supported by a Basic XSLT Processor -->
<xsl:choose>
<xsl:when test="$pThis instance of
xs:NMTOKEN">xs:NMTOKEN</xsl:when>
<xsl:when use-when="system-property('xsl:is-schema-aware')='yes'"
test="$pThis instance of xs:NMTOKENS">xs:NMTOKENS</xsl:when>
<xsl:when use-when="system-property('xsl:is-schema-aware')='yes'"
test="$pThis instance of xs:ENTITIES">xs:ENTITIES</xsl:when>
<xsl:when use-when="system-property('xsl:is-schema-aware')='yes'"
test="$pThis instance of xs:ENTITY">xs:ENTITY</xsl:when>
<xsl:when use-when="system-property('xsl:is-schema-aware')='yes'"
test="$pThis instance of xs:IDREFS">xs:IDREFS</xsl:when>
<xsl:when test="$pThis instance of xs:IDREF">xs:IDREF</xsl:when>
<xsl:when test="$pThis instance of xs:ID">xs:ID</xsl:when>
<xsl:when test="$pThis instance of xs:NCName">xs:NCName</xsl:when>
<xsl:when test="$pThis instance of xs:Name">xs:Name</xsl:when>
<xsl:when test="$pThis instance of
xs:language">xs:language</xsl:when>
<xsl:when test="$pThis instance of xs:token">xs:token</xsl:when>
<xsl:when test="$pThis instance of
xs:normalizedString">xs:normalizedString</xsl:when>
<xsl:otherwise>xs:string</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$pThis instance of xs:boolean">xs:boolean</xsl:when>
<xsl:when test="$pThis instance of xs:duration">xs:duration</xsl:when>
<xsl:when test="$pThis instance of xs:dateTime">xs:dateTime</xsl:when>
<xsl:when test="$pThis instance of xs:time">xs:time</xsl:when>
<xsl:when test="$pThis instance of xs:date">xs:date</xsl:when>
<xsl:when test="$pThis instance of
xs:gYearMonth">xs:gYearMonth</xsl:when>
<xsl:when test="$pThis instance of xs:gYear">xs:gYear</xsl:when>
<xsl:when test="$pThis instance of
xs:gMonthDay">xs:gMonthDay</xsl:when>
<xsl:when test="$pThis instance of xs:gDay">xs:gDay</xsl:when>
<xsl:when test="$pThis instance of xs:gMonth">xs:gMonth</xsl:when>
<xsl:when test="$pThis instance of
xdt:yearMonthDuration">xdt:yearMonthDuration</xsl:when>
<xsl:when test="$pThis instance of
xdt:dayTimeDuration">xdt:dayTimeDuration</xsl:when>
<xsl:when test="$pThis instance of
xs:base64Binary">xs:base64Binary</xsl:when>
<xsl:when test="$pThis instance of
xs:hexBinary">xs:hexBinary</xsl:when>
<xsl:when test="$pThis instance of xs:anyURI">xs:anyURI</xsl:when>
<xsl:when test="$pThis instance of xs:QName">xs:QName</xsl:when>
<xsl:when test="$pThis instance of xs:NOTATION">xs:NOTATION</xsl:when>
<!--
<xsl:when test="$pThis instance of
xdt:untypedAtomic">xdt:untypedAtomic</xsl:when>
<xsl:otherwise>Unknown xdt:untypedAtomic</xsl:otherwise>
-->
<xsl:when test="$pThis[1] instance of node()">xml:node</xsl:when>
<xsl:otherwise>xs:string</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:stylesheet>
And of course, a constructor function looks like this (extracted from
func-XpathConstructors.xsl):
<f:decimal/>
<xsl:template match="f:decimal" mode="f:FXSL">
<xsl:param name="arg1" as="xdt:anyAtomicType?"/>
<xsl:sequence select="f:decimal($arg1)"/>
</xsl:template>
<xsl:function name="f:decimal" as="node()">
<xsl:sequence select="document('')/*/f:decimal[1]"/>
</xsl:function>
<xsl:function name="f:decimal" as="xs:decimal?">
<xsl:param name="arg1" as="xdt:anyAtomicType?"/>
<xsl:sequence select="xs:decimal($arg1)"/>
</xsl:function>
Cheers,
Dimitre Novatchev
"James Fuller" <[email protected]> wrote in message
news:[email protected]...
> Hello All,
>
> EXSLT already has a facility to determine the type of an object e.g.
> common module object-type(), though what is sorely lacking in XSLT 2.0
> and XSLT 1.0 is the ability
> to do a bit of 'duck typing'; e.g. in the form of a type-of() function
> as initially proposed (i think) by Dimitre Novatchev in May 2005.
>
> http://www.stylusstudio.com/xsllist/200505/post70520.html [1]
>
> a type-of() function would return the type of the 'value' (not the
> object), which can be useful in many scenarios.
>
> So I am going to have a go at defining it though have a few additional
> thoughts; should we contemplate a different module, perhaps related
> specifically to data typing ? If so there maybe some knock on effects
> e.g. we might think about moving object-type() to this.
>
> So now stop reading now if u are sick of datatyping or schemas;
>
> I have for years now toyed with the idea of defining an EXSLT datatype
> module; not because I think I can come up with something better whats on
> offer....more to provide an alternate sandbox/forum for all of us to
> come up with something useful hopefully integrating existing
> specifications such as XML Schema, RELAXNG, NRL, Schematron, etc....
>
> I am more interested in lightweight aspects of data typing e.g. safety
> to a certain degree (think simple validation), documentation...not to
> mention the ease on my brain to immediately know what datatype an
> element or an attribute by perhaps looking at a type attribute (ala XML
> Schema primative datatypes though we could attempt to clean up the mess
> that is anyURI or add scie)..as well as the option to eschew with using
> datatypes if I choose (no strong typing required).
>
> Let me first assert that I am firmly 'on the fence' when it comes to the
> use of weak or strong typing especially when set within overly complex
> schema specifications such as XML Schema. Admittedly inertia and time is
> making XML Schema bearable, though I think I can safely predict that
> there will never be an XML Schema 2.0 and XML Schema 1.1 wont fix what I
> think is broke with it. Perhaps its just something I need to accept and
> just move on.
>
> Schematron approach based on assertions represents to me the most
> 'useful' approach when solving real world problems. Though, it
> highlights a problem with most of the various schema technologies, that
> there is no real thought of how to make an xml instance 'standalone'
> that is I would like to relate assertions and data types in the instance
> xml....use XML Schema primative datatypes u say.....yes these are useful
> (and I use them), though I would like to explicitly link xml instance
> data to an assertion using an attribute.
>
> Other approaches, albeit much simpler (RELAX NG) are still as
> frustratingly incomplete (co-constraints anyone) though this is my
> standard schema technology of choice when performing commercial
> work...it still suffers from low rates of adoption and presence in major
> toolsets.
>
> I think its insane to ignore the obvious benefits with respect to
> documentation and safety obtainable using even primative datatypes, so
> along with having a stab at type-of() I will start something in the
> sandbox for a data-type module;
>
> * come up with a set of simple data types, using XML Schema datatypes as
> a guide...cleaning up things like anyURI along the way, as well as
> adding support for scientific data types. Perhaps we use some DTD
> conventions for cardinality and for defining ranges/lists along the way
> (type:integer="*,1-5" or type:integer="xs:integer".....wild stabs at the
> moment).
>
> * come up with a standard way of linking schema definitions with
> instance xml data, which provides just enough information in the
> instance data for some developer/system to grok the data type (and/or
> follow a reference to look it up) and to assist documentation.
>
> * investigate where things such as Namespace Routing Language is going
> and if there is any place for such high level process control within
> such a module
>
> Ahhh, so something with the depth (and critical thinking) of XML Schema,
> simplicity (brevity and comprehension) of RELAX NG, combined with the
> ability to perform assertions ala Schematron. Sprinkle the facility to
> apply regular expression (XSLT 2.0) checking, add a dash of future
> proofing and process control aka Namespace routing language(NRL) and
> thats something I would use day in, day out for a long time to come.
>
> I am by far no expert in this field; would welcome any corrections to my
> thinking etc...
>
> cheers, Jim Fuller
>
> [1] http://www.stylusstudio.com/xsllist/200505/post70520.html : funnily
> enough Dimitre alludes in this May 2005 email to inactivity (death) of
> EXSLT, which I think can be directly attributed to the fact that we
> (well I for one) was waiting for what form XSLT 2.0 would take...now
> that its current form looks set to remain the same, I think EXSLT can
> now do its thing again.