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



我有一些表示数学表达式树的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足够好地执行这个转换?

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

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

最新更新