使用 SQL Server 2008 XQuery 将 XML 树转换为平面文本

发布于 2024-11-02 17:15:14 字数 1605 浏览 0 评论 0原文

我有一些表示数学表达式树的 XML 数据,并且希望将其转换为平面数学公式。听起来很简单,但 SQL Server 中的 XQuery 限制目前阻止了我成功(没有递归函数、“异构”结果问题等)。

该表达式可以具有任意嵌套深度。这是一个示例(数据稍后位于表的 xml 列中,但这对于此处的测试来说已经足够了):

DECLARE @expr xml;
SET @expr = '<expression aggregator="+">
  <indicator>122F277B-A241-7944-BC38-3BB5E8B213AF</indicator>
  <indicator>7DD46849-2193-EB41-8BAB-CE0C45255249</indicator>
  <expression aggregator="*">
    <expression aggregator="/">
      <indicator>122F277B-A241-7944-BC38-3BB5E8B213AF</indicator>
      <indicator>27F3156D-FDA7-1E44-B545-7F27A48D9838</indicator>
    </expression>
    <indicator>ADFCEF34-9877-DE4E-8A00-13576437D82B</indicator>
    <value>12</value>
  </expression>
  <expression aggregator="-">
    <indicator>ADFCEF34-9877-DE4E-8A00-13576437D82B</indicator>
    <indicator>75896474-C197-1C44-8EAA-8FE9D0AB2663</indicator>
  </expression>
  <indicator>27F3156D-FDA7-1E44-B545-7F27A48D9838</indicator>
</expression>';

所需的结果是(空格无关紧要):

(
  [122F277B-A241-7944-BC38-3BB5E8B213AF] +
  [7DD46849-2193-EB41-8BAB-CE0C45255249] +
  (
    (
      [122F277B-A241-7944-BC38-3BB5E8B213AF] /
      [27F3156D-FDA7-1E44-B545-7F27A48D9838]
    ) *
    [ADFCEF34-9877-DE4E-8A00-13576437D82B] *
    12
  ) +
  (
    [ADFCEF34-9877-DE4E-8A00-13576437D82B] -
    [75896474-C197-1C44-8EAA-8FE9D0AB2663]
  ) +
  [27F3156D-FDA7-1E44-B545-7F27A48D9838]
)

Does 有人掌握 SQL Server 2008 (R2) 中的 XQuery 吗执行此转换?

I have some XML data representing a mathematical expression tree and want to convert this to a flat math formula. Sounds simple, but the XQuery restrictions in SQL Server currently stopped me from succeeding (no recursive functions, problems with "heterogeneous" results etc.).

The expression can be of an arbitrary nesting depth. Here's a sample (the data is in a xml column of a table later on, but that's good enough for testing here):

DECLARE @expr xml;
SET @expr = '<expression aggregator="+">
  <indicator>122F277B-A241-7944-BC38-3BB5E8B213AF</indicator>
  <indicator>7DD46849-2193-EB41-8BAB-CE0C45255249</indicator>
  <expression aggregator="*">
    <expression aggregator="/">
      <indicator>122F277B-A241-7944-BC38-3BB5E8B213AF</indicator>
      <indicator>27F3156D-FDA7-1E44-B545-7F27A48D9838</indicator>
    </expression>
    <indicator>ADFCEF34-9877-DE4E-8A00-13576437D82B</indicator>
    <value>12</value>
  </expression>
  <expression aggregator="-">
    <indicator>ADFCEF34-9877-DE4E-8A00-13576437D82B</indicator>
    <indicator>75896474-C197-1C44-8EAA-8FE9D0AB2663</indicator>
  </expression>
  <indicator>27F3156D-FDA7-1E44-B545-7F27A48D9838</indicator>
</expression>';

The required result would be (whitespace is insignificant):

(
  [122F277B-A241-7944-BC38-3BB5E8B213AF] +
  [7DD46849-2193-EB41-8BAB-CE0C45255249] +
  (
    (
      [122F277B-A241-7944-BC38-3BB5E8B213AF] /
      [27F3156D-FDA7-1E44-B545-7F27A48D9838]
    ) *
    [ADFCEF34-9877-DE4E-8A00-13576437D82B] *
    12
  ) +
  (
    [ADFCEF34-9877-DE4E-8A00-13576437D82B] -
    [75896474-C197-1C44-8EAA-8FE9D0AB2663]
  ) +
  [27F3156D-FDA7-1E44-B545-7F27A48D9838]
)

Does someone master XQuery in SQL Server 2008 (R2) well enough to perform this transformation?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

提赋 2024-11-09 17:15:15

不漂亮,但似乎有效。递归 UDF。

create function GetExpression(@expr xml) returns varchar(max)
as
begin
  declare @max int
  declare @i int = 1
  declare @nodetype varchar(50)
  declare @aggregator char(1)
  declare @res varchar(max) = '('
  declare @value varchar(36)
  declare @SubExpr xml

  select @max=count(*)
  from @expr.nodes('/expression/*') as n(e)

  select @aggregator = n.e.value('@aggregator', 'char(1)')
  from @expr.nodes('expression') as n(e)

  while @i <= @max
  begin
    select
      @nodetype = x.value('local-name(.)[1]', 'varchar(36)'),
      @value = x.value('.', 'varchar(36)'),
      @SubExpr = x.query('.')
    from @expr.nodes('/expression/*[position()=sql:variable("@i")]') e(x)

    if @nodetype = 'indicator'
      set @res = @res + '[' + @value + ']'
    else
    if @nodetype = 'expression'
      set @res = @res + dbo.GetExpression(@SubExpr)
    else  
    if @nodetype = 'value'
      set @res = @res + @value

    if @i < @max
      set @res = @res + @aggregator

    set @i = @i + 1        
  end

  set @res = @res + ')'

 return @res
end

Not pretty but it seems to work. A recursive UDF.

create function GetExpression(@expr xml) returns varchar(max)
as
begin
  declare @max int
  declare @i int = 1
  declare @nodetype varchar(50)
  declare @aggregator char(1)
  declare @res varchar(max) = '('
  declare @value varchar(36)
  declare @SubExpr xml

  select @max=count(*)
  from @expr.nodes('/expression/*') as n(e)

  select @aggregator = n.e.value('@aggregator', 'char(1)')
  from @expr.nodes('expression') as n(e)

  while @i <= @max
  begin
    select
      @nodetype = x.value('local-name(.)[1]', 'varchar(36)'),
      @value = x.value('.', 'varchar(36)'),
      @SubExpr = x.query('.')
    from @expr.nodes('/expression/*[position()=sql:variable("@i")]') e(x)

    if @nodetype = 'indicator'
      set @res = @res + '[' + @value + ']'
    else
    if @nodetype = 'expression'
      set @res = @res + dbo.GetExpression(@SubExpr)
    else  
    if @nodetype = 'value'
      set @res = @res + @value

    if @i < @max
      set @res = @res + @aggregator

    set @i = @i + 1        
  end

  set @res = @res + ')'

 return @res
end
猫弦 2024-11-09 17:15:15

Mikael,你让我走上了正轨,这是我的最终解决方案:

CREATE FUNCTION dbo.GetExpression (@expr xml)
RETURNS varchar(max)
AS 
BEGIN
  RETURN STUFF(
    (   SELECT a.x.value('.', 'char'), CASE 
            WHEN v.x.exist('self::expression')=1 THEN '('+dbo.GetExpression(v.x.query('.'))+')' 
            WHEN v.x.exist('self::indicator')=1 THEN '['+REPLACE(v.x.value('.', 'varchar(35)'), '-', '')+']' 
            ELSE v.x.value('.', 'varchar(20)') 
        END
        FROM @expr.nodes('expression/@aggregator') a(x)
        CROSS APPLY @expr.nodes('expression/*') v(x) 
        FOR XML PATH('')
    ), 
    1, 1, '');
END

Mikael, you got me on the right track, here's my final solution:

CREATE FUNCTION dbo.GetExpression (@expr xml)
RETURNS varchar(max)
AS 
BEGIN
  RETURN STUFF(
    (   SELECT a.x.value('.', 'char'), CASE 
            WHEN v.x.exist('self::expression')=1 THEN '('+dbo.GetExpression(v.x.query('.'))+')' 
            WHEN v.x.exist('self::indicator')=1 THEN '['+REPLACE(v.x.value('.', 'varchar(35)'), '-', '')+']' 
            ELSE v.x.value('.', 'varchar(20)') 
        END
        FROM @expr.nodes('expression/@aggregator') a(x)
        CROSS APPLY @expr.nodes('expression/*') v(x) 
        FOR XML PATH('')
    ), 
    1, 1, '');
END
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文