Skip to content

Commit

Permalink
Replace node-kind() with new type-of() function
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelhkay committed Nov 12, 2024
1 parent 5f488b2 commit 76061a7
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 3 deletions.
143 changes: 143 additions & 0 deletions specifications/xpath-functions-40/src/function-catalog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,149 @@ $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()*" default="." usage="inspection"/>
</fos:proto>
</fos:signatures>
<fos:properties arity="0">
<fos:property>deterministic</fos:property>
<fos:property>context-dependent</fos:property>
<fos:property>focus-dependent</fos:property>
</fos:properties>
<fos:properties arity="1">
<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>If the argument is omitted, it defaults to the context value (<code>.</code>).</p>
<p>If <code>$item</code> is the empty sequence, the function returns the string <code>"empty-sequence()"</code>.</p>
<p>Otherwise, 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>. 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>
</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" 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
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 @@ -7973,6 +7971,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

0 comments on commit 76061a7

Please sign in to comment.