sql-server - SQL 2016 - 将 XML 转换为 Json

标签 sql-server json xml tsql sql-server-2016

我正在尝试使用 SQL2016 中的 FOR JSON PATH 将 XML 列转换为 Json,但我遇到了一些问题。给定以下 XML(请注意,某些 Product 元素可能在其中包含 Product 列表):

  <Request>
    <SelectedProducts>
      <Product id="D04C01S01" level="1" />
      <Product id="158796" level="1" />
      <Product id="7464" level="2">
        <Product id="115561" level="3" />
      </Product>
      <Product id="907" level="2">
        <Product id="12166" level="3" />
        <Product id="33093" level="3" />
        <Product id="33094" level="3" />
        <Product id="28409" level="3" />
      </Product>
      <Product id="3123" level="2">
        <Product id="38538" level="3" />
        <Product id="37221" level="3" />
      </Product>
    </SelectedProducts>    
  </Request>

我可以在 SQL 上运行以下语句(其中 @xml 是上面的 XML):
SELECT 
     d.value('./@id', 'varchar(50)') AS 'Id'
    ,d.value('./@level', 'int') AS 'Level'
    ,(SELECT 
        --f.value('../@id', 'varchar(50)') AS 'ParentId'
        f.value('./@id', 'varchar(50)') AS 'Id'
        ,f.value('./@level', 'int') AS 'Level'
        --FROM @xml.nodes('/Request/SelectedProducts/Product[@id="3123"]/Product') AS e(f)          
        FROM @xml.nodes('/Request/SelectedProducts/Product/Product') AS e(f)            
        FOR JSON PATH) 'Product'
    FROM @xml.nodes('/Request/SelectedProducts/Product') AS c(d)
    FOR JSON PATH

它生成的 Json 是这样的:
[{"Id":"D04C01S01", 
  "Level":2,
  "Product":[{"Id":"115561", "Level":3 }, {"Id":"12166","Level":3 }, { Id":"33093", "Level":3 }, {"Id":"33094","Level":3 }, {"Id":"28409","Level":3},
{"Id":"38538","Level":3},{"Id":"37221","Level":3 }]},

{"Id":"158796", 
  "Level":3,
  "Product":[{"Id":"115561", "Level":3 }, {"Id":"12166","Level":3 }, { Id":"33093", "Level":3 }, {"Id":"33094","Level":3 }, {"Id":"28409","Level":3},
{"Id":"38538","Level":3},{"Id":"37221","Level":3 }]...

如您所见,问题是在生成的 Json 中,所有元素最终都包含所有 Product,而不管它们的父级关系如何。

我想我错过了一个 WHERE 子句,我会在其中检查它是否属于父节点,但我不知道如何进行。

我试图添加一个节点 Product[@id="3123"] (见注释行),但我需要替换实际父 ID 的“3123”,我不知道该怎么做。

另一种选择是实际保存父 ID(请参阅注释行 ParentId),然后在结果中使用 JSON_MODIFY 删除不匹配的元素,但我也没有成功。

有没有人对我如何解决这个问题有任何想法?或者我还能做什么?

-- 编辑
这是我期待的 Json:
[{"Request": 
[{"Id":"D04C01S01","Level":1 }, 
{"Id":"158796","Level":1},
{"Id":"7464","Level":2,"Product":[{"Id":"115561","Level":3}]},
{"Id":"907","Level":2,"Product":[{"Id":"12166","Level":3},{"Id":"33093","Level":3},{"Id":"33094","Level":3},{"Id":"28409","Level":3}]},
{"Id":"3123","Level":2,"Product":[{"Id":"38538","Level":3},{"Id":"37221","Level":3}]}]}]

您可以假设,如果 Level=1,则没有 Product 子级,如果 Level=2,则有 Product 子级。

谢谢

最佳答案

内部节点集上的 XPath 是从 XML 中选择所有节点,而不仅仅是外部节点的子节点。

(我没有 SQL2016 的副本,但这样的东西应该可以工作。)

SELECT 
    d.value('./@id', 'varchar(50)') AS 'Id'
    ,d.value('./@level', 'int') AS 'Level'
    ,(SELECT 
        f.value('./@id', 'varchar(50)') AS 'Id'
        ,f.value('./@level', 'int') AS 'Level'
        FROM c.d.nodes('./Product') AS e(f)            
        FOR JSON PATH) 'Product'
FROM @xml.nodes('/Request/SelectedProducts/Product') AS c(d)
FOR JSON PATH

关于sql-server - SQL 2016 - 将 XML 转换为 Json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45728704/

相关文章:

java - Android - 动态创建 View 无法按预期工作

sql-server - SQL Server 锁的问题

sql - 我在我的数据库中发现了很多奇怪的字符串,有人试图进入我的网站?

sql-server - 在非聚集主键索引中包含附加列

java - Jackson - 接受对象属性上的空字符串

javascript - 您如何处理每个 XML 数据

c# - 无法从 C# 使用 AAD 连接到 Azure SQL 数据库

json - 如何在 C# XAML Windows 8 Metro App 中解析/反序列化 JSON 字符串?

java - Spring MVC + JAXB : ServletException: Unable to locate object to be marshalled in model

java - 为 BacKstack 调用 getChildFragmentManager() 时出现非法状态异常