2013-05-09 6 views
7

Ho la seguente query SQL:Interrogazione tipi di dati XML che hanno il nodo xmlns attributi

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) 

Ciò restituisce:

Name 
---- 
Foo 

Tuttavia, se il mio nodo <Feed> ha un attributo xmlns, allora questo doesn Non restituire alcun risultato:

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) 

Resi:

Name 
---- 

Questo succede solo se ho un attributo xmlns, qualsiasi altra cosa funziona correttamente.

Perché è questo e come posso modificare la query SQL per restituire i risultati indipendentemente dagli attributi?

risposta

8

Se il documento XML ha namespace XML, quindi è necessario prendere in considerazione quelli nelle query!

Così, se il XML si presenta come il campione, allora avete bisogno:

-- 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) 

O se si preferisce avere il controllo esplicito su cui namespace XML da utilizzare (ad esempio, se si dispone di più), utilizzare prefissi di namespace 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 C'è un modo per ignorare semplicemente xmlns? Avevo la tentazione di convertire il tipo di dati 'XML' in una stringa, rimuovere l'attributo xmlns e quindi richiamarlo ... – Curt

+0

Non mi interessa davvero lo spazio dei nomi, e questo è un feed di terze parti con versioning sul xmlns URL, quindi è soggetto a modifiche esterne – Curt

+0

@Curt: no, quando lo spazio dei nomi XML è presente nel tuo XML, non puoi semplicemente ignorarlo - devi occupartene. Se si ha solo uno spazio dei nomi XML, utilizzare l'approccio n. 1 per definirlo come spazio dei nomi XML predefinito e che dovrebbe essere abbastanza semplice e immediato da utilizzare. –

1

È possibile define namespaces come:

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

così come la soluzione XMLNAMESPACES, è anche possibile utilizzare il orrendamente ingombranti local-name sintassi ...

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 Grazie per la soluzione alternativa. A parte essere orribile, è così pesante sulle prestazioni? – Curt

+0

Lo immaginerei! Ha il vantaggio (o forse lo svantaggio? :)) di non preoccuparsi dello spazio dei nomi, a differenza della soluzione 'XMLNAMESPACES' che si rivolge in modo specifico a un determinato spazio dei nomi. –

+0

Inoltre, trovo che l'analisi XML in SQLServer sia piuttosto dannatamente lento, a prescindere ... Forse lo faccio male! –

Problemi correlati