2

我收到了一个我想通过 SQL 脚本生成的 XML 文档,但我没有做过类似的事情,也找不到任何可以让我生成所需的最终 XML 的示例(而且我不确定哪种可能的方法更适合我的需要 - EXPLICIT 或 PATH 或者它是否可能)。我希望在从 SQL 生成 XML 方面有一些经验的人能够指出我正确的方向(或者告诉我我想要做的事情是不可能的,我需要用子查询来做)。

场景是我从一个表中返回产品详细信息(我宁愿不必对我需要的每个值进行子查询)。

我希望能够生成的 xml 看起来像(我无法控制这种格式):

<records>
    <record>
        <fields>
            <field name="id">
                <values>
                    <value>666111</value>
                </values>
            </field>
            <field name="name">
                <values>
                    <value>
                        <![CDATA[My Product Title]]>
                    </value>
                </values>
            </field>
        </fields>
    </record>
    <record>
        ...
    </record>
</records>

我看过的第一种方法是使用 FOR XML PATH

SELECT TOP 2 
    'id' AS "@name",
    p.product_id as [value], 
    p.title
FROM products p 
ORDER BY p.product_id DESC
FOR XML PATH ('field'), ROOT ('fields'), ELEMENTS;

这给了我XML:

<fields>
  <field name="id">
    <value>20624</value>
    <title>test154</title>
  </field>
  <field name="id">
    <value>20623</value>
    <title>test153</title>
  </field>
</fields>

这给了我需要的'',但我无法指定下一个元素所需的布局。

我还研究了 FOR XML EXPLICIT

SELECT TOP 2
    1 AS Tag, NULL AS Parent,
    p.product_id AS [record!1!product_id!ELEMENT],
    NULL AS [values!2!value!ELEMENT]
FROM products p 
UNION ALL
SELECT TOP 2 
    2, 1,
    p.product_id,
    p.title
FROM products p 
ORDER BY [record!1!product_id!ELEMENT] DESC
FOR XML EXPLICIT;

这给了我以下 XML:

<record>
  <product_id>20624</product_id>
  <values>
    <value>test154</value>
  </values>
</record>
<record>
  <product_id>20623</product_id>
  <values>
    <value>test153</value>
  </values>
</record>

我在能够建立请求或获得正确的东西时有点迷失(而且我认为我在一次查找中尝试做太多事情,这就是我的问题的原因)。感谢您提供任何帮助-即使它为我指出了一个很好的指南(我发现的唯一示例在示例方面非常糟糕-它们没有显示您如何构建/更改它们的微妙之处)

4

3 回答 3

2

这是您可能正在寻找的查询

中间,''是一个技巧,它允许您创建多个具有相同名称的元素,一个在另一个之下......

DECLARE @tbl TABLE(id INT,name VARCHAR(100));
INSERT INTO @tbl VALUES
 (666111,'My Product Title 111')
,(666222,'My Product Title 222');

SELECT 
(
    SELECT  'id' AS [field/@name]
           ,id AS [field/values/value]
           ,''
           ,'name' AS [field/@name]
           ,name AS [field/values/value]
    FOR XML PATH('fields'),TYPE
)
FROM @tbl AS tbl
FOR XML PATH('record'),ROOT('records')

结果

<records>
  <record>
    <fields>
      <field name="id">
        <values>
          <value>666111</value>
        </values>
      </field>
      <field name="name">
        <values>
          <value>My Product Title 111</value>
        </values>
      </field>
    </fields>
  </record>
  <record>
    <fields>
      <field name="id">
        <values>
          <value>666222</value>
        </values>
      </field>
      <field name="name">
        <values>
          <value>My Product Title 222</value>
        </values>
      </field>
    </fields>
  </record>
</records>

更新:据我所知,没有干净的方法来添加CDATA-sections

出于某些原因,Microsoft 的人们认为 CDATA 部分不是必需的。嗯,他们不是,但有时他们仍然被要求......

添加部分的唯一干净方法CDATA是使用FOR XML EXPLICIT. 另一种解决方法是放置类似'|' + name + '#'(使用两个字符,这两个字符永远不会出现在您的实际数据中。

然后您可以将结果转换为NVARCHAR(MAX),在字符串基础上替换这些字符。

这会将您的 XML 作为字符串返回

SELECT 
REPLACE(REPLACE(CAST(
(
SELECT 
(
    SELECT  'id' AS [field/@name]
           ,id AS [field/values/value]
           ,''
           ,'name' AS [field/@name]
           ,'|' + name + '#' AS [field/values/value]
    FOR XML PATH('fields'),TYPE
)
FROM @tbl AS tbl
FOR XML PATH('record'),ROOT('records')
) AS NVARCHAR(MAX)),'|','<![CDATA['),'#',']]>')

此刻,您将其转换回XMLCDATA 已消失 :-(

于 2016-07-06T14:01:58.103 回答
1

类似的东西

    declare @t table (id varchar(10))

    insert into @t values ('1')
    insert into @t values ('2')

    select (
            select 
                    t.id 'fields/field/@id'
                    , t.id 'fields/field/name'
                from @t t
                for xml path(''), type
        ) 'records/record'
        for xml path('')
于 2016-07-06T14:10:21.523 回答
1

我使用的最终 SQL 是:

SELECT TOP 2
(
    SELECT  
        (SELECT 'id' AS [field/@id],
        product_id [field/values/value]
        FOR XML PATH(''), TYPE),
        (SELECT 'title' AS [field/@id],
        title [field/values/value]
        FOR XML PATH(''), TYPE)
    FOR XML PATH('fields'), TYPE
)
FROM products 
FOR XML PATH('record'), ROOT('records')

因为这使我可以更轻松地操作输出。

感谢@xdd 尤其是@Shnugo 的回答!最终解决方案基于@Shnugo 的建议,只是避免了添加额外空白行的技巧。

于 2016-07-06T15:21:55.143 回答