SQL-сервер имеет довольно расширенную поддержку для работы с XML. То, что вы ищете, это собственные методы XML типа данных XML .value()
, .nodes()
и .query()
. Найти подробности здесь .
Попробуйте:
DECLARE @xml XML=
N'<FORM>
<PAGES>
<PAGE Title="Record Input Sheet">
<FIELDS>
<FIELD Name="ddlStatus" type="DropdownList" Caption="Status" required="true" id="Status">
<PROPERTIES>
<PROPERTY name="ID">ddlStatus</PROPERTY>
<PROPERTY name="BackColor">lightyellow</PROPERTY>
<PROPERTY name="Width">75</PROPERTY>
<PROPERTY name="onchange">CategoryPopulate('' '')</PROPERTY>
<PROPERTY name="CssClass">form-control</PROPERTY>
</PROPERTIES>
<LISTITEMS>
<LISTITEM value="">Select</LISTITEM>
<LISTITEM value="Adjudicate">Adjudicate</LISTITEM>
<LISTITEM value="Skip">Skip</LISTITEM>
<LISTITEM value="Cancel">Cancel</LISTITEM>
</LISTITEMS>
</FIELD>
</FIELDS>
</PAGE>
</PAGES>
</FORM>';
SELECT pg.value('@Title','nvarchar(max)') AS PAGE_Title
,fld.value('@Name','nvarchar(max)') AS FIELD_Name
,fld.value('@type','nvarchar(max)') AS FIELD_type
,fld.value('@Caption','nvarchar(max)') AS FIELD_Caption
,fld.value('@required','nvarchar(max)') AS FIELD_required
,fld.value('@id','nvarchar(max)') AS FIELD_id
,fld.query('PROPERTIES/PROPERTY') AS FIELD_Properties
,fld.query('LISTITEMS/LISTITEM') AS FIELD_ListItems
FROM @xml.nodes('/FORM/PAGES/PAGE') A(pg)
OUTER APPLY A.pg.nodes('FIELDS/FIELD') B(fld);
Идея:
Вызов .nodes()
на /FORM/PAGES/PAGE
вернет производную таблицу со всеми страницами (если их несколько). Затем мы используем другой вызов .nodes()
, чтобы получить производную таблицу всех полей под каждой страницей.
.value()
-метод используется для получения внутренних значений. В вашем случае это атрибуты, следовательно, @
.
Я не знаю, как вы хотите иметь дело с внутренними свойствами и элементами списка, поэтому я включил их просто как .
UPDATE
Согласно вашему комментарию, следующий запрос немного улучшен: свойства выбираются по их именам, а список элементов списка возвращается в виде строки, разделенной запятой.
SELECT pg.value('@Title','nvarchar(max)') AS PAGE_Title
,fld.value('@Name','nvarchar(max)') AS FIELD_Name
,fld.value('@type','nvarchar(max)') AS FIELD_type
,fld.value('@Caption','nvarchar(max)') AS FIELD_Caption
,fld.value('@required','nvarchar(max)') AS FIELD_required
,fld.value('@id','nvarchar(max)') AS FIELD_id
,fld.value('(PROPERTIES/PROPERTY[@name="ID"]/text())[1]','nvarchar(max)') AS Prop_ID
,fld.value('(PROPERTIES/PROPERTY[@name="BackColor"]/text())[1]','nvarchar(max)') AS Prop_BackColor
--more properties--
,STUFF(
fld.query('for $li in LISTITEMS/LISTITEM
return <x>{concat(",",$li/text()[1])}</x>
').value('.','nvarchar(max)'),1,1,'') AS ListItems_separatedByBlanks
FROM @xml.nodes('/FORM/PAGES/PAGE') A(pg)
OUTER APPLY A.pg.nodes('FIELDS/FIELD') B(fld);
О свойствах:
Часть [@name="ID"]
называется предикатом . Это фильтр XQuery
, который можно прочитать как , взять свойство, где атрибут name
равен ID
и выбрать его text()
.
Об элементах списка:
Это небольшой взлом с использованием FLWOR-XQuery . Его можно прочитать как Выполнить через элементы списка и вернуть новый XML, где каждому text()
предшествует запятая . Использование .
в качестве Xpath
в .value()
вернет все из них в один . Функция STUFF()
необходима только для удаления запятой.