Sql server 如何在SQL中使用xml命名空间通配符(表中的多个xml文件具有不同的命名空间url)
我有一个SQL文件表,其中存储了多个xml文件以供SQL使用。 xml文件的内容超出了我的控制范围。我只需要将它们用作表的输入。 所有xml文件都具有相同的结构/设置。唯一的问题是,我刚刚意识到其中一些xml文件具有不同的名称空间url(因此在我的表中返回NULL) 我使用xml文件创建一个表,其中xml中的键作为列返回,属性作为行中的值返回。每个xml都作为行返回 所以我现在遇到的问题是,对于名称空间(稍微)不同的所有xml,整行返回NULL 使用的名称空间包括: 和 我使用的查询:Sql server 如何在SQL中使用xml命名空间通配符(表中的多个xml文件具有不同的命名空间url),sql-server,xml,tsql,Sql Server,Xml,Tsql,我有一个SQL文件表,其中存储了多个xml文件以供SQL使用。 xml文件的内容超出了我的控制范围。我只需要将它们用作表的输入。 所有xml文件都具有相同的结构/设置。唯一的问题是,我刚刚意识到其中一些xml文件具有不同的名称空间url(因此在我的表中返回NULL) 我使用xml文件创建一个表,其中xml中的键作为列返回,属性作为行中的值返回。每个xml都作为行返回 所以我现在遇到的问题是,对于名称空间(稍微)不同的所有xml,整行返回NULL 使用的名称空间包括: 和 我使用的查询: WIT
WITH XMLNAMESPACES('http://schemas.kvk.nl/xb/query/service/2016/1/0/0' AS ns2) -- Pull namespaces for NS2
SELECT p.*
FROM
(
SELECT [name]
,x.l.value('(ns2:opendataField[@key="SbiBusinessCode"]/@value)[1]','varchar(max)') AS SBI
,x.l.value('(ns2:opendataField[@key="FinancialYear"]/@value)[1]','varchar(max)') AS FY
from dbo.XBRLft t -- filestream table
CROSS APPLY(SELECT CAST(t.[file_stream] AS XML)) A(xbrl) -- convert filestream into xml.
CROSS APPLY xbrl.nodes('/opendata') x(l)
where x.l.exist('./*/@key')=1
) p
这将返回仅包含第一个名称空间值的表(因为在查询中使用了该名称空间),但基于具有第二个名称空间的xml的每一行都返回null
所以我尝试使用通配符而不是名称空间,但这只会返回错误
SELECT p.*
FROM
(
SELECT [name]
-- Putting all key's as columns and showing the attribute value in row.
,x.l.value('(//*:ns2:opendataField[@key="FinancialYear"]/@value)[1]','varchar(max)') AS FY
from dbo.XBRLft t -- filestream table
CROSS APPLY(SELECT CAST(t.[file_stream] AS XML)) A(xbrl) --
CROSS APPLY xbrl.nodes('//*:opendata') x(l) --
where x.l.exist('./*/@key')=1 --
) p
查询中还有更多的键,但在本例中,这些键被忽略了
我可以通过应用2个名称空间url或修复通配符来实现这一点吗
更新
以下是2个示例(每个XML中有1个具有不同名称空间)。我不确定是否可以使用COALESCE,因为这两个XML版本在整个XML中都使用ns2(我需要在查询中添加整个路径以获得不同的键/值,因为XML是分层的)
XML 1:
<opendata xmlns:ns2="http://schemas.kvk.nl/xb/query/service/2016/1/0/0">
<ns2:opendataField key="DocumentAdoptionDate" value="2017-08-27" />
<ns2:opendataField key="FinancialYear" value="2016" />
<ns2:opendataField key="BalanceSheet">
<ns2:opendataField key="BalanceSheetBeforeAfterAppropriationResultsTitle">
<ns2:opendataField key="BalanceSheetBeforeAfterAppropriationResults" value="Na" />
</ns2:opendataField>
<ns2:opendataField key="BalanceSheetTitle">
<ns2:opendataField key="Assets" value="548985">
<ns2:opendataField key="AssetsNoncurrent" value="447571">
<ns2:opendataField key="PropertyPlantEquipment" value="208215" />
<ns2:opendataField key="FinancialAssets" value="239355" />
</ns2:opendataField>
<ns2:opendataField key="AssetsCurrent" value="101414">
<ns2:opendataField key="Receivables" value="68895" />
<ns2:opendataField key="CashAndCashEquivalents" value="32519" />
</ns2:opendataField>
</ns2:opendataField>
etc etc
我不确定如何在这里应用您的合并示例,因为这两种XML类型都有ns2,我需要完整的路径
再次感谢 需要名称空间来避免相等名称之间的歧义。从这个角度来看,使用通配符可能非常危险,并可能导致意外的结果 试试这个: 包含一些测试数据的虚拟表
DECLARE @tbl TABLE(id INT IDENTITY, YourXml XML);
INSERT INTO @tbl VALUES
('<root xmlns="blah1">
<test>Test in 1</test>
</root>'),
('<root xmlns="blah2">
<test>Test in 2</test>
</root>');
--但我们可以使用两个带前缀的名称空间,并使用COALESCE返回返回值的名称空间:
WITH XMLNAMESPACES('blah1' AS ns1
,'blah2' AS ns2)
SELECT t.id
,COALESCE(
t.YourXml.value('(/ns1:root/ns1:test/text())[1]','nvarchar(100)')
,t.YourXml.value('(/ns2:root/ns2:test/text())[1]','nvarchar(100)')
) AS ContentOfTest
FROM @tbl t
--如果可以确定,这是使用通配符的方法,不会导致歧义:
SELECT t.id
,t.YourXml.value('(/*:root/*:test/text())[1]','nvarchar(100)') AS ContentOfTest
FROM @tbl t
我真的很感激这一步一步的过程。非常好的回答!非常感谢您的详细解释和反馈。为我的延迟回复道歉,我在度假。我相信联合会是个好主意。但是,我不确定它是否能与我需要使用的XML一起工作。我已经更新了我的初始问题,以包含2个XML版本的示例。@jmhrijdt您不必绑定前缀。事实上,你可以使用任何你喜欢的前缀。只需将
作为ns1
用于其中一个,将作为ns2
用于另一个,然后在XPath中一致地使用它们。希望这有帮助…@Shnugo,那么你的意思是我需要修改这两个选项的XPath吗?@jmhrijdt完全正确。使用任何前缀声明它们,并在路径中使用此前缀。
WITH XMLNAMESPACES(DEFAULT 'blah1')
SELECT t.id
,t.YourXml.value('(/root/test/text())[1]','nvarchar(100)') AS ContentOfTest
FROM @tbl t;
WITH XMLNAMESPACES('blah1' AS ns1
,'blah2' AS ns2)
SELECT t.id
,COALESCE(
t.YourXml.value('(/ns1:root/ns1:test/text())[1]','nvarchar(100)')
,t.YourXml.value('(/ns2:root/ns2:test/text())[1]','nvarchar(100)')
) AS ContentOfTest
FROM @tbl t
SELECT t.id
,t.YourXml.value('(/*:root/*:test/text())[1]','nvarchar(100)') AS ContentOfTest
FROM @tbl t