- query : xml را به عنوان ورودی گرفته و نهایتا یک خروجی XML دیگر را بر میگرداند.
- exist : خروجی bit دارد؛ true یا false. ورودی آن یک XQuery است.
- value : یک خروجی SQL Type را ارائه میدهد.
- nodes : خروجی جدولی دارد.
- modify : برای تغییر اطلاعات بکار میرود.
استفاده از متد exist به عنوان جایگزین سبک وزن XML Schema
یکی از کاربردهای متد exist، تعریف قید بر روی یک ستون XML ایی جدول است. این روش، راه حل دوم و سادهای است بجای استفاده از XML Schema برای ارزیابی و اعتبارسنجی کل سند. پیشنیاز اینکار، تعریف قید مدنظر توسط یک تابع جدید است:
CREATE FUNCTION dbo.checkPerson(@data XML) RETURNS BIT WITH SCHEMABINDING AS BEGIN RETURN @data.exist('/people/person') END GO CREATE TABLE tblXML ( id INT PRIMARY KEY, doc XML CHECK(dbo.checkPerson(doc)=1) ) GO
اکنون برای آزمایش آن خواهیم داشت:
INSERT INTO tblXML (id, doc) VALUES ( 1, '<people><person name="Vahid"/></people>' ) INSERT INTO tblXML (id, doc) VALUES ( 2, '<people><emp name="Vahid"/></people>' )
The INSERT statement conflicted with the CHECK constraint "CK__tblXML__doc__060DEAE8". The conflict occurred in database "testdb", table "dbo.tblXML", column 'doc'. The statement has been terminated.
استفاده از متد value برای دریافت اطلاعات
با کاربرد مقدماتی متد value در بازگشت یک مقدار scalar در قسمتهای قبل آشنا شدیم. در ادامه مثالهای کاربردیتر را بررسی خواهیم کرد.
ابتدا جدول زیر را با یک ستون XML در آن درنظر بگیرید:
CREATE TABLE xml_tab ( id INT IDENTITY PRIMARY KEY, xml_col XML )
INSERT INTO xml_tab VALUES ('<people><person name="Vahid"/></people>') INSERT INTO xml_tab VALUES ('<people><person name="Farid"/></people>')
SELECT id, xml_col.value('(/people/person/@name)[1]', 'varchar(50)') AS name FROM xml_tab
یک نکته
اگر نیاز به خروجی از نوع XML است، بهتر است از متد query که در دو قسمت قبل بررسی شد، استفاده گردد. خروجی متد query همیشه یک untyped XML است یا نال. البته میتوان خروجی آنرا به یک typed XML دارای Schema نیز نسبت داد. در اینجا اعتبارسنجی در حین انتساب صورت خواهد گرفت.
استفاده از متد value برای تعریف قیود
از متد value همچنین میتوان برای تعریف قیود پیشرفته نیز استفاده کرد. برای مثال فرض کنیم میخواهیم ویژگی Id سند XML در حال ذخیره شدن، حتما مساوی ستون Id جدول باشد. برای این منظور ابتدا نیاز است همانند قبل یک تابع جدید را ایجاد نمائیم:
CREATE FUNCTION getIdValue(@doc XML) RETURNS int WITH SCHEMABINDING AS BEGIN RETURN @doc.value('/*[1]/@Id', 'int') END
سپس از این تابع در عبارت check برای مقایسه ویژگی Id سند XML در حال ذخیره شدن و id ردیف جاری استفاده میشود:
CREATE TABLE docs_tab ( id INT PRIMARY KEY, doc XML, CONSTRAINT id_chk CHECK(dbo.getIdValue(doc)=id) )
در ادامه برای آزمایش آن خواهیم داشت:
INSERT INTO docs_tab (id, doc) VALUES ( 1, '<Invoice Id="1"/>' ) INSERT INTO docs_tab (id, doc) VALUES ( 2, '<Invoice Id="1"/>' )
The INSERT statement conflicted with the CHECK constraint "id_chk". The conflict occurred in database "testdb", table "dbo.docs_tab". The statement has been terminated.
استفاده از متد value برای تعریف primary key
پیشتر عنوان شد که از فیلدهای XML نمیتوان به عنوان کلید یک جدول استفاده کرد؛ چون امکان مقایسهی محتوای کل آنها وجود ندارد. اما با استفاده از متد value میتوان مقدار دریافتی را به عنوان یک کلید اصلی محاسبه شده، ثبت کرد:
CREATE TABLE Invoices ( doc XML, id AS dbo.getIdValue(doc) PERSISTED PRIMARY KEY )
برای آزمایش آن سعی میکنیم دو رکورد را که حاوی ویژگی id برابری هستند، ثبت کنیم:
INSERT INTO Invoices VALUES ( '<Invoice Id="1"/>' ) INSERT INTO Invoices VALUES ( '<Invoice Id="1"/>' )
Violation of PRIMARY KEY constraint 'PK__Invoices__3213E83F145C0A3F'. Cannot insert duplicate key in object 'dbo.Invoices'. The duplicate key value is (1). The statement has been terminated.
توابع دسترسی به مقدار دادهها در XQuery
تابع data ، string و text برای دسترسی به مقدار دادهها در XQuery پیش بینی شدهاند.
اگر سعی کنیم مثال زیر را اجرا نمائیم:
DECLARE @doc XML SET @doc = '<foo bar="baz" />' SELECT @doc.query('/foo/@bar')
XQuery [query()]: Attribute may not appear outside of an element
DECLARE @doc XML SET @doc = '<foo bar="baz" />' SELECT @doc.query('data(/foo/@bar)')
DECLARE @x XML SET @x = '<x>hello<y>world</y></x><x>again</x>' SELECT @x.query('data(/*)')
اما اگر همین مثال را با متد string اجرا کنیم:
DECLARE @x XML SET @x = '<x>hello<y>world</y></x><x>again</x>' SELECT @x.query('string(/*)')
XQuery [query()]: 'string()' requires a singleton (or empty sequence), found operand of type 'element(*,xdt:untyped) *'
SELECT @x.query('string(/*[1])')
برای دریافت تمام کلمات توسط متد string میتوان از اسلش کمک گرفت:
SELECT @x.query('string(/)')
نمونهی دیگر آن مثال زیر است:
DECLARE @x XML = '<age>12</age>' SELECT @x.query('string(/age[1])')
متد text اندکی متفاوت عمل میکند. برای بررسی آن، ابتدا یک schema collection جدید را تعریف میکنیم که داری تک المانی رشتهای است به نام Root.
CREATE XML SCHEMA COLLECTION root_el AS '<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:geo"> <xs:element name="Root" type="xs:string" /> </xs:schema> ' GO
DECLARE @xmlDoc XML SET @xmlDoc = '<g:Root xmlns:g="urn:geo">datadata...</g:Root>' SELECT @xmlDoc.query(' declare namespace g="urn:geo"; /g:Root/text() ')
DECLARE @xmlDoc XML(root_el) SET @xmlDoc = '<g:Root xmlns:g="urn:geo">datadata...</g:Root>' SELECT @xmlDoc.query(' declare namespace g="urn:geo"; /g:Root[1]/text() ')
XQuery [query()]: 'text()' is not supported on simple typed or 'http://www.w3.org/2001/XMLSchema#anyType' elements, found 'element(g{urn:geo}:Root,xs:string) *'.
DECLARE @xmlDoc XML(root_el) SET @xmlDoc = '<g:Root xmlns:g="urn:geo">datadata...</g:Root>' SELECT @xmlDoc.query(' declare namespace g="urn:geo"; data(/g:Root[1]) ')
data(/age/text())