Преобразование дерева XML в плоский текст с использованием SQL Server 2008 XQuery - PullRequest
1 голос
/ 20 апреля 2011

У меня есть некоторые данные XML, представляющие дерево математических выражений, и я хочу преобразовать их в формулу плоской математики.Звучит просто, но ограничения XQuery в SQL Server в настоящее время мешают мне добиться успеха (нет рекурсивных функций, проблемы с «разнородными» результатами и т. Д.).

Выражение может иметь произвольную глубину вложенности.Вот пример (позже данные будут представлены в столбце 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]
)

Достаточно ли хорошо владеет XQuery в SQL Server 2008 (R2) для выполнения этого преобразования?

Ответы [ 2 ]

1 голос
/ 21 апреля 2011

Микаэль, ты вывел меня на правильный путь, вот мое окончательное решение:

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
1 голос
/ 21 апреля 2011

Не красиво, но, похоже, работает.Рекурсивный 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...