2011-04-20 85 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

相關問題