I am trying to add an attribute if it does not exist. It should be simple, but I am new to XML XPath/XQuery/etc., so excuse my ignorance.
I want to be able to pass XML data and modify it...
ALTER FUNCTION [dbo].[ConvertXmlData](@xmlData XML)
RETURNS XML
AS
BEGIN
RETURN @xmlData.<something here>
END
If I pass data like:
<something>
this is sample data <xxx id="1"/> and <xxx id="2" runat="server" />. More <yyy id="3" />
</something>
I would like
<something>
this is sample data <xxx id="1" runat="server" /> and <xxx id="2" runat="server" />. More <yyy id="3" />
</something>
And not :
<something>
this is sample data <xxx id="1" runat="server" /> and <xxx id="2" runat="server" runat="server"/>. More <yyy id="3" />
</something>
You can do
SET @xmlData.modify('insert attribute runat { "server" } into descendant::xxx[not(@runat)][1]');
This will however only change the first xxx
descendant not having a runat attribute, at least with SQL Server 2005 you can only modify one node at a time.
Maybe combining the above with a WHILE helps e.g.
WHILE @xmlData.exist('descendant::xxx[not(@runat)]') = 1
BEGIN
SET @xmlData.modify('insert attribute runat { "server" } into descendant::xxx[not(@runat)][1]');
END
I don't have access to SQL Server 2008 R2 but I think the modify is still limited to one node at a time so you could try
ALTER FUNCTION [dbo].[ConvertXmlData](@xmlData XML)
RETURNS XML
AS
BEGIN
WHILE @xmlData.exist('descendant::xxx[not(@runat)]') = 1
BEGIN
SET @xmlData.modify('insert attribute runat { "server" } into descendant::xxx[not(@runat)][1]');
END
RETURN @xmlData
END