構造化され、型指定された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">[email protected]</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>
さらに、オブジェクトSalePropertyが欠落している可能性があり、代わりにオブジェクトPurchasePropertyである可能性があります。同様に、オブジェクトQuoteには、Sale、Purchase、Remortgageオブジェクト、またはsalesとPurchaseを同時に含めることができます。SQLServer 2012のxqueryを介して1つのテーブルに挿入するためのヒントが見つかりません。基本的な問題は、抽出するクエリを構築するたびに1つの値(トランザクション)でも、エラー以外は空の文字列です。
私のサンプルクエリ(MSDNの例に基づく):
SELECT t.c.value('(.)[1]','varchar(50)') as type
from @ixml.nodes('/root/item/transaction') as t(c)
このxmlをテーブルに挿入する方法の例を示します(可能なすべての要素に独自の列があります)。
名前空間とxmlの厳密な型指定に問題があると思います。ただし、これは私がWebサービスから取得するものです。欠落していて、ルート要素に2番目のxmlns宣言が含まれているxmlと、ルートだけにトリミングされた構造に取り組んでいます。
私が見ることができるXQueryの3つの問題は次のとおりです(これは型付きXMLとは何の関係もありません)。
/root
ノードへの正しいパスを指定していません。そのはず:
SELECT t.c.value('(.)[1]','varchar(50)') as type
from @ixml.nodes('/WebService/NewLeads/OutputSchema/root/item/transaction') as t(c)
XMLでは大文字と小文字が区別されるため、「Transaction」ノードには大文字の「T」を使用する必要があります。
SELECT t.c.value('(.)[1]','varchar(50)') as type
from @ixml.nodes('/WebService/NewLeads/OutputSchema/root/item/Transaction') as t(c)
これらの修正により、おそらく1つの値が返されますが(この場合は、 "SaleOnly"になるはずです)、.nodes()
に指定されたパスが具体的すぎるため、「item」ノードを反復しません。関数。代わりに、その仕様の最後のノードは「アイテム」である必要があります。これは、繰り返し処理したいものです。その場合は、「トランザクション」の部分を.value()
関数まで移動します。
SELECT t.c.value('(./Transaction)[1]','varchar(50)') as type
from @ixml.nodes('/WebService/NewLeads/OutputSchema/root/item') as t(c)
次のステートメントについて:
欠落していて、ルート要素に2番目のxmlns宣言が含まれているxmlと、ルートだけにトリミングされた構造に取り組んでいます。
「ルートだけにトリミングされた構造」は、最初の/
と/
の直前の/root...
の間のすべてを削除することで処理できます(つまり、WebService/NewLeads/OutputSchema
)。したがって、結果のパスは次のようになります。
from @ixml.nodes('//root/item') as t(c)
注:<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)
注2:
さらに良いことに、WITH XMLNAMESPACES
を使用して、クエリ全体に使用する1つ以上の名前空間を宣言できるため、各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)
ただし、ドキュメントに<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
要素がなく、デフォルトの名前空間がない場合は、;WITH XMLNAMESPACES
の部分を削除する必要があることに注意してください。もちろん、<root>
要素に独自のデフォルトの名前空間がある場合は、それを維持する必要があります。動作するまで、これらの要素間の関係がわかったので、いじってみてください。
注3:
2つのデフォルト名前空間が宣言されてしまう場合は、1つは<WebService>
要素で、もう1つは<root>
要素で、<root xmlns="bob">
および完全修飾パスの代わりに//
構文。したがって、XMLが次のようになっているとします。
<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
<NewLeads>
<OutputSchema>
<root xmlns="http://someplace" type="array">
次に、以下を使用します。
;WITH XMLNAMESPACES (DEFAULT 'http://someplace')
SELECT t.c.value('(./Transaction)[1]','varchar(50)') as [type]
from @ixml.nodes('//root/item') as t(c)
ただし、<WebService>
要素があり、<root>
要素にxmlns
宣言がない場合、これは役に立ちません。その場合でも、<WebService>
要素に記載されている名前空間を指定する必要があります。楽しい楽しい楽しい :-)。
注4:
さらに改善:@wBobの answer で言及されたものを組み込むと、実際に;WITH XMLNAMESPACES
句を取り除くことができ、代わりに名前空間ワイルドカードを使用できます。 everyノードのeveryXML関数の前に*:
を付けるだけです。これで、クエリは次のようになります。
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);
これにより、クエリはすべてのシナリオで機能します。
「WebService」ノードで始まる完全な構造、2番目のxmlns宣言:
<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
<NewLeads>
<OutputSchema>
<root xmlns="uri" type="array">
「WebService」ノードで始まる完全な構造、単一のxmlns宣言:
<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
<NewLeads>
<OutputSchema>
<root type="array">
「ルート」ノードで始まる構造をトリミングし、単一のxmlns宣言:
<root xmlns="uri" type="array">
名前空間に関係なく、すべての要素の値を行としてダンプする場合は、名前空間のワイルドカードを使用できます。例:
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">[email protected]</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)
結果:
これを列に変換する必要がある場合は、動的ピボットなどを実行できます。要素を明示的に指定したい場合は、同様の手法を使用できます。
あなたの質問から判断すると、おそらくXML名前空間についてより多くの時間を費やす必要があるので、ここから始めます:
WITH XMLNAMESPACESを使用して名前空間を追加する http://msdn.Microsoft.com/en-us/library/ms177400.aspx