Para o caminho XML no SQL Server
-
21-09-2019 - |
Pergunta
NOTA: Eu resolvi a maioria desse problema, mas me deparei com um problema. Leia no fundo, por favor. Você verá onde eu adicionei uma seção (Nota). Tia.
Eu tenho uma consulta de junção bastante extensa que quero despejada no XML. Eu tenho quase funcionando, mas estou perdendo um conceito aqui em algum lugar. Minha consulta (abreviada) parece:
SELECT Campaign.CampaignId "Campaign/ID"
, Campaign.CompanyId "Campaign/CompanyID"
, Campaign.CampaignName "Campaign/Name"
...
, Audio.AudioID "Campaign/Audio/ID"
, Audio.[Name] "Campaign/Audio/Name"
...
, Video.CampaignVideosAudioMute "Campaign/Video/Audio/Mute"
, Video.CampaignVideosAudioVolume "Campaign/Video/Audio/Volume"
, Video.CampaignVideosPositionX "Campaign/Video/Position/X"
...
, Characters.CharacterID "Campaign/Characters/Character/ID"
, Characters.[Name] "Campaign/Characters/Character/Name"
...
, Element.ElementID "Campaign/Elements/Element/ID"
, Element.Editable "Campaign/Elements/Element/Editable"
...
, [Image].ImageID "Campaign/Elements/Element/Image/ID"
, [Image].[Path] "Campaign/Elements/Element/Image/Path"
...
, [Text].TextID "Campaign/Elements/Element/Text/ID"
, [Text].Value "Campaign/Elements/Element/Text/Value"
FROM vwCampaign Campaign
LEFT JOIN dbo.vwCampaignAudio Audio ON Campaign.CampaignId = Audio.CampaignId
LEFT JOIN dbo.vwCampaignCharacters Characters ON Campaign.CampaignId = Characters.CampaignId
LEFT JOIN dbo.vwCampaignVideo Video ON Campaign.CampaignId = Video.CampaignId
LEFT JOIN dbo.vwCampaignElements Element ON Campaign.CampaignId = Element.CampaignId
LEFT JOIN dbo.vwCampaignElementImage [Image] ON Element.CampaignId = [Image].CampaignId AND Element.ElementID = [Image].ElementID
LEFT JOIN dbo.vwCampaignElementText [Text] ON Element.CampaignId = [Text].CampaignId AND Element.ElementID = [Text].ElementID
WHERE Campaign.CampaignId = 10370
FOR XML PATH, ELEMENTS XSINIL
A maneira como os dados funcionam:
- 1 fila de campanha
- 1 fila de áudio - relacionada à linha da campanha
- 1 fila de vídeo - relacionada à linha da campanha
- Linhas de caracteres 1 -N - relacionadas à linha da campanha
- Linhas de elemento 1 -N - relacionadas à linha da campanha
- 0 ou 1 linhas de imagem - relacionadas a cada linha de elemento
- 0 ou 1 linhas de texto - relacionadas a cada linha de elemento
O XML está saindo como:
<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Campaign>
<ID>10370</ID>
<CompanyID>C2811EA3-361A-411A-BB4C-816A5D6C12DB</CompanyID>
<Name>Keith01</Name>
<URL>http://kab.rivworks.com/tests/kab02.htm</URL>
<Module>Coupon</Module>
<StartDate>2009-06-29T12:05:00</StartDate>
<EndDate>2021-06-30T18:00:00</EndDate>
<Notes>Test #1</Notes>
<Meta>D7E7D735-8D64-4127-84B1-7D72FB5EDD17</Meta>
<Orientation>Half-Body Left</Orientation>
<PresentationPlayerFlashVars>config=http://cdn1.deal4it.com/rivworks/demos/skymall/skymall-coupon-3.xml</PresentationPlayerFlashVars>
<Player>
<CookieIdentity>honirjymcvzk</CookieIdentity>
<Stage>
<Top></Top>
<Left></Left>
<Height>423</Height>
<Width>500</Width>
<MarginLeft></MarginLeft>
<Container>
<Background>
<Color>0xffffff</Color>
<Image></Image>
</Background>
</Container>
</Stage>
</Player>
<Audio>
<ID xsi:nil="true" />
<Name xsi:nil="true" />
<Path xsi:nil="true" />
<Meta xsi:nil="true" />
<Genre xsi:nil="true" />
</Audio>
<Video>
<ControlbarEvent>visible</ControlbarEvent>
<Event>play</Event>
<PresentationSkin>https://widgets.rivworks.com/player/latest/rivplayer.swf</PresentationSkin>
<Audio>
<Mute>False</Mute>
<Volume>100</Volume>
</Audio>
<Position>
<X>19</X>
<Y>140</Y>
</Position>
<About>
<Text>RIV Works</Text>
<Url>http://www.deal4it.com</Url>
</About>
<Size>
<Height>266</Height>
<Width>400</Width>
</Size>
<Settings>
<Autostart>True</Autostart>
<Buffer>1</Buffer>
<DelayPlay>0</DelayPlay>
<Item>0</Item>
<Quality>True</Quality>
<Repeat>none</Repeat>
</Settings>
</Video>
<Character>
<ID>19029FFC-C1C0-4134-B813-93A9FF17C7F6</ID>
<Name>Jenna</Name>
<Actor>CD5AF2B6-C39A-4316-BFB0-D4450194EC80</Actor>
<Meta>10041662-305F-4493-ACB3-460D687306A4</Meta>
<Access>Public</Access>
<Configuration>Individual</Configuration>
<ImageThumbnail>http://cdn1.deal4it.com/rivworks/images/headshots/jenna.jpg</ImageThumbnail>
<isPublic>1</isPublic>
<Demographics>
<Age>31 - 40</Age>
<Ethnicity>Caucasian</Ethnicity>
<Gender>Female</Gender>
</Demographics>
</Character>
<Elements>
<Element>
<ID>D9B2A643-73EC-4D55-BA34-D643113CEDEA</ID>
<Editable>1</Editable>
<Meta>D5F6175C-8DC7-4F18-9A5F-E2021579498B</Meta>
<Position>
<Level>2</Level>
<X>464</X>
<Y>21</Y>
</Position>
<Image>
<ID>90FF7F5A-75EC-4FB5-81B1-B9BEC4E8A22A</ID>
<Path>http://developer.rivworks.com/images/a5b19fe8-c8d3-4588-9eac-7cdf39b52078.jpg</Path>
<Link></Link>
<Target></Target>
<Meta>97261982-2131-41F7-9E2C-ADB10E31ED20</Meta>
<Size>
<Height>16</Height>
<Width>16</Width>
</Size>
</Image>
<Text>
<ID xsi:nil="true" />
<Value xsi:nil="true" />
<Link xsi:nil="true" />
<Target xsi:nil="true" />
<Meta xsi:nil="true" />
<FontColor xsi:nil="true" />
<FontFamily xsi:nil="true" />
<FontSize xsi:nil="true" />
</Text>
</Element>
</Elements>
</Campaign>
</row>
Infelizmente, tenho alguns problemas com isso.
- O elemento raiz ainda está no nível da linha. O elemento raiz deve ser
- Se eu tenho 3 caracteres e 3 elementos, acabo 9 elementos radiculares. A única coisa que muda de um elemento raiz para o próximo é qual personagem e qual elemento está mostrando. (E componha isso com cada elemento com 0 ou 1 textos e/ou imagens)
O XML deve sair parecendo algo como:
<campaign>
<ID>10370</ID>
<CompanyID>C2811EA3-361A-411A-BB4C-816A5D6C12DB</CompanyID>
<etc>...</etc>
<Characters>
<Character>
<data>...</data>
<Character>
<Character>
<data>...</data>
<Character>
</Characters>
<Elements>
<Element>
<data>...</data>
<Image>...</Image>
<Text>...</Text>
<Element>
<Element>
<data>...</data>
<Image>...</Image>
<Text>...</Text>
<Element>
</Elements>
</campaign>
O que eu preciso mudar? Preciso olhar para um método diferente de criar meu XML, talvez algum tipo de cláusula de nidificação?
NOTA: Depois de brincar e muitas pesquisas no Google/Bing, alterei minha consulta para que ela use consultas aninhadas. Aqui está o que parece agora:
SELECT Campaign.CampaignId "Campaign/ID"
, Campaign.CompanyId "Campaign/CompanyID"
, Campaign.CampaignName "Campaign/Name"
...
, Audio.AudioID "Campaign/Audio/ID"
, Audio.[Name] "Campaign/Audio/Name"
...
, Video.CampaignVideosControlbarEvent "Campaign/Video/ControlbarEvent"
, Video.CampaignVideosEvent "Campaign/Video/Event"
, (SELECT cc.CharacterID "Character/ID"
, cc.[Name] "Character/Name"
FROM dbo.vwCampaignCharacters cc
WHERE cc.CampaignID = Campaign.CampaignId
FOR XML PATH ('')
) AS "Campaign/Characters"
, (SELECT ce.ElementID "Element/ID"
, ce.Editable "Element/Editable"
, ce.Meta "Element/Meta"
, ce.PositionLevel "Element/Position/Level"
, ce.PositionX "Element/Position/X"
, ce.PositionY "Element/Position/Y"
, (SELECT cei.ImageID "Image/ID"
, cei.[Path] "Image/Path"
, cei.Link "Image/Link"
, cei.Target "Image/Target"
, cei.Meta "Image/Meta"
, cei.SizeHeight "Image/Size/Height"
, cei.SizeWidth "Image/Size/Width"
FROM dbo.vwCampaignElementImage cei
WHERE cei.CampaignID = ce.CampaignId
AND cei.ElementID = ce.ElementID
FOR XML PATH ('')
) AS "Element"
, (SELECT cet.TextID "ID"
, cet.Value "Value"
, cet.Link "Link"
, cet.Target "Target"
, cet.Meta "Meta"
, cet.FontColor "FontColor"
, cet.FontFamily "FontFamily"
, cet.FontSize "FontSize"
FROM dbo.vwCampaignElementText cet
WHERE cet.CampaignID = ce.CampaignId
AND cet.ElementID = ce.ElementID
FOR XML PATH ('Text')
) AS "Element"
FROM dbo.vwCampaignElements ce
WHERE ce.CampaignID = Campaign.CampaignId
FOR XML PATH ('Element')
) AS "Campaign/Elements"
FROM vwCampaign Campaign
LEFT JOIN dbo.vwCampaignAudio Audio ON Campaign.CampaignId = Audio.CampaignId
LEFT JOIN dbo.vwCampaignVideo Video ON Campaign.CampaignId = Video.CampaignId
WHERE Campaign.CampaignId = 10370
FOR XML PATH ('Campaign'), ROOT ('Campaigns'), ELEMENTS XSINIL
O XML está saindo quase perfeito agora exceto para a marcação das sub-questões.
<Campaigns xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Campaign>
<Campaign>
<ID>10370</ID>
<CompanyID>C2811EA3-361A-411A-BB4C-816A5D6C12DB</CompanyID>
<Name>Keith01</Name>
...
<Characters><Character><ID>19029FFC-C1C0-4134-B813-93A9FF17C7F6</ID><Name>Jenna</Name> ...
<Elements><Element><Element><ID>D9B2A643-73EC-4D55-BA34-D643113CEDEA</ID><Editable>1</Editable> ...
</Campaign>
</Campaign>
</Campaigns>
O personagem e as sub-inter-questões estão produzindo < /> em vez de < />, como se diz, URL Safe Markup? Eu não quero isso.
A imagem e a sub-sub-querros de imagem e texto estão produzindo & < / &> em vez de < />. Observe que foi tornado o URL seguro duas vezes! Eu também não quero isso.
Qualquer idéia de como obter a marcação real em vez disso porcaria. :)
Tia
Solução
Você provavelmente deve transferir a 'campanha' para o caminho:
SELECT Campaign.CampaignId "ID"
, Campaign.CompanyId "CompanyID"
, Audio.AudioID "Audio/ID"
, Audio.[Name] "Audio/Name"
...
FROM vwCampaign Campaign
LEFT JOIN dbo.vwCampaignAudio Audio
...
WHERE Campaign.CampaignId = 10370
FOR XML PATH('Campaign'), ELEMENTS XSINIL
Atualizar
Para o problema da suqueria, você precisa usar o FOR XML PATH(..),
TYPE
Para criar um valor XML digitado (em oposição a uma string contendo XML). Uma subconsulta XML digitada criará um elemento XML, uma string apenas inserirá o resultado como text () e será escapada.
select a, (select b from t for xml path("b"), type) as "*"
from ... for xml path("a")