2017-09-05 79 views
1

我們有許多應用程序通過提供XML數據來訪問我們的API。在某個時候,我們決定使用xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"來傳入NULL-值,以便能夠以統一的方式區分空值和NULL值。嘗試列出已聲明的XML名稱空間

因爲要xsi:nil過渡還在進行中,我希望能夠告訴xsi - 命名空間是否被聲明爲的調用應用程序是否會使用xsi:nil="true"NULL - 值的指標。

我試圖

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文檔中的命名空間實際上是指這隻會工作。像//@xmlns:*查詢導致錯誤

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

//@*:xsi查詢只是返回什麼都沒有。

有什麼方法可以確定SQL Server 2016中聲明的XML名稱空間嗎?

回答

0

我從this thread中瞭解到,還有一個比較舊的方式來枚舉命名空間利用OPENXML:我不清楚如何優雅,這是

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

我不確定在URI上轉換爲nvarchar並執行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