2011-04-20 87 views
1

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

表达式可以是任意的嵌套深度。下面是一个示例(该数据在一个表中的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来执行此转换吗?

+0

您不能处理未定义deph树不一般的递归。这就是为什么这个XQuery引擎有它自己的标签... – 2011-04-20 22:03:26

+0

@Alejandro,抱歉没有收到这个标签,感谢编辑。 – Lucero 2011-04-20 23:56:05

回答

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 
+0

非常感谢 - 确实不是很漂亮,但我猜这些漂亮的变体因为SQL Server XQuery的限制而无法工作......;)我会用我的测试用例(通过阅读代码我会认为它会正常工作)。 – Lucero 2011-04-20 23:14:17

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 
+0

更好:)。它也应该可以用递归CTE,但我认为你必须使用旧的'openxml'并使用'@mp:id'和'@mp:parentid'来构建层次结构。我不知道在使用XML数据类型时是否有任何等效函数。 – 2011-04-21 06:41:15

+0

是的,我也在做一个CTE,它总是将没有嵌套表达式的表达式转换为文本表示,直到没有任何标签再被使用,但它也没有真正的工作。我认为UDF是一个很好的折衷方案(甚至可能更有效)。 – Lucero 2011-04-21 09:13:08

相关问题