É muito comum em cenário com XML ter situações que no cabeçalho do arquivo há “xmlns” e nós com prefixos “xsi:”, “xsd:” e entre outros, deixando o DBA ou desenvolvedor responsável pelas consultas confuso com o fato de consultas com simples XQueries não trazerem nenhum resultado.
Mesmo que o comportamento “padrão” nestes cenários na maioria das vezes é dar um REPLACE no cabeçalho do XML, vamos aprender como resolver esta situação de forma prática.
O XML que usarei para o exemplo possui um namespace bem comum para dados oriundos de aplicações como o http://tempuri.org/, que é o namespace padrão do exemplo (URL declarada com xmlns sem qualquer sufixo):
DECLARE @X XML
SET @X = '
<ArrayOfDsItem xmlns="http://tempuri.org/" xmlns:ns2="http://tempuri2.org/">
<DsItem Code="1" Value="ACRE" Value2="AC">
<ns2:Status>Não existe</ns2:Status>
</DsItem>
<DsItem Code="5" Value="BAHIA" Value2="BA" />
<DsItem Code="11" Value="MATO GROSSO" Value2="MT" />
<DsItem Code="13" Value="MINAS GERAIS" Value2="MG" />
<DsItem Code="19" Value="RIO DE JANEIRO" Value2="RJ" />
<DsItem Code="21" Value="RIO GRANDE DO SUL" Value2="RS" />
<DsItem Code="24" Value="SÃO PAULO" Value2="SP" />
</ArrayOfDsItem>'
Visto que estamos tratando de um namespace padrão, podemos determinar ou por T-SQL ou por XQuery, que este é o bendito namespace de todo o XML:
-- Definindo o namespace padrão
;WITH XMLNAMESPACES (DEFAULT 'http://tempuri.org/')
SELECT
E.value('@Value', 'varchar(25)') AS Estado,
E.value('@Value2', 'char(2)') AS Sigla
FROM @X.nodes('//ArrayOfDsItem/DsItem') AS N(E)
SELECT
E.value('@Value', 'varchar(25)') AS Estado,
E.value('@Value2', 'char(2)') AS Sigla
FROM @X.nodes('
declare default element namespace "http://tempuri.org/";
//ArrayOfDsItem/DsItem
') AS N(E)
Ou podemos criar um namespace sinônimo (ns), o que afetará um pouco a nossa XQuery:
-- Definindo um sinonimo para namespace padrão (ns)
;WITH XMLNAMESPACES ('http://tempuri.org/' AS ns)
SELECT
E.value('@Value', 'varchar(25)') AS Estado,
E.value('@Value2', 'char(2)') AS Sigla
FROM @X.nodes('//ns:ArrayOfDsItem/ns:DsItem') AS N(E)
SELECT
E.value('@Value', 'varchar(25)') AS Estado,
E.value('@Value2', 'char(2)') AS Sigla
FROM @X.nodes('
declare namespace ns = "http://tempuri.org/";
//ns:ArrayOfDsItem/ns:DsItem
') AS N(E)
Mas e agora, tenho dois ou mais namespaces no XML, o que podemos fazer? Podemos optar por qualquer uma das práticas anteriores (definindo um sinônimo ou definindo o namespace padrão) e mais os sinônimos para os namespaces secundários:
-- Definindo o namespace padrão e o sinonimo para o secundário (ns2)
;WITH XMLNAMESPACES (
DEFAULT 'http://tempuri.org/',
'http://tempuri2.org/' AS ns2
)
SELECT
E.value('@Value', 'varchar(25)') AS Estado,
E.value('@Value2', 'char(2)') AS Sigla,
E.value('ns2:Status[1]', 'varchar(25)') AS Comentario
FROM @X.nodes('//ArrayOfDsItem/DsItem') AS N(E)
SELECT
E.value('@Value', 'varchar(25)') AS Estado,
E.value('@Value2', 'char(2)') AS Sigla,
E.value('
declare namespace ns2 = "http://tempuri2.org/";
ns2:Status[1]
' , 'varchar(25)') AS Comentario
FROM @X.nodes('
declare default element namespace "http://tempuri.org/";
//ArrayOfDsItem/DsItem
') AS N(E)
-- Definindo sinonimos para namespace padrão (ns) e para o secundário (ns2)
;WITH XMLNAMESPACES (
'http://tempuri.org/' AS ns,
'http://tempuri2.org/' AS ns2
)
SELECT
E.value('@Value', 'varchar(25)') AS Estado,
E.value('@Value2', 'char(2)') AS Sigla,
E.value('ns2:Status[1]', 'varchar(25)') AS Comentario
FROM @X.nodes('//ns:ArrayOfDsItem/ns:DsItem') AS N(E)
SELECT
E.value('@Value', 'varchar(25)') AS Estado,
E.value('@Value2', 'char(2)') AS Sigla,
E.value('
declare namespace ns2 = "http://tempuri2.org/";
ns2:Status[1]
' , 'varchar(25)') AS Comentario
FROM @X.nodes('
declare namespace ns = "http://tempuri.org/";
//ns:ArrayOfDsItem/ns:DsItem
') AS N(E)
Ficou legal, não ficou? Mas nada te impede de colocar alguns REPLACEs na sua query e ser feliz…
No próximo artigo veremos com iniciar um pequeno caos com o FOR XML e Namespaces…