Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Помогите распарсить xml в иерархию!  [new]
uaggster
Member

Откуда:
Сообщений: 867
Коллеги, помогите распарсить xml в иерархию таблиц.

Пример:
<a>
	<z>
		<x>1</x>
		<b>
			<y>a</y>
			<y>b</y>
			<y>c</y>
		</b>
	</z>
	<z>
		<x>1</x>
		<b>
			<y>a</y>
			<y>c</y>
		</b>
	</z>
	<z>
		<x>2</x>
		<b>
			<y>b</y>
			<y>c</y>
		</b>
	</z>
</a>


Нужно преобразовать в таблицы:
Create table z
(KeyZ int identity(1,1) primary key clustered,
x int)

Create table b
(KeyB int identity(1,1) primary key clustered,
KeyZ int,
y nvarchar(10))


Связь между таблицами - по синтетическому автоинкрементному ключу, т.к. натуральный "ключ" <х> не подходит, т.к. содержит повторяющиеся значения.

Фишка в том, что хочется решения через OPENXML (т.к. исходный хмл ОЧЕНЬ большой)
20 дек 13, 20:41    [15325676]     Ответить | Цитировать Сообщить модератору
 Re: Помогите распарсить xml в иерархию!  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5975
uaggster
Связь между таблицами - по синтетическому автоинкрементному ключу, т.к. натуральный "ключ" <х> не подходит, т.к. содержит повторяющиеся значения.

Необязательно по автоинкрементному - просто по уникальному. Нужен идентификатор ноды z, и в случае openxml он есть в edge table, из которой openxml извлекает данные. Поэтому можно сделать как-то так:
....
exec sp_xml_preparedocument @h out, @x;
declare
  @t1 table (
    z int,
    id int,
    x int
  );
declare
  @t2 table (
    b int,
    y varchar(1)
  );
insert into @t1
select z, id, x from openxml(@h, '/a/z/*')
with (
  z int '@mp:parentid',
  id int '@mp:id',
  x int 'text()'
);
insert into @t2
select b, y from openxml(@h, '/a/z/b/y')
with (
  b int '@mp:parentid',
  y varchar(1) 'text()'
) t2;
exec sp_xml_removedocument @h;
select
  tx.z, tx.x, t2.y
from @t2 t2
join @t1 tb on tb.id=t2.b
join @t1 tx on tx.z=tb.z and tx.x is not null

и полученные данные раскидать по нужным табличкам.
Хотя я бы сделал вот так:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" />
  <xsl:template match="/">
    <root>
      <xsl:apply-templates/>
    </root>
  </xsl:template>
  <xsl:template match="z">
    <z>
      <xsl:attribute name="x">
        <xsl:value-of select="x/text()"/>
      </xsl:attribute>
      <xsl:apply-templates/>
    </z>
  </xsl:template>
  <xsl:template match="y">
    <y>
      <xsl:attribute name="name">
        <xsl:value-of select="text()"/>
      </xsl:attribute>
    </y>
  </xsl:template>
  <xsl:template match="text()"/>
</xsl:stylesheet>

- после преобразования (не на сервере, естественно) получится вот такой xml:
<root>
  <z x="1">
    <y name="a" />
    <y name="b" />
    <y name="c" />
  </z>
  <z x="1">
    <y name="a" />
    <y name="c" />
  </z>
  <z x="2">
    <y name="b" />
    <y name="c" />
  </z>
</root>

а с ним все совсем просто:
select
  z,x,name y
from openxml(@h, '/root/z/y', 1)
with (
  name varchar(1),
  x int '../@x',
  z int '@mp:parentid'
);
21 дек 13, 08:54    [15326944]     Ответить | Цитировать Сообщить модератору
 Re: Помогите распарсить xml в иерархию!  [new]
uaggster
Member

Откуда:
Сообщений: 867
Сон Веры Павловны,
Нет, с xsd фокус не прокатит. XML, понятно, совсем не такой простой, и существенно более многоэтажный :). Мне просто нужен пример реализации.

Но за мысль - спасибо. :)
21 дек 13, 10:25    [15327008]     Ответить | Цитировать Сообщить модератору
 Re: Помогите распарсить xml в иерархию!  [new]
qwerty112
Guest
uaggster,

я правильно понимаю, что та структура таблиц, которая должна "получиться" - наперёд неизвестна ?

я делал такое для Акцесса, через MSXML2.DOMDocument - 13735864
в принципе, это можно переписать на VBS и работу с БД сервера, и потом запускать скрипт из ХП

+ тут - 13738446 - "платная приблуда", которая тем же "занимается" ...
21 дек 13, 12:04    [15327113]     Ответить | Цитировать Сообщить модератору
 Re: Помогите распарсить xml в иерархию!  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5975
uaggster
Мне просто нужен пример реализации

Ну, какой бы xml ни был, на него можно написать соответсвующий xslt.
А для вашего случая самый общий пример -
select * from openxml(@h, '//*')

- вы получаете edge table для всех нод исходного xml. Эта edge table иерархическая. Дальше из нее получаете всё, что нужно.
21 дек 13, 13:06    [15327228]     Ответить | Цитировать Сообщить модератору
 Re: Помогите распарсить xml в иерархию!  [new]
uaggster
Member

Откуда:
Сообщений: 867
qwerty112, нет, структура наперед известна. Просто состоит из, примерно, полутора десятков подобных иерархий (там тоже никакого произвола).
Результат нужен в виде реляционно связанного набора таблиц (по синтетическому ключу, проблемы там с натуральными).
Коллега Сон Веры Павловны подсказал @mp:id, @mp:parentid.
Тогда вроде бы все просто? Разложу xml по нескольким кучам в tempdb, а потом вставлю в целевую структуру, уже связанную автоинкрементными ключами (правда в целевой структуре должно появиться поле со значением @mp:id, как я понимаю).
Всё вроде должно получиться не блокирующе и параллельно...
Доберусь до компа - попробую!
22 дек 13, 08:36    [15329313]     Ответить | Цитировать Сообщить модератору
 Re: Помогите распарсить xml в иерархию!  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6723
uaggster
Нет, с xsd фокус не прокатит. XML, понятно, совсем не такой простой, и существенно более многоэтажный
Да конечно. XSD (XmlBulkLoad) можно загрузить почти любой xml в любую структуру.
Копайте.
Описалово. Дерево (какое смог найти).
Не забыть пометить тэг <b> как sql:is-constant="1" и прописать правильный <sql:relationship ...>.

OPENXML и XQuery для детей.
23 дек 13, 03:50    [15331708]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить