Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 загадки OPENXML  [new]
aleks2
Guest
Стандартный пример
DECLARE @docHandle int
DECLARE @XmlDocument nvarchar(1000)
SET @XmlDocument = N'<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot">
   <Order EmployeeID="5" >
      <OrderID>10248</OrderID>
      <CustomerID>VINET</CustomerID>
      <OrderDate>1996-07-04T00:00:00</OrderDate>
      <OrderDetail ProductID="11" Quantity="12"/>
      <OrderDetail ProductID="42" Quantity="10"/>
   </Order>
</Customer>
<Customer CustomerID="LILAS" ContactName="Carlos Gonzlez">
   <Order  EmployeeID="3" >
      <OrderID>10283</OrderID>
      <CustomerID>LILAS</CustomerID>
      <OrderDate>1996-08-16T00:00:00</OrderDate>
      <OrderDetail ProductID="72" Quantity="3"/>
   </Order>
</Customer>
</ROOT>'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @docHandle OUTPUT, @XmlDocument
-- Execute a SELECT statement using OPENXML rowset provider.

-- 1. Возвращает данные
SELECT *, cast(localname as varbinary(100))
FROM OPENXML (@docHandle, '/ROOT')
-- эквивалент
SELECT *, cast(localname as varbinary(100))
FROM OPENXML (@docHandle, '/*')

-- 2. НЕ Возвращает данные
SELECT *, cast(localname as varbinary(100))
FROM OPENXML (@docHandle, '/ROOt')

EXEC sp_xml_removedocument @docHandle


как бы все понятно. XML - регистрочувствителен.

НО! у мя есть файл, который я не могу заставить вернуть данные
-- 1. вот это возвращает данные
SELECT  *
FROM OPENXML (@hdoc, '/*',1)

0	NULL	1	selena	NULL	http://project.selena-online.ru	NULL	1	NULL	0x730065006C0065006E006100
5	0	2	xmlns	xmlns	NULL	NULL	NULL	NULL	0x78006D006C006E007300
199	5	3	#text	NULL	NULL	NULL	NULL	http://project.selena-online.ru	0x23007400650078007400
6	0	2	xsi	xmlns	NULL	NULL	NULL	NULL	0x780073006900
200	6	3	#text	NULL	NULL	NULL	NULL	http://www.w3.org/2001/XMLSchema-instance	0x23007400650078007400
7	0	2	schemaLocation	xsi	http://www.w3.org/2001/XMLSchema-instance	NULL	NULL	NULL	0x73006300680065006D0061004C006F0063006100740069006F006E00
201	7	3	#text	NULL	NULL	NULL	NULL	http://project.selena-online.ru https://selena-online.ru/static/rest/apartmentprice.xsd	0x23007400650078007400
8	0	1	apartmentprices	NULL	http://project.selena-online.ru	NULL	NULL	NULL	0x610070006100720074006D0065006E007400700072006900630065007300
9	8	1	apartment	NULL	http://project.selena-online.ru	NULL	NULL	NULL	0x610070006100720074006D0065006E007400
10	9	2	id	NULL	NULL	NULL	NULL	NULL	0x69006400
202	10	3	#text	NULL	NULL	NULL	NULL	26	0x23007400650078007400
11	9	1	price	NULL	http://project.selena-online.ru	NULL	NULL	NULL	0x70007200690063006500

-- 2. НЕ возвращает ничего
SELECT  *
FROM OPENXML (@hdoc, '/selena',1)
-- хотя "selena" просто скопирована из предыдущего набора

Я, канешно, могу обойтись и *, но интересно же в чем засада?
27 окт 15, 09:20    [18330960]     Ответить | Цитировать Сообщить модератору
 Re: загадки OPENXML  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5975
aleks2,

а можно пример этого файла? а то как-то проворачивать назад фарш от edge table к исходному xml не очень получается.
27 окт 15, 11:07    [18331514]     Ответить | Цитировать Сообщить модератору
 Re: загадки OPENXML  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5975
P.S. вангую, что у тэга selena прописан xmlns.
27 окт 15, 11:19    [18331563]     Ответить | Цитировать Сообщить модератору
 Re: загадки OPENXML  [new]
invm
Member

Откуда: Москва
Сообщений: 9400
Репро:
DECLARE @docHandle int;
DECLARE @XmlDocument nvarchar(1000);
SET @XmlDocument = N'<selena xmlns="http://project.selena-online.ru"/>';

EXEC sp_xml_preparedocument @docHandle OUTPUT, @XmlDocument;

SELECT *, cast(localname as varbinary(100))
FROM OPENXML (@docHandle, '/selena', 1);

SELECT *, cast(localname as varbinary(100))
FROM OPENXML (@docHandle, '/*', 1);

EXEC sp_xml_removedocument @docHandle
27 окт 15, 11:32    [18331639]     Ответить | Цитировать Сообщить модератору
 Re: загадки OPENXML  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5975
invm,

DECLARE @docHandle int;
DECLARE @XmlDocument nvarchar(1000);
SET @XmlDocument = N'<selena xmlns="http://project.selena-online.ru"/>';

EXEC sp_xml_preparedocument @docHandle OUTPUT, @XmlDocument, '<selena xmlns:ns="http://project.selena-online.ru"/>';

SELECT *, cast(localname as varbinary(100))
FROM OPENXML (@docHandle, '/ns:selena', 1);

SELECT *, cast(localname as varbinary(100))
FROM OPENXML (@docHandle, '/*', 1);

EXEC sp_xml_removedocument @docHandle
27 окт 15, 11:34    [18331652]     Ответить | Цитировать Сообщить модератору
 Re: загадки OPENXML  [new]
aleks2
Guest
Сон Веры Павловны
invm,

DECLARE @docHandle int;
DECLARE @XmlDocument nvarchar(1000);
SET @XmlDocument = N'<selena xmlns="http://project.selena-online.ru"/>';

EXEC sp_xml_preparedocument @docHandle OUTPUT, @XmlDocument, '<selena xmlns:ns="http://project.selena-online.ru"/>';

SELECT *, cast(localname as varbinary(100))
FROM OPENXML (@docHandle, '/ns:selena', 1);

SELECT *, cast(localname as varbinary(100))
FROM OPENXML (@docHandle, '/*', 1);

EXEC sp_xml_removedocument @docHandle


Нельзя отрицать - работает.
Но еще бы пояснить: в чем суть проблемы?
27 окт 15, 12:33    [18332069]     Ответить | Цитировать Сообщить модератору
 Re: загадки OPENXML  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5975
aleks2
Но еще бы пояснить: в чем суть проблемы?

В том, что в данном случае узел нельзя адресовать через его local name, т.к. для него задан xml namespace, и узел должен адресоваться по совокупности xmlns и local-name. В таком случае парсеру нужно обязательно скормить неймспейсы узлов, к которым мы собираемся обращаться, и префиксы этих неймспейсов (задать можно свои). Собственно, третий параметр sp_xml_preparedocument именно эти данные и принимает (см. документацию). И это всё касается не только OPENXML - то же самое и в XQuery (там неймспейсы задаются в инструкции with xmlnamespces), и у прочих парсеров (msxml, saxon, дотнетовский XmlDocument, итд.).
И еще нюанс: если в OPENXML используется element-centric mapping, и элемент, заданный в with, соответствует узлу с объявленным неймспейсом, то для поля внутри with после задания типа следует указать префиксированное имя элемента:
declare
  @n int,
  @xml xml=N'<root xmlns="urn:foo"><a>123</a></root>';
exec sp_xml_preparedocument @n out, @xml, N'<root xmlns:foo="urn:foo"/>';
select a from openxml(@n, '/foo:root', 2) with (a int 'foo:a');
exec sp_xml_removedocument @n 
27 окт 15, 12:48    [18332150]     Ответить | Цитировать Сообщить модератору
 Re: загадки OPENXML  [new]
aleks2
Guest
Сон Веры Павловны
aleks2
Но еще бы пояснить: в чем суть проблемы?

В том, что в данном случае узел нельзя адресовать через его local name, т.к. для него задан xml namespace, и узел должен адресоваться по совокупности xmlns и local-name. В таком случае парсеру нужно обязательно скормить неймспейсы узлов, к которым мы собираемся обращаться, и префиксы этих неймспейсов (задать можно свои). Собственно, третий параметр sp_xml_preparedocument именно эти данные и принимает (см. документацию). И это всё касается не только OPENXML - то же самое и в XQuery (там неймспейсы задаются в инструкции with xmlnamespces), и у прочих парсеров (msxml, saxon, дотнетовский XmlDocument, итд.).
И еще нюанс: если в OPENXML используется element-centric mapping, и элемент, заданный в with, соответствует узлу с объявленным неймспейсом, то для поля внутри with после задания типа следует указать префиксированное имя элемента:
declare
  @n int,
  @xml xml=N'<root xmlns="urn:foo"><a>123</a></root>';
exec sp_xml_preparedocument @n out, @xml, N'<root xmlns:foo="urn:foo"/>';
select a from openxml(@n, '/foo:root', 2) with (a int 'foo:a');
exec sp_xml_removedocument @n 


Большое спасибо.
"Мои" познания в этом вопросе произвели неизгладимое впечатление на собеседователей.
Я даже не ожидал.
28 окт 15, 09:31    [18336039]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить