Avoid double nested elements while using FOR XML PATH

时间:2016-04-04 16:58:55

标签: sql sql-server xml

My stored procedure creates an XML (by taking all the inputs from the consumer) like the following:

<Event>
    <DataSource>Test</DataSource>
    <Name>SomeTable.Created</Name>
    <Context>SomeTable</Context>
    <ContextKey>
        <SomeFieldId>999</SomeFieldId>
        <SomeOtherFieldId>777</SomeOtherFieldId>
    </ContextKey>
</Event>

The ContextKey is an XML input that needs to be given by the consumer in this format:

<SomeFieldId>999</SomeFieldId>

(Then my stored procedure creates the above XML for me..)

But I have an important question here:

What if the consumer sends in the ContextKey xml like this:

   <ContextKey>
      <SomeFieldId>999</SomeFieldId>
    </ContextKey>

I don't want duplicates with TWO ContextKey elements... My stored procedure needs to omit the duplicated input and just create the "Event" xml with only one ContextKey element ..

Could someone suggest how I can put a condition so that even if the consumer sends in the XML inclusive of the attribute itself, my code should actually create the Event XML by only creating one element for ContextKey??

Hope my question is elaborated enough. Appreciate all your help! This is of much importance.

For more clarity:

This is how my XML PATH looks like inside my stored procedure:

SET NOCOUNT ON;
DECLARE @xml XML

SET @xml = (SELECT DataSource = @DataSource, 
                   Name = @EventName,
                   Context = @EventContext,
                   ContextKey = @EventContextKey
            FOR XML PATH('Event')) 

SET @Payload = @xml 

1 个答案:

答案 0 :(得分:0)

说实话,整个方法都有点气味......

但是 - 给你一个提示 - 你可以这样做

这里我定义了两个参数的替代方案,一个有一个,一个没有封闭元素:

DECLARE @prm1 XML='<SomeField>999</SomeField><SomeOtherField>000</SomeOtherField>';
DECLARE @prm2 XML='<ContextKey><SomeField>999</SomeField><SomeOtherField>000</SomeOtherField></ContextKey>';

这里我对两者都进行相同的处理:如果有一个元素ContextKey,那么将其内部参数作为 ......

SET @prm1=CASE WHEN @prm1.exist('//ContextKey')=1 THEN @prm1.query('//ContextKey/*') ELSE @prm1 END;
SET @prm2=CASE WHEN @prm2.exist('//ContextKey')=1 THEN @prm2.query('//ContextKey/*') ELSE @prm2 END;

现在您的查询

DECLARE @xml XML;
SET @xml = (SELECT DataSource = 'MyDataSource', 
                   Name = 'MyEventName',
                   Context = 'MyContext',
                   ContextKey1 = @prm1,
                   ContextKey2 = @prm2
            FOR XML PATH('Event'));

SELECT @xml;             

结果。你看,两个参数都以相同的方式处理并以相同的方式显示 - 即使它们在开始时它们也是不同的......

<Event>
  <DataSource>MyDataSource</DataSource>
  <Name>MyEventName</Name>
  <Context>MyContext</Context>
  <ContextKey1>
    <SomeField>999</SomeField>
    <SomeOtherField>000</SomeOtherField>
  </ContextKey1>
  <ContextKey2>
    <SomeField>999</SomeField>
    <SomeOtherField>000</SomeOtherField>
  </ContextKey2>
</Event>