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

时间:2011-04-20 19:28:10

标签: sql-server xml sql-server-2008 recursive-query xquery-sql

我有一些表示数学表达式树的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]
)

有人在SQL Server 2008(R2)中掌握XQuery是否足以执行此转换?

2 个答案:

答案 0 :(得分:1)

不漂亮,但似乎有效。递归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

答案 1 :(得分:1)

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