Ace*_*ePL 4 xml sql-server sql-server-2012 xquery
我有一个结构化的、类型化的 xml 文件。
<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
<NewLeads>
<OutputSchema>
<root xmlns="" type="array">
<item type="object">
<SaleProperty type="object">
<Type type="string">Freehold</Type>
<PostDistrict type="string">xxx</PostDistrict>
<Address type="string">address</Address>
<Value type="number">17.0</Value>
</SaleProperty>
<Transaction type="string">SaleOnly</Transaction>
<Quote type="object">
<Sale type="object">
<Fees type="number">450.0</Fees>
<Disbursements type="number">0.0</Disbursements>
<StampDuty type="number">0.0</StampDuty>
<Total type="number">450.0</Total>
</Sale>
<Discount type="number">0.0</Discount>
<VAT type="number">90.0</VAT>
<Total type="number">540.0</Total>
</Quote>
<MoverId type="number">12345678</MoverId>
<Name type="string">Mr AS</Name>
<Email type="string">as@yahoo.ppp</Email>
<Telephone type="string">0123456789</Telephone>
<Comments type="string">Joint ownership</Comments>
<EstimatedMoveDate type="string">2015-11-25T05:57:00</EstimatedMoveDate>
<Charge type="number">4.99</Charge>
<ChargeStatus type="string">Chargeable</ChargeStatus>
</item>
</root>
</OutputSchema></NewLeads></WebService>
Run Code Online (Sandbox Code Playgroud)
此外,对象 SaleProperty 可能会丢失,而可能是对象 PurchaseProperty。类似地,对象 Quote 可以包含 Sale、Purchase、Remortgage 对象或同时包含 Sale 和 Purchase 我找不到任何关于通过 SQL Server 2012 上的 xquery 将其插入到一个表中的提示。基本问题是每次我构建查询以提取除了我得到的错误之外,即使是一个值(即交易)也是空字符串。
我的示例查询(基于 MSDN 示例):
SELECT t.c.value('(.)[1]','varchar(50)') as type
from @ixml.nodes('/root/item/transaction') as t(c)
Run Code Online (Sandbox Code Playgroud)
我想举一个例子,如何将这个 xml 插入到表中(每个可能的元素都有自己的列。
我认为问题在于命名空间和 xml 的强类型。但是,这是我从网络服务中得到的。我处理在根元素中缺少和包含第二个 xmlns 声明的 xml,以及将结构修剪为仅根。
我可以看到您的 XQuery 的三个问题是(这些都与它是类型化 XML 无关):
您没有指定正确的/root节点路径。它应该是:
SELECT t.c.value('(.)[1]','varchar(50)') as type
from @ixml.nodes('/WebService/NewLeads/OutputSchema/root/item/transaction') as t(c)
Run Code Online (Sandbox Code Playgroud)XML 区分大小写,因此您需要对“事务”节点使用大写的“T”:
SELECT t.c.value('(.)[1]','varchar(50)') as type
from @ixml.nodes('/WebService/NewLeads/OutputSchema/root/item/Transaction') as t(c)
Run Code Online (Sandbox Code Playgroud)虽然这些修复可能会让您返回 1 个值(在这种情况下,它应该是“SaleOnly”),但它不会遍历“item”节点,因为您在提供给.nodes()函数的路径中过于具体。相反,该规范的最后一个节点应该是“item”,这是您想要迭代的。在这种情况下,您将“交易”部分移到.value()函数上:
SELECT t.c.value('(./Transaction)[1]','varchar(50)') as type
from @ixml.nodes('/WebService/NewLeads/OutputSchema/root/item') as t(c)
Run Code Online (Sandbox Code Playgroud)关于声明:
我处理在根元素中缺少和包含第二个 xmlns 声明的 xml,以及将结构修剪为仅根。
通过删除第一个/和/右边之间的所有内容/root...(即WebService/NewLeads/OutputSchema),应该可以处理“修剪为根的结构” 。所以结果路径是:
from @ixml.nodes('//root/item') as t(c)
Run Code Online (Sandbox Code Playgroud)
注意:
我无法使用<WebService>元素中声明的命名空间使其 100% 工作(请参阅附加说明,因为情况不再如此)。把它拿出来让它工作。给它一个前缀,比如xmlns:something="http://www.orbis-software.com/WebSvcCon"让它工作,但是这需要在方法中声明。我现在让它工作的唯一方法是在每个 XML 函数 (.nodes和.value) 中声明默认命名空间,如下所示:
SELECT t.c.value('declare default element namespace "http://www.orbis-software.com/WebSvcCon";
(./Transaction)[1]','varchar(50)') as [type]
from @ixml.nodes('declare default element namespace "http://www.orbis-software.com/WebSvcCon";
/WebService/NewLeads/OutputSchema/root/item') as t(c)
Run Code Online (Sandbox Code Playgroud)
注意 2:
更好的是,您可以使用WITH XMLNAMESPACES声明一个或多个命名空间以用于整个查询,因此无需在每个 XML 函数中定义。以下两者都有效:
;WITH XMLNAMESPACES (DEFAULT 'http://www.orbis-software.com/WebSvcCon')
SELECT t.c.value('(./Transaction)[1]','varchar(50)') as [type]
from @ixml.nodes('/WebService/NewLeads/OutputSchema/root/item') as t(c)
;WITH XMLNAMESPACES (DEFAULT 'http://www.orbis-software.com/WebSvcCon')
SELECT t.c.value('(./Transaction)[1]','varchar(50)') as [type]
from @ixml.nodes('//root/item') as t(c)
Run Code Online (Sandbox Code Playgroud)
但是,请记住,如果文档缺少该<WebService xmlns="http://www.orbis-software.com/WebSvcCon">元素,因此没有默认命名空间,那么您需要删除该;WITH XMLNAMESPACES部分。当然,如果<root>元素有自己的默认命名空间,那么也许你需要保留它。既然你知道这些部分之间的联系,你就可以玩弄它直到它起作用。
注3:
如果你最终有两个默认命名空间中声明-一个在<WebService>元素,一个在<root>元素-那么你需要指定URI中指出<root xmlns="bob"> ,并在//语法,而不是完全合格的路径。因此,如果您的 XML 如下所示:
<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
<NewLeads>
<OutputSchema>
<root xmlns="http://someplace" type="array">
Run Code Online (Sandbox Code Playgroud)
然后你会使用:
;WITH XMLNAMESPACES (DEFAULT 'http://someplace')
SELECT t.c.value('(./Transaction)[1]','varchar(50)') as [type]
from @ixml.nodes('//root/item') as t(c)
Run Code Online (Sandbox Code Playgroud)
但是,如果您确实拥有该<WebService>元素但该<root>元素缺少xmlns声明,那将无济于事。在这种情况下,您仍然需要指定<WebService>元素中注明的命名空间。有趣,有趣,有趣:-)。
注意 4:
更好:结合@wBob 的回答中提到的内容,我们实际上可以摆脱该;WITH XMLNAMESPACES子句,而是使用命名空间通配符。您只需要在每个XML 函数的每个节点前加上. 现在查询应如下所示:*:
SELECT t.c.value('(./*:Transaction)[1]','varchar(50)') AS [type],
t.c.value('(./*:SaleProperty/*:PostDistrict)[1]','varchar(50)') AS [PostDistrict]
FROM @ixml.nodes('//*:root/*:item') t(c);
Run Code Online (Sandbox Code Playgroud)
这样做意味着查询适用于您的所有场景:
从“WebService”节点开始的完整结构,第二个 xmlns 声明:
<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
<NewLeads>
<OutputSchema>
<root xmlns="uri" type="array">
Run Code Online (Sandbox Code Playgroud)以“WebService”节点开始的完整结构,单个 xmlns 声明:
<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
<NewLeads>
<OutputSchema>
<root type="array">
Run Code Online (Sandbox Code Playgroud)从“根”节点开始的精简结构,单个 xmlns 声明:
<root xmlns="uri" type="array">
Run Code Online (Sandbox Code Playgroud)如果您只想将所有元素值转储为行,而不考虑命名空间,则可以使用命名空间通配符,例如:
DECLARE @xml XML = '<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
<NewLeads>
<OutputSchema>
<root xmlns="" type="array">
<item type="object">
<SaleProperty type="object">
<Type type="string">Freehold</Type>
<PostDistrict type="string">xxx</PostDistrict>
<Address type="string">address</Address>
<Value type="number">17.0</Value>
</SaleProperty>
<Transaction type="string">SaleOnly</Transaction>
<Quote type="object">
<Sale type="object">
<Fees type="number">450.0</Fees>
<Disbursements type="number">0.0</Disbursements>
<StampDuty type="number">0.0</StampDuty>
<Total type="number">450.0</Total>
</Sale>
<Discount type="number">0.0</Discount>
<VAT type="number">90.0</VAT>
<Total type="number">540.0</Total>
</Quote>
<MoverId type="number">12345678</MoverId>
<Name type="string">Mr AS</Name>
<Email type="string">as@yahoo.ppp</Email>
<Telephone type="string">0123456789</Telephone>
<Comments type="string">Joint ownership</Comments>
<EstimatedMoveDate type="string">2015-11-25T05:57:00</EstimatedMoveDate>
<Charge type="number">4.99</Charge>
<ChargeStatus type="string">Chargeable</ChargeStatus>
</item>
</root>
</OutputSchema>
</NewLeads>
</WebService>'
-- Show all elements and their values irrespective of namespace
SELECT
x.y.value('local-name(..)', 'VARCHAR(MAX)') parentElementName,
x.y.value('local-name(.)', 'VARCHAR(MAX)') elementName,
x.y.value('.', 'VARCHAR(MAX)') elementValue
FROM @xml.nodes('//*[not(*)]') AS x(y)
SELECT
ws.c.value('local-name(..)', 'VARCHAR(MAX)') parentElementName,
ws.c.value('local-name(.)', 'VARCHAR(MAX)') elementName,
ws.c.value('.', 'VARCHAR(MAX)') elementValue
FROM @xml.nodes('*:WebService/*:NewLeads/*:OutputSchema/*:root/*:item/*[not(*)]') AS ws(c)
Run Code Online (Sandbox Code Playgroud)
结果:
如果您需要将其转换为列,您可以执行诸如动态透视之类的操作。如果您确实想明确指定元素,则可以使用类似的技术。
从你的问题来看,你可能需要花更多的时间来学习 XML 命名空间,所以从这里开始:
使用WITH XMLNAMESPACES 添加命名空间 http://msdn.microsoft.com/en-us/library/ms177400.aspx
| 归档时间: |
|
| 查看次数: |
11914 次 |
| 最近记录: |