2013-05-09 14 views
7

Mam następujące zapytanie SQL:odpytywanie które posiadają węzeł xmlns atrybuty

DECLARE @XMLDOC XML 
SET @XMLDOC = '<Feed><Product><Name>Foo</Name></Product></Feed>' 

SELECT x.u.value('Name[1]', 'varchar(100)') as Name 
from @XMLDOC.nodes('/Feed/Product') x(u) 

Powrócisz:

Name 
---- 
Foo 

Jednak jeśli węzeł <Feed> ma atrybut xmlns, to nie robi „t zwróciło żadnych wyników:

DECLARE @XMLDOC XML 
SET @XMLDOC = '<Feed xmlns="bar"><Product><Name>Foo</Name></Product></Feed>' 

SELECT x.u.value('Name[1]', 'varchar(100)') as Name 
from @XMLDOC.nodes('/Feed/Product') x(u) 

Returns:

Name 
---- 

Dzieje się tak tylko wtedy, gdy mam atrybut xmlns, wszystko inne działa poprawnie.

Dlaczego tak jest i jak mogę zmodyfikować moje zapytanie SQL, aby zwracać wyniki niezależnie od atrybutów?

Odpowiedz

8

Jeśli dokument XML ma przestrzeni nazw XML, to trzeba brać pod uwagę w zapytaniach!

Więc jeśli XML wygląda próbkę, to trzeba:

-- define the default XML namespace to use 
;WITH XMLNAMESPACES(DEFAULT 'bar') 
SELECT 
    x.u.value('Name[1]', 'varchar(100)') as Name 
from 
    @XMLDOC.nodes('/Feed/Product') x(u) 

Lub jeśli wolisz mieć bezpośrednią kontrolę nad tym, które XML namespace użyć (na przykład, jeśli masz wiele), należy użyć przedrostków przestrzeni nazw XML :

-- define the XML namespace 
;WITH XMLNAMESPACES('bar' as b) 
SELECT 
    x.u.value('b:Name[1]', 'varchar(100)') as Name 
from 
    @XMLDOC.nodes('/b:Feed/b:Product') x(u) 
+0

+1 Czy istnieje sposób na po prostu ignorowanie xmlns? Kusiło mnie, aby przekonwertować typ danych "XML" na ciąg znaków, usunąć atrybut xmlns, a następnie odrzucić go ... – Curt

+0

Naprawdę nie dbam o przestrzeń nazw, a to jest plik danych stron trzecich z wersjami na xmlns URL, więc jest podatny na zewnętrzne zmiany – Curt

+0

@Curt: nie, jeśli przestrzeń XML jest w twoim XML, nie możesz po prostu jej zignorować - musisz sobie z tym poradzić. Jeśli masz tylko jedną przestrzeń nazw XML - użyj podejścia nr 1, aby zdefiniować je jako domyślną przestrzeń nazw XML, która powinna być dość prosta i prosta w użyciu. –

1

Można define namespaces jak:

WITH XMLNAMESPACES ('bar' as b) 
SELECT x.u.value('b:Name[1]', 'varchar(100)') as Name 
FROM @XMLDOC.nodes('/b:Feed/b:Product') x(u) 
5

jak również rozwiązania XMLNAMESPACES, można również użyć potwornie gruby składni local-name ...

DECLARE @XMLDOC XML 
SET @XMLDOC = '<Feed xmlns="bar"><Product><Name>Foo</Name></Product></Feed>' 

SELECT x.u.value('*[local-name() = "Name"][1]', 'varchar(100)') as Name 
from @XMLDOC.nodes('/*[local-name() = "Feed"]/*[local-name() = "Product"]') x(u) 
+0

+1 Dzięki za alternatywne rozwiązanie. Poza tym, że jest on ohydny, czy jest to ciężki występ? – Curt

+0

Wyobrażam sobie! Ma on przewagę (a może nawet wady? :)) braku dbałości o przestrzeń nazw w przeciwieństwie do rozwiązania 'XMLNAMESPACES', które jest ukierunkowane na konkretny obszar nazw. –

+0

Co więcej - uważam, że parsowanie XML w SQLServer jest całkiem powolne, niezależnie od ... Może zrobię to źle! –

Powiązane problemy