The self-closing element <SomeElement/> is - semantically - the same as <SomeElement></SomeElement>. You should not bother about this... If your reading tool (or a third party requirement) needs this, you should rather replace this tool or discuss this with your partner.
The problem is: You have no control, that things stay as they are. Even in cases, where you are able to store the empty value with an opening and a closing tag this might be changed implicitly with a later call.
Try this:
DECLARE @tbl TABLE(ID INT IDENTITY,YourXML XML);
INSERT INTO @tbl VALUES
(
(SELECT '' AS [SomeTag] FOR XML PATH('RowNode'),ROOT('RootNode'),TYPE)
)
,(
(SELECT '' AS [SomeTag] FOR XML RAW('RowNode'),ROOT('RootNode'), ELEMENTS)
)
,(
N'<RootNode>
<RowNode>
<SomeTag></SomeTag>
</RowNode>
</RootNode>'
)
,
(CAST(
N'<RootNode>
<RowNode>
<SomeTag></SomeTag>
</RowNode>
</RootNode>'AS XML)
);
DECLARE @FirstXml XML=(SELECT YourXml FROM @tbl WHERE ID=1);
INSERT INTO @tbl VALUES(@FirstXml);
INSERT INTO @tbl SELECT @FirstXml;
INSERT INTO @tbl SELECT @FirstXml.query(N'.');
SELECT * FROM @tbl
The result
ID YourXML
--FOR XML PATH created - why ever - both tags
1 <RootNode><RowNode><SomeTag></SomeTag></RowNode></RootNode>
--FOR XML AUTO and all implicit casts use self-closing tags
2 <RootNode><RowNode><SomeTag /></RowNode></RootNode>
3 <RootNode><RowNode><SomeTag /></RowNode></RootNode>
4 <RootNode><RowNode><SomeTag /></RowNode></RootNode>
--Here we insert the first node *as is*
5 <RootNode><RowNode><SomeTag></SomeTag></RowNode></RootNode>
6 <RootNode><RowNode><SomeTag></SomeTag></RowNode></RootNode>
--But `.query()` will reformat this
7 <RootNode><RowNode><SomeTag /></RowNode></RootNode>
Some background:
XML is not stored as string string representation you see but as a hierarchy-table. Whenever you get the XML displayed on screen, its string representation is rebuilt from scratch. This can be slightly different each time you call it (e.g. attribute's order, CDATA sections, empty elements).
If you need this you can only enforce this format on string level. You might use some kind of RegEx approach, to replace any <abc/> with <abc></abc>.
But again: You should not have to think about that...
UPDATE
Try the code above with this SELECT:
SELECT *
,CAST(YourXML AS NVARCHAR(MAX)) AS CastedToString
FROM @tbl
The result
ID YourXML
CastedToString
--implicitly changed to self-closing tags
1 <RootNode><RowNode><SomeTag></SomeTag></RowNode></RootNode>
<RootNode><RowNode><SomeTag/></RowNode></RootNode>
--Self-closing **without a blank!!!**
2 <RootNode><RowNode><SomeTag /></RowNode></RootNode>
<RootNode><RowNode><SomeTag/></RowNode></RootNode>
You can see, that a comparisson on string level is not that easy... and rather hard to predict... You might use CAST(YourXml.query(N'.') AS NVARCHAR(MAX)) to get the same action done on each of your XMLs...