2016-01-31 5 views
2

Я предоставляю пользователям инструмента, над которым мы работаем, возможность вычисления переменных. Значения вычисляются с помощью выражения XPath. В .Net, с саксонской библиотекой, можно вычислить значение, выполнив выражение XPath в контексте значения, которое нужно вычислить.SQL Server XML.value node node

Пример XML:

@data = '<Object> 
    <Parameters> 
    <Parameter Name="a">2</Parameter> 
    <Parameter Name="b">5</Parameter> 
    <Parameter Name="c"/> 
    </Parameters> 
</Object>' 

Пример XPath-выражение в контексте параметра с именем "C":

../Parameter[@Name="a"]/text() + ../Parameter[@Name="b"]/text() 

Это Виль результат 7;)

Я хотел бы выполнить команду XPath на SQL Server, но теперь есть идея, как изменить контекстный узел типа XML?

Возможно, что я добавлю XPath перед выражением, которое изменяет контекст, но не нашел, если это возможно. Запрос может выглядеть так:

/<go to node variable "c" and make this the context node> 

../Parameter[@Name="a"]/text() + ../Parameter[@Name="b"]/text() 

У кого-то есть хорошие идеи?

ответ

1

Что вы хотите - AFAIK - невозможно ...

Попробуйте определить рабочий запрос с выражением XPath:

Btw: Ваш пример неправильно двумя способами: Attributs внутри XML не имеют @ -Марк и закрытия Parameters-тег отсутствует окончательное «S »...

DECLARE @data XML= 
'<Object> 
    <Parameters> 
    <Parameter Name="a">2</Parameter> 
    <Parameter Name="b">5</Parameter> 
    <Parameter Name="c"/> 
    </Parameters> 
</Object>'; 

--This will not work, because your parts are not singleton 
--SELECT Context.Node.value('../Parameter[@Name="a"]/text() + ../Parameter[@Name="b"]/text()','int') 
--FROM @data.nodes('/Object/Parameters/Parameter[@Name="c"]') AS Context(Node); 

--This works, because I framed both parts with (...)[1] 
SELECT Context.Node.value('(../Parameter[@Name="a"]/text())[1] + (../Parameter[@Name="b"]/text())[1]','int') 
FROM @data.nodes('/Object/Parameters/Parameter[@Name="c"]') AS Context(Node); 

но может быть обходным путем, но это вполне Hacky и не надежно:

хранимая процедура создает динамический оператор SQL застроенный из ваших параметров и выполняет это.

Ваш должен-не-быть изменено XPath выражение будет изменено в пути, что + с пустым влево и вправо (а также -, * и /) заменяется в путь, что возвращается одноэлементное выражение. Я не знаю, как могут быть сложные вычисления. Проверьте это ...

CREATE PROCEDURE dbo.CalculateXPathExpression 
(
    @data XML 
    ,@XPathContextNode VARCHAR(MAX) 
    ,@XPathCalculation VARCHAR(MAX) 
) 
AS 
BEGIN 
    DECLARE @Return INT; 
    DECLARE @CalcSingleton VARCHAR(MAX)='(' + REPLACE(REPLACE(REPLACE(REPLACE(@XPathCalculation,' + ',')[1] + ('),' - ',')[1] + ('),' * ',')[1] + ('),'/',')[1] + (') + ')[1]'; 
    DECLARE @Cmd NVARCHAR(MAX)= 
    'SELECT @Return = Context.Node.value(''' + @CalcSingleton + ''',''int'') 
    FROM @data.nodes(''' + @XPathContextNode + ''') AS Context(Node);'; 

    EXEC sp_executesql @Cmd, N'@data XML, @Return INT OUTPUT',@[email protected], @[email protected] OUTPUT; 

    SELECT @Return; 

    RETURN; 
END 
GO 

DECLARE @data XML= 
'<Object> 
    <Parameters> 
    <Parameter Name="a">2</Parameter> 
    <Parameter Name="b">5</Parameter> 
    <Parameter Name="c"/> 
    </Parameters> 
</Object>'; 

DECLARE @XPathContextNode VARCHAR(MAX)='/Object/Parameters/Parameter[@Name="c"]'; 
DECLARE @XPathCalculation VARCHAR(MAX)='../Parameter[@Name="a"]/text() + ../Parameter[@Name="b"]/text()'; 

EXEC dbo.CalculateXPathExpression @data, @XPathContextNode, @XPathCalculation; 
GO 

DROP PROCEDURE dbo.CalculateXPathExpression; 
GO 
+0

Спасибо за ваш ответ. Вы указываете мне на другой вопрос! Saxon XPath не является SQL XPath. Я представил XPath, чтобы освободить руки для реализации других функций вместо того, чтобы сделать свой собственный язык для вычисления переменных. Другим решением может быть использование библиотеки DLL, которая вычисляет выражение на стороне клиента также на сервере ?! –

+0

@MeindertOldenburger, к сожалению все вокруг XML не нормируется чисто ... Ваш комментарий - следующий вопрос, не связанный с этим вопросом. Я действительно думаю, что нет никакого «реального» решения для вашей проблемы ... Поскольку вы новичок в SO, пожалуйста, позвольте мне дать один совет: все профессионалы, дающие ответы на SO, жаждут очков репутации. [Пожалуйста, прочтите это: кто-то-ответы] (http://stackoverflow.com/help/someone-answers). Было бы очень любезно принять этот ответ (поскольку он решает вопрос) и начать новый вопрос со ссылкой здесь. Как только вы набрали более 15 очков: используйте свои голоса! – Shnugo

1

Используя SQL Server XQuery, вы можете объявить переменную XQuery, скажем $p, для ссылки на целевой родительский элемент i.e <Parameters>, где найден дочерний элемент с атрибутом Name="c". Затем вы можете сделать дальнейшую обработку XPath/XQuery при использовании $p в качестве контекстного элемента:

declare @data XML = '<Object> 
    <Parameters> 
    <Parameter Name="a">2</Parameter> 
    <Parameter Name="b">5</Parameter> 
    <Parameter Name="c"/> 
    </Parameters> 
</Object>' 

SELECT @data.value(' 
    let $p := /Object/Parameters[Parameter/@Name="c"] 
    return ($p/Parameter[@Name="a"])[1] + ($p/Parameter[@Name="b"])[1] 
','int') AS Result 

sqlfiddle demo

выход:

7 
+0

Спасибо за ваш ответ, но это не то, что я хочу. Оригинальный XPath должен оставаться как есть. –

+1

Я проголосовал за тебя, потому что я предпочитаю подход с «пусть», не знал этого ... Thx! – Shnugo

Смежные вопросы