MMDG
MMDG

Reputation: 83

Best way to generate XML using TSQL

The code below is wrong on so many levels I can't list them all. I imagine anyone trying to answer this would only make use of the test data table. Ha!

I've cobbled together several posts, bouncing between EXPLICIT, RAW and PATH and it's getting a little much.

I think someone who uses SQL to generate XML frequently would know this off the top of their head.

I don't have a preference for Ex, Raw or Path - I just need the best tool for the job. At the end of the day there will be 65 columns making up various levels of the final document.

I need code to query that table and generate this:

<batchContactList>
    <contact contactID="123" action="AddOrModify">
        <contactField name="FirstName">Johnny</contactField>
        <contactField name="LastName">Testguy</contactField>
        <contactPointList>
            <contactPoint type="Email">
            <contactPointField name="Label">Email</contactPointField>
            <contactPointField name="Address">[email protected]</contactPointField>
                </contactPoint>
             </contactPointList>
    </contact>
</batchContactList>

Test Code

--Test Data

DECLARE @tvTest TABLE (contactID INT, FirstName VARCHAR(25), LastName VARCHAR(25), [type] VARCHAR(25), [address] VARCHAR(25))
INSERT INTO @tvTest (contactID, FirstName, LastName, [type], [address])
SELECT 123, 'Johnny', 'Testguy', 'email', '[email protected]'
UNION
SELECT 321, 'Sally', 'Testgirl', 'email', '[email protected]';

--Outer
SELECT
      A.contactID AS "@contactID"
    , 'AddOrModify' AS "@action"
FROM 
    @tvTest A
FOR XML PATH('contact'), ROOT('batchContactList')

--Level 1
DECLARE @xmldata XML;
SELECT @xmldata = (SELECT contactID, FirstName, LastName FROM @tvTest FOR XML PATH (''));

SELECT
      ColumnName AS "@name"
    , ColumnValue AS "text()"
FROM
    (SELECT 
          i.value('local-name(.)','varchar(100)') ColumnName
        , i.value('.','varchar(100)') ColumnValue
    FROM 
        @xmldata.nodes('//*[text()]') x(i)) tmp
FOR XML PATH ('contactField'), ROOT('contact')

SELECT @xmldata = (SELECT contactID, [type], [address] FROM @tvTest FOR XML PATH (''));

--Level 2, not complete
SELECT
      ColumnName AS "@name"
    , ColumnValue AS "text()"
FROM
    (SELECT 
          i.value('local-name(.)','varchar(100)') ColumnName
        , i.value('.','varchar(100)') ColumnValue
    FROM 
        @xmldata.nodes('//*[text()]') x(i)) tmp
FOR XML PATH ('contactPoint'), ROOT('contactPointList')

Upvotes: 3

Views: 87

Answers (1)

Mikael Eriksson
Mikael Eriksson

Reputation: 138960

I use PATH, always.

Something like this should give you what you want.

select T.contactID as [@contactID],
       'AddOrModify' as [@Action],
       'FirstName' as [contactField/@name],
       T.FirstName as [contactField],
       null,
       'LastName' as [contactField/@name],
       T.LastName as [contactField],
       (
       select 'Email' as [contactPoint/@type],
              'Label' as [contactPointField/@name],
              T.type as [contactPointField],
              null,
              'Address' as [contactPointField/@name],
              T.address as [contactPointField]
       for xml path('contactPointList'), type
       )
from @tvTest as T
for xml path('contact'), root('catchContactList')

Result:

<catchContactList>
  <contact contactID="123" Action="AddOrModify">
    <contactField name="FirstName">Johnny</contactField>
    <contactField name="LastName">Testguy</contactField>
    <contactPointList>
      <contactPoint type="Email" />
      <contactPointField name="Label">email</contactPointField>
      <contactPointField name="Address">[email protected]</contactPointField>
    </contactPointList>
  </contact>
  <contact contactID="321" Action="AddOrModify">
    <contactField name="FirstName">Sally</contactField>
    <contactField name="LastName">Testgirl</contactField>
    <contactPointList>
      <contactPoint type="Email" />
      <contactPointField name="Label">email</contactPointField>
      <contactPointField name="Address">[email protected]</contactPointField>
    </contactPointList>
  </contact>
</catchContactList>

Upvotes: 6

Related Questions