共用方式為


xsi:type magic

As I said in my previous post, the past few weeks have been demanding and I had little time to spend on blog post. However I recently rediscovered an interesting behavior in typed XML DML and I felt I should make some time for a quick post.

Today’s post deals with xsi:type. If you don’t know about this subcasting feature of XML Schema, here is a quick recap.

An element doesn’t always have to be validated according to the type it is associated with in its schema declaration. It is possible to validate it according to any subtype of the schema type. For example, if I have a declaration for an element ‘e’ of type ‘xsd:decimal’, I can decide to validate any instance of ‘e’ with any subtype of ‘xsd:decimal’, such as ‘xsd:byte’. In order to do this, my instance of ‘e’ must contain an attribute named ‘type’ qualified with namespace ‘https://www.w3.org/2001/XMLSchema’. The value of this attribute must be a QName that references the type to use for validation. In our example, my instance would look like this:

<e xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xs="https://www.w3.org/2001/XMLSchema" xsi:type="xs:byte">1</e>

 

If you are not familiar with this feature and need to find out more, you can read about it in the W3C’s primer document at https://www.w3.org/TR/xmlschema-0/#UseDerivInInstDocs

 

Before we go any further, let’s create a schema collection containing our definition of element ‘e’.

CREATE XML SCHEMA COLLECTION SC AS '

<schema xmlns="https://www.w3.org/2001/XMLSchema">

     <element name="e" type="decimal"/>

</schema>'

 

Additionally, let’s create a table ‘T’ with a typed XML column, and let’s insert two instances of ‘e’. The first one is just a regular instance. The second one makes use of the subcasting mechanism through the presence of the xsi:type attribute.

CREATE TABLE T (iCol int primary key, xmlCol XML(SC))

INSERT INTO T VALUES (1, '<e>1</e>')

INSERT INTO T VALUES (2, '<e xsi:type="xs:long" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xs="https://www.w3.org/2001/XMLSchema">1</e>')

 

Attribute xsi:type isn’t treated like other user-declared attributes. It cannot be queried or deleted, and its value cannot be replaced. For example, let’s run the following query

UPDATE T

SET xmlCol.modify('delete /e[1]/@xsi:type')

WHERE iCol = 2

 

We get the following error message

XQuery [T.xmlCol.modify()]: The XQuery syntax '@{https://www.w3.org/2001/XMLSchema-instance}:type' is not supported.

So is there a way to manipulate the xsi:type attribute? The short answer is “yes”, but there are limitations.

Let’s run the following XML DML query

UPDATE T

SET xmlCol.modify('replace value of /e[1] with xs:byte(1)')

Now let’s look at what happened to the two instances in the table. The first one now looks like this

<e>1</e>

And the second one looks like this

<e xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xs="https://www.w3.org/2001/XMLSchema" xsi:type="xs:byte">1</e>

Notice that the first instance remains unchanged, but in the second instance element ‘e’ is now subcasted to type xsd:byte. We can run an “instance of” query to show this.

select xmlCol.query('data(/e[1]) instance of xs:byte?') FROM T

returns

false

true

The rules for replace value of are the following

· If the destination element isn’t subcasted (i.e. doesn’t contain an xsi:type attribute) then the destination value is promoted to the schema type of the element

· If the destination element is subcasted (i.e. contains an xsi:type attribute) then it is recasted to the destination value’s type

If you’re inserting a non-subcasted element but know that you might want to change its types later, all you need to do is add an xsi:type attribute with a value equal to the QName of the element’s type as declared in the schema. In our case we’d do this

INSERT INTO T VALUES (3,

'<e xsi:type="xs:decimal" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xs="https://www.w3.org/2001/XMLSchema">1</e>')

 

Technically this instance is equivalent to <e>1</e> (since element ‘e’ is declared of type ‘xsd:decimal’ in the schema) but because it contains the xsi:type attribute, whenever its value is updated it will also take the type of the new value.

-
Disclaimer:
This posting is provided “AS IS” with no warranties, and confers no rights.
Use of included script samples are subject to the terms specified at https://www.microsoft.com/info/cpyright.htm.

Comments