2017-09-05 6 views
1

XMLデータを提供することによってAPIにアクセスする多くのアプリケーションがあります。ある時点で、NULLの値を均一な方法で値と区別できるように、NULLの値にxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"を使用することに決めました。宣言されたXML名前空間をリストしようとしています

xsi:nilへの移行がまだ進行中ですので、私はxsi -namespaceは、呼び出し側のアプリケーションがNULL - 値のためxsi:nil="true"を使用するかどうかの指標として宣言されているかどうかを伝えることができるようにしたいです。

私は

DECLARE @SomeXML xml = N'<ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><blubb><blah xsi:nil="true"/></blubb></ROOT>'; 

SELECT @SomeXML.exist('declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; //xsi:*, //@xsi:*'); 

を試みたが、名前空間が実際にXMLドキュメントで参照される場合にのみ動作します。 //@*:xsiのクエリだけで全く何も返さない間//@xmlns:*のようなクエリが

Msg 2229, Level 16, State 1, Line 6 
XQuery [query()]: The name "xmlns" does not denote a namespace. 

エラーにつながります。

SQL Server 2016で宣言されたXML名前空間を特定する方法はありますか?

答えて

0

私はOPENXMLを利用した名前空間を列挙するため、むしろ古い方法があることが、this threadから学んだ:

DECLARE @SomeXML xml = N'<ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.w3.org/2001/XMLSchema-instance"><blubb xmlns:xsiu="http://www.w3.org/2001/XMLSchema-instance"><blah xsi:nil="true"/></blubb></ROOT>'; 

DECLARE @hDoc int; 

EXEC sys.sp_xml_preparedocument 
    @hDoc OUTPUT, 
    @SomeXML; 

IF EXISTS (SELECT namespace = NULLIF(XmlnsAttribute.localname, 'xmlns'), 
        namespace_uri = XmlnsValue.text 
      FROM OPENXML(@hDoc, '//*') XmlnsAttribute 
      INNER JOIN OPENXML(@hDoc, '//*') XmlnsValue ON XmlnsValue.parentid = XmlnsAttribute.id 
      WHERE XmlnsAttribute.prefix = 'xmlns' 
        AND XmlnsValue.nodetype = 3 /*text*/ 
        AND CAST(XmlnsValue.text AS nvarchar(MAX)) = N'http://www.w3.org/2001/XMLSchema-instance') 
    PRINT 'Has http://www.w3.org/2001/XMLSchema-instance namespace'; 
ELSE 
    PRINT 'Does not have http://www.w3.org/2001/XMLSchema-instance namespace'; 

EXEC sys.sp_xml_removedocument 
    @hDoc; 

text列がタイプntextのものであり、sys.sp_xml_preparedocumentへの呼び出しとして、私は、これがどのようにエレガントな確信がもてませんsys.sp_xml_removedocumentは、これを他のクエリに含めるときに、もう少し注意を払う必要があることを意味します。おそらく最悪の欠点は、あなたはこのRBARを行う必要があるということです。

これは、キャストなしの解決方法です。xmlvarcharですので、スプーフィングするのは難しいはずです。

DECLARE @SomeXML xml = N'<ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.w3.org/2001/XMLSchema-instance"><blubb xmlns:xsiu="http://www.w3.org/2001/XMLSchema-instance"><blah xsi:nil="true"/></blubb></ROOT>'; 

DECLARE @hDoc int; 

EXEC sys.sp_xml_preparedocument 
    @hDoc OUTPUT, 
    @SomeXML; 

-- All registered namespaces 
WITH XmlNodes 
      AS (SELECT OX.id, 
         OX.parentid, 
         OX.nodetype, 
         OX.localname, 
         OX.prefix, 
         OX.text 
       FROM  OPENXML(@hDoc, '//*') OX) 
    SELECT namespace = NULLIF(XmlnsAttribute.localname, 'xmlns'), 
      namespace_uri = XmlnsValue.text 
    FROM XmlNodes XmlnsAttribute 
    INNER JOIN XmlNodes XmlnsValue ON XmlnsValue.parentid = XmlnsAttribute.id 
    WHERE XmlnsAttribute.prefix = 'xmlns' 
      AND XmlnsValue.nodetype = 3 
/*text*/; 

-- All registered namespaces with scope 
WITH XmlNodes 
      AS (SELECT OX.id, 
         OX.parentid, 
         OX.nodetype, 
         OX.localname, 
         OX.prefix, 
         OX.text 
       FROM  OPENXML(@hDoc, '//*') OX), 
     XmlNodesWithPath 
      AS (SELECT XN.id, 
         path = CAST(N'/' + ISNULL(XN.prefix + N':', N'') + XN.localname AS nvarchar(MAX)) 
       FROM  XmlNodes XN 
       WHERE  XN.parentid IS NULL 
       UNION ALL 
       SELECT XN.id, 
         path = XNWP.path + N'/' + ISNULL(XN.prefix + N':', N'') + XN.localname 
       FROM  XmlNodesWithPath XNWP 
       INNER JOIN XmlNodes XN ON XN.parentid = XNWP.id 
             AND XN.nodetype = 1) 
    SELECT scope = Scope.path, 
      namespace = NULLIF(XmlnsAttribute.localname, 'xmlns'), 
      namespace_uri = XmlnsValue.text 
    FROM XmlNodesWithPath Scope 
    INNER JOIN XmlNodes XmlnsAttribute ON XmlnsAttribute.parentid = Scope.id 
    INNER JOIN XmlNodes XmlnsValue ON XmlnsValue.parentid = XmlnsAttribute.id 
    WHERE XmlnsAttribute.prefix = 'xmlns' 
      AND XmlnsValue.nodetype = 3 
/*text*/; 

EXEC sys.sp_xml_removedocument 
    @hDoc; 
1

nvarcharに変換し、URIにCHARINDEXを実行するよりも優れた方法はないでしょうか。私はあなたが間違ったポジティブを起こす可能性は低いと思いますが、それは正しいと感じません。

DECLARE @SomeXML xml = N'<ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><blubb><blah xsi:nil="true"/></blubb></ROOT>' 

select CHARINDEX(N'"http://www.w3.org/2001/XMLSchema-instance"',CONVERT(nvarchar(max), @SomeXML)) 

(我々は異なるプレフィックスを文書内で使用されている場合でも、それを拾うように、私たちは、URI上だけで検索)

問題は、ほとんどのXMLツールは、それぞれ「文脈」ことを前提としていることである(たとえば、 XML文書、XPath式など)は、それに関連するネームスペースを導入するため、他の「コンテキスト」内のネームスペース宣言を探索するメカニズムは必要ありません。

+0

をそしてそれが正しい感じていないので、私は別の方法があることを期待して、SOに尋ねた:

すべての名前空間をリストD – TheConstructor

+0

を私は最終的にXML-機能を利用し解決策を見つけました。まだ完全に幸せではありません。 – TheConstructor

関連する問題