2012-02-10 22 views
9

値を取得するxml属性であるattributeという変数を使用するSQL関数があります。 xmlPathは完全なXML文字列です。変数を使用してSQL xml属性値を取得

私のXMLは次のようになります。

<EventSpecificData> 
    <Keyword> 
    <Word>myWord</Word> 
    <Occurences>1</Occurences> 
    <Context>context</Context> 
    </Keyword> 
</EventSpecificData> 

私は<Word>の値を取得したいので、私は/Keyword/Wordに渡すと、変数を設定します。

set @value = @xmlPath.value('(/EventSpecificData/@attribute)[1]', 'varchar(max)') 

しかし、私はしないでください@attributeが実際に変数文字列を挿入していると考えてください。これを行う別の方法がありますか?

+0

私はあなたがそうすることはできないと思っています.SQL XQueryはリテラル文字列で動作することが多く、ほとんどの場合、SQL変数で置き換えることはできません。 –

答えて

14

ここにはいくつかの解決策があります。

サンプルデータ:

declare @xml xml 
set @xml = 
'<EventSpecificData> 
    <Keyword> 
    <Word>myWord</Word> 
    <Occurences>1</Occurences> 
    <Context>context</Context> 
    </Keyword> 
</EventSpecificData>' 

は関係なく、両親の言葉という名前のノードから最初の値を取得します。深い検索を行い、local-name()を使用してノード名を一致させるには、//を使用します。

declare @Attribute varchar(max) 

set @Attribute = 'Word' 
select @xml.value('(//*[local-name() = sql:variable("@Attribute")])[1]', 'varchar(max)') 

local-name()を2つのレベルで使用して、別々の変数に親ノードの名前と属性を指定します。 nodesのパラメータので

declare @Node varchar(max) 
declare @Attribute varchar(max) 

set @Attribute = 'Word' 
set @Node = 'Keyword' 
select @xml.value('(/EventSpecificData 
        /*[local-name() = sql:variable("@Node")] 
        /*[local-name() = sql:variable("@Attribute")])[1]', 'varchar(max)') 

は、この問題を解決するために、動的SQLを使用するように誘うリテラル文字列でなければなりません。元の変数の内容と同じように見えるようにすることができます。

set @Attribute = 'Keyword/Word' 
declare @SQL nvarchar(max) 
set @SQL = 'select @xml.value(''(/EventSpecificData/'[email protected]+')[1]'', ''varchar(max)'')' 
exec sp_executesql @SQL, N'@xml xml', @xml 

しかし、あなたがこれを使用する場合は、SQLインジェクション攻撃に大きく開いていることに注意する必要があります。それはあなたに2つの結果セットを与えると、動的SQLを実行

set @Attribute = 'Keyword/Word)[1]'', ''varchar(max)'') select @@version --' 

:一部のよこしまなエンドユーザーは次のようになります属性文字列を思い付くかもしれません。 select @@versionは、無害なコードを表示するためだけにありますが、そこにはもっと悪いものがあるかもしれません。

quotename()を使用すると、SQLインジェクション攻撃を防ぐことができます。それは少なくとも私の試みを妨げるでしょう。

quotename()を使用している最後のバージョンは安全ですか? Erland Sommarskog The Curse and Blessings of Dynamic SQLによってこの記事を見てください。

引用:

QUOTENAME()とquotestring()を持つので、

、我々はパラメータ化コマンドを持っているように、我々はSQLインジェクションに対するとして良好な保護 を持っているのですか?多分。私は quotestring()または quotestring()を通過するSQLを挿入する方法を知らない。それにもかかわらず、ユーザ入力を SQL文字列に補間していますが、パラメータ化されたコマンドの場合はそうではありません。

1

文字列を連結してみてください。

の操作をCASE'ingてみましょう:

set @value = @xmlPath.value('(/EventSpecificData/' + @attribute + ')[1]', 'varchar(max)') 

は答えを更新しました。

SELECT @value = CASE @attribute 
     WHEN 'word' THEN [word] 
     WHEN 'occurrence' THEN [occurrence] 
     WHEN 'context' THEN [context] 
     END AS [value] 
FROM 
(
    SELECT x.u.value('(/EventSpecificData/Keyword/Word)[1]', 'varchar(max)') AS [word] 
     , x.u.value('(/EventSpecificData/Keyword/Occurrence)[1]', 'varchar(max)') AS [word] 
     , x.u.value('(/EventSpecificData/Keyword/Context)[1]', 'varchar(max)') AS [word] 
    FROM @xmlPath.nodes('/EventSpecificData') x(u) 
) a 
+1

応答をありがとう。これを行うと、「XMLデータ型メソッドの引数1」の値が文字列リテラルでなければならないというメッセージが表示されます。最初の引数がXQueryであるためです。 – user1200083

+1

@ user1200083:そのエラーメッセージにはすべてが記載されています。文字列リテラルが必要です。変数は使用できません。 –

+0

私はこのようにリテラルでsql変数を使用できます:select xmlPath.value( '(*/* [local-name()= sql:variable( "attribute1")])[1]'、 'varchar (MAX) ')を示しています。しかし、attribute1を 'Keyword/Word'に設定すると、結果は返されません。 xmlPath.value( '(*/* [local-name()= sql:variable( "attribute1")]/Word)[1]'、 'varchar(MAX)を選択するとスラッシュと関係があります。 ')は働きます。 – user1200083

関連する問題