FOR XML PATH i atrybut

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.

Advertisements

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s