Del via


Some more static typing info...

Denis talks about static typing again over in his blog. Today he is focusing on path expressions which evaluate to singletons. I recommend you check the entry on his site for the details. The only thing that I wanted to add is that usually it is better from a performance perspective to wrap the entire path expression with a predicate (if possible), rather than applying postitional predicates across the entire path expression. I am going to use the sample XSD that Denis provided:

CREATE XML SCHEMA COLLECTION MyCollection AS '
<schema xmlns="https://www.w3.org/2001/XMLSchema" targetNamespace="uri:myns" xmlns:ns="uri:myns">

 <complexType name="myType">
<sequence>
<element name="a" type="string" minOccurs="1" maxOccurs="1"/>
<element name="b" type="byte" minOccurs="3" maxOccurs="7"/>
</sequence>
</complexType>

 <element name="root" type="ns:myType"/>

</schema>'
go

I am going to use the value() method in my examples. Like the "replace value of" XQuery DML statement that Denis uses, the result of the value() method must be a singleton. 

DECLARE @var XML(MyCollection)
SET @var = '<x:root xmlns:x="uri:myns">
<a>Data</a>
<b>1</b><b>2</b><b>3</b>
</x:root>'
SELECT @var.value('declare namespace ns="uri:myns"; /ns:root[1]/a', 'nvarchar(max)')

This expression will compile and execute just fine, however one could write the following statement instead and it will actually in most cases perform better:

DECLARE @var XML(MyCollection)
SET @var = '<x:root xmlns:x="uri:myns">
<a>Data</a>
<b>1</b><b>2</b><b>3</b>
</x:root>'
SELECT @var.value('declare namespace ns="uri:myns"; (/ns:root/a)[1]', 'nvarchar(max)')

Now, I understand that these are not technically equivalent path expressions, but many times they can be used interchangeably due to the schema. One gets the the element "a" which is a child of the 1st top-level element "ns:root", the second gets all of the elements "a" underneath the element "ns:root", and picks the 1st one from that set. However, in many cases these are actually equivalent due to the schema constraints.

One more thing that I want to throw out there is that in this example, you can get away with not using the positional predicate altogether by specifying the DOCUMENT property on the XML instance:

DECLARE @var XML(DOCUMENT MyCollection)
SET @var = '<x:root xmlns:x="uri:myns">
<a>Data</a>
<b>1</b><b>2</b><b>3</b>
</x:root>'
SELECT @var.value('declare namespace ns="uri:myns"; /ns:root/a', 'nvarchar(max)')

The DOCUMENT property works in two ways, first of all it tells the XSD validator to only accept instances which contain a single top-level element and no top-level text nodes. Secondly, we actually use this information for static typing of path expressions in the XQuery statements. In this case, we are guaranteed that there will always be exactly one "ns:root" element, and according to the schema it will always have another element "a" as its child.