Eu tenho um arquivo xml estruturado e digitado.
<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>
Além disso, o objeto SaleProperty pode estar ausente, em vez disso pode ser o objeto PurchaseProperty. Da mesma forma, o objeto Quote pode conter objetos Sale, Purchase, Remortgage ou sale e Purchase simultaneamente. Não consigo encontrar nenhuma dica sobre como inseri-lo em uma tabela via xquery no SQL Server 2012. até mesmo um valor (ou seja, transação), a única coisa, exceto erros, que recebo é uma string vazia.
minha consulta de amostra (baseada em exemplos do MSDN):
SELECT t.c.value('(.)[1]','varchar(50)') as type
from @ixml.nodes('/root/item/transaction') as t(c)
Eu gostaria de ter um exemplo de como inserir este xml na tabela (onde cada elemento possível tem sua própria coluna.
Presumo que o problema esteja nos namespaces e na digitação forte do xml. No entanto, é isso que recebo do serviço da web. Eu trabalho em xml faltando e contendo a segunda declaração xmlns no elemento raiz, bem como com a estrutura reduzida para apenas raiz.
Os três problemas com o seu XQuery que posso ver são (e nada disso tem nada a ver com o XML digitado):
Você não está especificando o caminho correto para o
/root
nó. Deveria ser:O XML diferencia maiúsculas de minúsculas, então você precisa usar um "T" maiúsculo para o nó "Transação":
Embora essas correções provavelmente recuperem 1 valor (neste caso, deve ser "SaleOnly"), ele não iterará pelos nós "item" porque você foi muito específico no caminho fornecido para a
.nodes()
função. Em vez disso, o nó final dessa especificação deve ser "item", que é o que você deseja iterar. E nesse caso, você move a parte "Transação" até a.value()
função:Sobre a declaração de:
A "estrutura cortada para apenas raiz" deve ser manuseada removendo tudo entre o primeiro
/
e o/
imediatamente anterior/root...
(ou seja, oWebService/NewLeads/OutputSchema
). Assim, o caminho resultante seria:OBSERVAÇÃO:
não consigo fazer isso funcionar 100% com o namespace declarado no
<WebService>
elemento ( consulte as notas adicionais, pois esse não é mais o caso ). Tirar isso faz funcionar. Dar um prefixo, comoxmlns:something="http://www.orbis-software.com/WebSvcCon"
fazê-lo funcionar, mas isso precisa ser declarado nos métodos. A única maneira de fazê-lo funcionar agora é declarando o namespace padrão em cada função XML (.nodes
e.value
) da seguinte forma:NOTA 2:
Melhor ainda, você pode usar
WITH XMLNAMESPACES
para declarar um ou mais namespaces para usar em toda a consulta, portanto não há necessidade de definir em cada função XML. Os dois a seguir funcionam:No entanto, lembre-se de que, se o documento não tiver o
<WebService xmlns="http://www.orbis-software.com/WebSvcCon">
elemento e, portanto, não tiver um namespace padrão, será necessário remover a;WITH XMLNAMESPACES
parte. Obviamente, se o<root>
elemento tiver seu próprio namespace padrão, talvez você precise mantê-lo. Você pode brincar com ele até que funcione, agora que você conhece a conexão entre essas peças.NOTA 3:
Se você acabar tendo dois namespaces padrão declarados -- um no
<WebService>
elemento e outro no<root>
elemento -- então você precisa especificar o URI anotado<root xmlns="bob">
e a//
sintaxe em vez do caminho totalmente qualificado. Portanto, se o seu XML se parecesse com:Você então usaria:
Mas isso não ajudará se você tiver o
<WebService>
elemento e ainda assim o<root>
elemento não tiver axmlns
declaração. Nesse caso, você ainda precisa especificar o namespace anotado no<WebService>
elemento. Diversão diversão diversão :-).NOTA 4: Ainda melhor: incorporando algo mencionado na resposta
de @wBob , podemos realmente nos livrar da cláusula e, em vez disso, usar um curinga de namespace. Você só precisa prefixar cada nó de cada função XML com . Agora a query deve ficar assim:
;WITH XMLNAMESPACES
*:
Isso significa que a consulta funciona em todos os seus cenários:
Estrutura completa começando com o nó "WebService", segunda declaração xmlns:
Estrutura completa começando com o nó "WebService", declaração xmlns única:
Estrutura reduzida começando com o nó "raiz", declaração xmlns única:
Se você deseja apenas despejar todos os valores de elemento como linhas, independentemente do namespace, pode usar um curinga de namespace, por exemplo:
Resultado:
Você poderia então fazer algo como pivô dinâmico se precisar transformar isso em colunas. Se você deseja especificar elementos explicitamente, pode usar uma técnica semelhante.
A julgar pela sua pergunta, você provavelmente precisará gastar mais tempo aprendendo sobre namespaces XML, então comece aqui:
Adicionando namespaces usando WITH XMLNAMESPACES http://msdn.microsoft.com/en-us/library/ms177400.aspx