T-sql用特殊元素解析XML节点

时间:2015-10-26 14:39:46

标签: xml tsql xquery

我的目标是打破这个xml,这样我就可以为每个Record Row获取Field元素并插入到SQL表中。 我根本无法弄清楚如何遍历网格层次结构。我已经能够运行一些xquery 对它的命令,但只在最高级别,如下所示。请帮助完全放下 为每一行的每个字段执行字段元素值。

declare @Responsetext varchar(8000)
set @Responsetext =
 '<GridResponse xmlns="http://abcd.abcd.net/aapi/2009/08/">
  <Brand id="1111">API Starter App</Brand>
  <User>AAA_API</User>
  <Grids>
    <Grid type="subscriber">
      <Record row="1">
        <Fields>
          <Field element="subscriber_id">111107293</Field>
          <Field element="bounce_date" />
          <Field element="cancellation_mailing_instance_id" />
          <Field element="cancellation_message" />
          <Field element="cancellation_date" />
          <Field element="email">aaaa4@gmail.com</Field>
          <Field element="is_repeated_bouncer">0</Field>
          <Field element="is_unsubscriber">0</Field>
          <Field element="modified_date">2015-04-07T13:19:09.3400000Z</Field>
          <Field element="service_since_date">2011-10-17T13:23:38.7800000Z</Field>
          <Field element="user_id" />
        </Fields>
      </Record>
      <Record row="2">
        <Fields>
          <Field element="subscriber_id">111169135</Field>
          <Field element="bounce_date" />
          <Field element="cancellation_mailing_instance_id" />
          <Field element="cancellation_message" />
          <Field element="cancellation_date" />
          <Field element="email">aaaa.bass@aaa.org</Field>
          <Field element="is_repeated_bouncer">0</Field>
          <Field element="is_unsubscriber">0</Field>
          <Field element="modified_date">2014-12-15T17:30:18.2230000Z</Field>
          <Field element="service_since_date">2011-10-19T14:11:26.6370000Z</Field>
          <Field element="user_id" />
        </Fields>
      </Record>
    </Grid>
  </Grids>
</GridResponse>
'

这段代码给了我节点树,但是我无法弄清楚如何调整它以隔离8级深度的字段值。

--This CTE gives you the Node Tree
WITH Xml_CTE AS
(
    SELECT
        CAST('/' + node.value('fn:local-name(.)',
            'varchar(100)') AS varchar(100)) AS name,
        node.query('*') AS children
    FROM @XmlResponse.nodes('/*') AS roots(node)

    UNION ALL

    SELECT
        CAST(x.name + '/' + 
            node.value('fn:local-name(.)', 'varchar(100)') AS varchar(100)),
        node.query('*') AS children
    FROM Xml_CTE x
    CROSS APPLY x.children.nodes('*') AS child(node)
)
SELECT distinct name
FROM Xml_CTE x
OPTION (MAXRECURSION 1000)

如果我将xml推入表而不是使用变量,我可以像这样得到根节点,但仍然无法达到字段级别。

--Parent Node -- Returns GridResponse
SELECT 
( 
SELECT 
c.value('local-name(.)', 'nvarchar(50)') 
FROM 
xmldata.nodes('/*') AS r(c) 
) AS RootParent 
FROM [dbo].subscriber_xml

我可以查询节点是否存在,并获取root和Brand子节点,但不能获取Grids子节点。这是非常令人困惑的,为什么一个工作,另一个不工作。

SELECT XmlData.exist('(/*[1][contains(local-name(.),"GridResponse")])') 
FROM [dbo].subscriber_xml

SELECT XmlData.exist('(/*/*[1][contains(local-name(.),"Brand")])') 
FROM [dbo].subscriber_xml

SELECT XmlData.exist('(/*/*[1][contains(local-name(.),"Grids")])') 
FROM [dbo].subscriber_xml

1 个答案:

答案 0 :(得分:0)

这是我的建议(请将@Responsetext的声明更改为XML):

WITH XMLNAMESPACES(DEFAULT 'http://abcd.abcd.net/aapi/2009/08/')
SELECT OneRecord.value('@row','varchar(max)') AS RowID
      ,OneRecord.value('(Fields/Field[@element="subscriber_id"])[1]','varchar(max)') AS subscriber_id
      ,OneRecord.value('(Fields/Field[@element="bounce_date"])[1]','varchar(max)') AS bounce_date
      ,OneRecord.value('(Fields/Field[@element="cancellation_mailing_instance_id"])[1]','varchar(max)') AS cancellation_mailing_instance_id
      ,OneRecord.value('(Fields/Field[@element="cancellation_message"])[1]','varchar(max)') AS cancellation_message
      ,OneRecord.value('(Fields/Field[@element="cancellation_date"])[1]','varchar(max)') AS cancellation_date
      ,OneRecord.value('(Fields/Field[@element="email"])[1]','varchar(max)') AS email
      ,OneRecord.value('(Fields/Field[@element="is_repeated_bouncer"])[1]','varchar(max)') AS is_repeated_bouncer
      ,OneRecord.value('(Fields/Field[@element="is_unsubscriber"])[1]','varchar(max)') AS is_unsubscriber
      ,OneRecord.value('(Fields/Field[@element="modified_date"])[1]','varchar(max)') AS modified_date
      ,OneRecord.value('(Fields/Field[@element="service_since_date"])[1]','varchar(max)') AS service_since_date
      ,OneRecord.value('(Fields/Field[@element="user_id"])[1]','varchar(max)') AS user_id
--INTO tempTable
FROM @Responsetext.nodes('/GridResponse/Grids/Grid/Record') AS Records(OneRecord)

这将在表格中显示您的数据。 只需在--之前删除INTO tempTable,然后在其中设置您喜欢的表名。这将创建一个具有给定结构的表,并用数据填充它。

还有一点:您应该根据您的数据选择数据类型。我全部用了varchar(max),但您可能希望将其更改为intdatetime或其他任何内容......