Разбор XML-файла со встроенной схемой с использованием OPENXML в SQL Server - PullRequest
0 голосов
/ 30 января 2019

Я пытаюсь извлечь данные из файла XML и сохранить их в таблице SQL с помощью OPENXML в SQL Server.Но запрос ничего не возвращает.

Данные XML

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:schema="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
    <xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd"/>
    <xsd:element name="ogridroles">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="ogrid_cde" type="sqltypes:int" nillable="1"/>
                <xsd:element name="role" nillable="1">
                    <xsd:simpleType>
                        <xsd:restriction base="sqltypes:char" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
                            <xsd:maxLength value="1"/>
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>
<ogridroles xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
    <ogrid_cde>28</ogrid_cde>
    <role>T</role>
</ogridroles>
<ogridroles xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
    <ogrid_cde>75</ogrid_cde>
    <role>T</role>
</ogridroles>
<ogridroles xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
    <ogrid_cde>93</ogrid_cde>
    <role>O</role>
</ogridroles>
<ogridroles xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
    <ogrid_cde>135</ogrid_cde>
    <role>O</role>
</ogridroles>
</root>

Запрос SQL

DECLARE @xmlStr xml;
DECLARE @idoc INT

SELECT @xmlStr = BulkColumn FROM OPENROWSET(
   BULK 'D:\ogridroles.xml',
   SINGLE_BLOB) AS DATA;

EXEC sp_xml_preparedocument @idoc OUTPUT, @xmlStr;
SELECT *
FROM OPENXML (@idoc, '/root/ogridroles',2)
    WITH (
        ogrid_cde   int 'ogrid_cde',
        role varchar(1) 'role')
EXEC sp_xml_removedocument @idoc

Я хочу извлечь все значения строк элементов

ogrid_cde
роль

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Подход через FROM OPENXML (вместе с процедурами подготовки и удаления документа) устарел и больше не должен использоваться.

Гораздо лучше родные методы XML-типа .Попробуйте это:

Ваш XML

DECLARE @xml XML=
N'<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <xsd:schema xmlns:schema="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" elementFormDefault="qualified">
    <xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
    <xsd:element name="ogridroles">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element name="ogrid_cde" type="sqltypes:int" nillable="1" />
          <xsd:element name="role" nillable="1">
            <xsd:simpleType>
              <xsd:restriction base="sqltypes:char" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
                <xsd:maxLength value="1" />
              </xsd:restriction>
            </xsd:simpleType>
          </xsd:element>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <ogridroles xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
    <ogrid_cde>28</ogrid_cde>
    <role>T</role>
  </ogridroles>
  <ogridroles xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
    <ogrid_cde>75</ogrid_cde>
    <role>T</role>
  </ogridroles>
  <ogridroles xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
    <ogrid_cde>93</ogrid_cde>
    <role>O</role>
  </ogridroles>
  <ogridroles xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
    <ogrid_cde>135</ogrid_cde>
    <role>O</role>
  </ogridroles>
</root>';

- Запрос

WITH XMLNAMESPACES(DEFAULT 'urn:schemas-microsoft-com:sql:SqlRowSet1')
SELECT OgrRol.value('(ogrid_cde/text())[1]','int') AS ogrid_cde
      ,OgrRol.value('(role/text())[1]','nvarchar(10)') AS [role]
FROM @xml.nodes('/*:root/ogridroles') A(ogrRol);

Результат

ogrid_cde   role
28          T
75          T
93          O
135         O

Краткое объяснение

Вы можете просто проигнорировать XML-схему здесь.Это было бы полезно для проверки целостности и достоверности данных.Но если предположить, что данные верны, мы можем просто прочитать их.

Существует (неоднократно определенное) пространство имен по умолчанию .Но - это важно видеть! - сам элемент <root> не живет в этом пространстве имен!.

Спокойно, я только что использовал подстановочный знак namespace для адресации этого элемента с *:root.В общем, лучше избегать подстановочных знаков, но в этом случае это кажется приемлемым.

Мы используем .nodes(), чтобы получить производную таблицу всех элементов <ogridroles>.Затем мы .value() будем читать text() узлы кода и элемент роли.

Надеюсь, это поможет, удачного кодирования!

0 голосов
/ 30 января 2019

Я не очень хорошо разбираюсь в схемах и использую другой способ декодирования XML:

DECLARE @x XML = 'bla bla bla'
DECLARE @idoc INT
EXEC sp_xml_preparedocument @idoc OUTPUT ,@x 

SELECT * INTO #t
FROM OPENXML (@idoc, '/',2)
EXEC sp_xml_removedocument @idoc 

SELECT [ogrid_cde] = t3.text, [role] = t4.text
FROM #t as t1
INNER JOIN #t as t2 ON t1.parentid = t2.parentid
INNER JOIN #t as t3 ON t1.id = t3.parentid
INNER JOIN #t as t4 ON t2.id = t4.parentid
WHERE t1.localname = 'ogrid_cde' and t2.localname = 'role'
...