Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1550 Replace node-kind() with new type-of() function #1570

Merged
merged 4 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 152 additions & 1 deletion specifications/xpath-functions-40/src/function-catalog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,157 @@ $node ! (
</fos:changes>
</fos:function>

<fos:function name="type-of" prefix="fn">
<fos:signatures>
<fos:proto name="type-of" return-type="xs:string">
<fos:arg name="value" type="item()*" usage="inspection"/>
</fos:proto>
</fos:signatures>
<fos:properties>
<fos:property>deterministic</fos:property>
<fos:property>context-independent</fos:property>
<fos:property>focus-independent</fos:property>
</fos:properties>
<fos:summary>
<p>Returns information about the type of a value, as a string.</p>
</fos:summary>
<fos:rules>
<p>The function returns a string, whose lexical form will always match
the grammar of <xnt spec="XP40" ref="SequenceType">SequenceType</xnt>, representing a sequence type that matches
<code>$value</code>.</p>
<p>If <code>$value</code> is the empty sequence, the function returns the string <code>"empty-sequence()"</code>.</p>
<p>Otherwise, the returned string is the concatenation of:</p>
<olist>
<item><p>A string representing the distinct item types that are present in <code>$value</code>,
formed as follows:</p>
<olist>
<item><p>For each item in <code>$value</code>, construct a string representing its item type
as described below.</p></item>
<item><p>Eliminate duplicate strings from this list by applying the <code>fn:distinct-values</code>
function, forming a sequence of strings <var>$ss</var>.</p></item>
<item><p>If <var>$ss</var> contains only one string, use that string.</p></item>
<item><p>Otherwise, return the result of the expression <code>`({fn:string-join(<var>$ss</var>, "|")})`</code>.</p></item>
</olist>
</item>
<item><p>An occurrence indicator: absent if <code>$value</code> contains exactly one item, or
<code>"+"</code> if it contains more than one item.</p></item>
</olist>
<p>The string representing the type of an individual item <var>J</var> is constructed as follows:</p>
<olist>
<item><p>If <var>J</var> is a node, the result is one of the following
strings, determined by the node kind of the node (see <xspecref spec="DM40" ref="dm-node-kind"/>):</p>
<p><slist>
<sitem><code>"document-node()"</code></sitem>
<sitem><code>"element()"</code></sitem>
<sitem><code>"attribute()"</code></sitem>
<sitem><code>"text()"</code></sitem>
<sitem><code>"processing-instruction()"</code></sitem>
<sitem><code>"comment()"</code></sitem>
<sitem><code>"namespace-node()"</code></sitem>
</slist></p>
</item>
<item>
<p>If <var>J</var> is an atomic item, the result is a string chosen as follows:</p>
<olist>
<item><p>Let <var>T</var> be the type denoted by the type annotation of <var>J</var>.</p></item>
<item><p>If <var>T</var> is an anonymous type, set <var>T</var> to the base type of <var>T</var>, and
repeat until a type is reached that is not anonymous.</p></item>
<item><p>If the name of <var>T</var> is in the namespace <code>http://www.w3.org/2001/XMLSchema</code>,
return the string <code>"xs:<var>local</var>"</code> where <var>local</var> is the local part of the
name of <var>T</var>.</p></item>
<item><p>Otherwise, return the name of <var>T</var> in the form of a
<xnt spec="XP40" ref="URIQualifiedName">URIQualifiedName</xnt> (that is, <code>"Q{<var>uri</var>}<var>local</var>"</code>,
or <code>"Q{}<var>local</var>"</code> if the name is in no namespace).</p></item>
</olist>
</item>
<item><p>If <var>J</var> is a function item:</p>
<olist>
<item><p>If <var>J</var> is an array, return <code>"array(*)"</code>.</p></item>
<item><p>If <var>J</var> is a map, return <code>"map(*)"</code>.</p></item>
<item><p>Otherwise, return <code>"function(*)"</code>.</p></item>
</olist>
</item>
</olist>
</fos:rules>

<fos:errors>
<p>If the <code>$value</code> argument is omitted and the context value is <xtermref ref="dt-absent" spec="DM40"
>absent</xtermref>, the function raises
type error <xerrorref spec="XP"
class="DY" code="0002" type="type"/>.</p>

</fos:errors>
<fos:notes>
<p>In general, an item matches more than one type, and there are cases where there is no single matching type that
is more specific than all the others. This is especially true with functions, maps, and arrays. This function therefore
selects one of the types that matches the item, which is not necessarily the most specific type.</p>

<p>This function should not be used as a substitute for an <code>instance of</code> test. The precise type annotation
of the result of an expression is not always predictable, because processors are free to deliver a more specific type
than is mandated by the specification. For example, if <code>$n</code> is of type <code>xs:positiveInteger</code>,
then the result of <code>abs($n)</code> is guaranteed to be an instance of <code>xs:integer</code>, but an
implementation might reasonably return the supplied value unchanged: that is, a value whose actual type
annotation is <code>xs:positiveInteger</code>. Similarly the type annotation of the value returned by
<code>position()</code> might be <code>xs:long</code> rather than <code>xs:integer</code>.</p>

<p>Implementations <rfc2119>should</rfc2119>, however, refrain from exposing types that are purely internal.
For example, an implementation might have an optimized internal representation for strings consisting entirely
of ASCII characters, or for single-character strings; if this is the case then the type annotation returned by this function
should be a user-visible supertype such as <code>xs:string</code>.</p>
</fos:notes>

<fos:examples>
<fos:variable name="e" id="v-type-of-e"><![CDATA[<doc>
<p id="alpha" xml:id="beta">One</p>
<p id="gamma" xmlns="http://example.com/ns">Two</p>
<ex:p id="delta" xmlns:ex="http://example.com/ns">Three</ex:p>
<?pi 3.14159?>
</doc>]]>
</fos:variable>
<fos:example>
<fos:test use="v-type-of-e" spec="XQuery">
<fos:expression>type-of($e//*[@id = 'alpha'])</fos:expression>
<fos:result>"element()"</fos:result>
</fos:test>
<fos:test use="v-type-of-e" spec="XQuery">
<fos:expression>type-of($e//*)</fos:expression>
<fos:result>"element()+"</fos:result>
</fos:test>
<fos:test use="v-type-of-e" spec="XQuery">
<fos:expression>type-of($e//@id[. = 'gamma'])</fos:expression>
<fos:result>"attribute()"</fos:result>
</fos:test>
<fos:test use="v-type-of-e" spec="XQuery">
<fos:expression>type-of($e//node()[.='3.14159'])</fos:expression>
<fos:result>"processing-instruction()"</fos:result>
</fos:test>
<fos:test use="v-type-of-e" spec="XQuery">
<fos:expression>type-of($e//no-such-node)</fos:expression>
<fos:result>"empty-sequence()"</fos:result>
</fos:test>
<fos:test use="v-type-of-e" spec="XQuery">
<fos:expression>type-of($e//doc/child::node())</fos:expression>
<fos:result>"(element()|processing-instruction())+"</fos:result>
</fos:test>
<fos:test>
<fos:expression>type-of(1)</fos:expression>
<fos:result>"xs:integer"</fos:result>
</fos:test>
<fos:test>
<fos:expression>type-of(1 to 5)</fos:expression>
<fos:result>"xs:integer+"</fos:result>
</fos:test>
<fos:test>
<fos:expression>type-of((1, 1.2, 2))</fos:expression>
<fos:result>"(xs:integer|xs:decimal)+"</fos:result>
</fos:test>
</fos:example>
</fos:examples>
<fos:changes>
<fos:change issue="1550" PR="1570" date="2024-11-12"><p>New in 4.0</p></fos:change>
</fos:changes>
</fos:function>

<fos:function name="nilled" prefix="fn">
<fos:signatures>
<fos:proto name="nilled" return-type="xs:boolean?">
Expand Down Expand Up @@ -22230,7 +22381,7 @@ declare function transitive-closure (
then the result of <code>abs($n)</code> is guaranteed to be an instance of <code>xs:integer</code>, but an
implementation might reasonably return the supplied value unchanged: that is, a value whose actual type
annotation is <code>xs:positiveInteger</code>. Similarly the type annotation of the value returned by
<code>position()</code> might have a type annotation of <code>xs:long</code> rather than <code>xs:integer</code>.</p>
<code>position()</code> might be <code>xs:long</code> rather than <code>xs:integer</code>.</p>

<p>Implementations <rfc2119>should</rfc2119>, however, refrain from exposing types that are purely internal.
For example, an implementation might have an optimized internal representation for strings consisting entirely
Expand Down
7 changes: 4 additions & 3 deletions specifications/xpath-functions-40/src/xpath-functions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1415,9 +1415,7 @@ This includes all the built-in datatypes defined in <bibref ref="xmlschema-2"/>.
</tbody>
</table>
<?local-function-index?>
<div3 id="func-node-kind">
<head><?function fn:node-kind?></head>
</div3>

<div3 id="func-node-name">
<head><?function fn:node-name?></head>
</div3>
Expand Down Expand Up @@ -9161,6 +9159,9 @@ return <table>
<div3 id="func-schema-type">
<head><?function fn:schema-type?></head>
</div3>
<div3 id="func-type-of">
<head><?function fn:type-of?></head>
</div3>
<div3 id="func-atomic-type-annotation">
<head><?function fn:atomic-type-annotation?></head>
</div3>
Expand Down