To jest wpis z rodzaju „dopadło mnie zaćmienie, jak kiedyś będę miał znów problem to zajrzę na bloga, czy nie pisałem na ten temat”.
Przy tworzeniu dokumentu XML za pomocą FOR XML PATH
możemy podać nazwę elementu, który ma „opakowywać” każdy zwracany rekord (jeśli nie podamy będzie domyślne <row>
). A co jeśli potrzebujemy dodać atrybut do elementu „opakowującego”?
Taki przykład:
IF OBJECT_ID(N'dbo.Kontrahent', N'U') IS NOT NULL EXEC sp_executesql N'DROP TABLE dbo.Kontrahent'; GO CREATE TABLE dbo.Kontrahent ( Id INT NOT NULL, Nazwa VARCHAR(150) NOT NULL, NIP CHAR(10) NOT NULL, REGON CHAR(9) NOT NULL ); GO INSERT INTO dbo.Kontrahent (Id, Nazwa, NIP, REGON) VALUES (1, 'Firma1', '1234567890', '123456789'), (2, 'Firma2', '2345678901', '234567890'), (3, 'Firma3', '3456789012', '345678901'), (4, 'Firma4', '4567890123', '456789012') ; GO SELECT * FROM dbo.Kontrahent FOR XML PATH SELECT * FROM dbo.Kontrahent FOR XML PATH('') SELECT * FROM dbo.Kontrahent FOR XML PATH('Kontrahent')
W wyniku otrzymamy trzy dokumenty XML
<row> <Id>1</Id> <Nazwa>Firma1</Nazwa> <NIP>1234567890</NIP> <REGON>123456789</REGON> </row> <row> <Id>2</Id> <Nazwa>Firma2</Nazwa> <NIP>2345678901</NIP> <REGON>234567890</REGON> </row> <row> <Id>3</Id> <Nazwa>Firma3</Nazwa> <NIP>3456789012</NIP> <REGON>345678901</REGON> </row> <row> <Id>4</Id> <Nazwa>Firma4</Nazwa> <NIP>4567890123</NIP> <REGON>456789012</REGON> </row> <Id>1</Id> <Nazwa>Firma1</Nazwa> <NIP>1234567890</NIP> <REGON>123456789</REGON> <Id>2</Id> <Nazwa>Firma2</Nazwa> <NIP>2345678901</NIP> <REGON>234567890</REGON> <Id>3</Id> <Nazwa>Firma3</Nazwa> <NIP>3456789012</NIP> <REGON>345678901</REGON> <Id>4</Id> <Nazwa>Firma4</Nazwa> <NIP>4567890123</NIP> <REGON>456789012</REGON> <Kontrahent> <Id>1</Id> <Nazwa>Firma1</Nazwa> <NIP>1234567890</NIP> <REGON>123456789</REGON> </Kontrahent> <Kontrahent> <Id>2</Id> <Nazwa>Firma2</Nazwa> <NIP>2345678901</NIP> <REGON>234567890</REGON> </Kontrahent> <Kontrahent> <Id>3</Id> <Nazwa>Firma3</Nazwa> <NIP>3456789012</NIP> <REGON>345678901</REGON> </Kontrahent> <Kontrahent> <Id>4</Id> <Nazwa>Firma4</Nazwa> <NIP>4567890123</NIP> <REGON>456789012</REGON> </Kontrahent>
Przy samym FOR XML PATH
generowany jest domyślny element <row>
. Możemy go wyeliminować podając pusty ciąg znaków – FOR XML PATH('')
lub nazwać po swojemu – FOR XML PATH('Kontrahent')
. A teraz – jak do tego elementu Kontrahent
dodać atrybut?
Ogólnie bardzo prosto – wystarczy dodać na początku kolumnę z nazwą atrybutu i oznaczoną jako atrybut – czyli ze znakiem małpy. Np. jeśli chciałbym do elementu <Kontrahent>
dodać atrybut typ="A"
, to wystarczy, że na początku dodam jeden wpis:
SELECT '@typ' = 'A', k.* FROM dbo.Kontrahent k FOR XML PATH('Kontrahent')
Co daje:
<Kontrahent typ="A"> <Id>1</Id> <Nazwa>Firma1</Nazwa> <NIP>1234567890</NIP> <REGON>123456789</REGON> </Kontrahent> <Kontrahent typ="A"> <Id>2</Id> <Nazwa>Firma2</Nazwa> <NIP>2345678901</NIP> <REGON>234567890</REGON> </Kontrahent> <Kontrahent typ="A"> <Id>3</Id> <Nazwa>Firma3</Nazwa> <NIP>3456789012</NIP> <REGON>345678901</REGON> </Kontrahent> <Kontrahent typ="A"> <Id>4</Id> <Nazwa>Firma4</Nazwa> <NIP>4567890123</NIP> <REGON>456789012</REGON> </Kontrahent>
Ważne, żeby atrybut dać na początku listy SELECT
, bo inaczej otrzymamy komunikat
Msg 6852, Level 16, State 1, Line 68
Attribute-centric column ‚@typ’ must not come after a non-attribute-centric sibling in XML hierarchy in FOR XML PATH.
Gdybym chciał dodać atrybut do elementu ROOT, to już niestety się tak nie da. O tym jak to obejść innym razem.