Reputation: 3338
I am trying to replace the null xml element into the null value while doing the concatenation. And i am making some silly mistake. I want to differentiate between an empty value and null value. I am using OpenXML to parse the XML data and something is missing in the code to read the null based param element.
I am using Server Server 2014.
Please suggest.
DECLARE @message_body XML;
DECLARE @XMLParameterData Table
(SeqID INT Identity(1,1),
ParamValue varchar(max))
DECLARE @docRef int
DECLARE @dataPath nvarchar(255)
DECLARE @mappingType int = 2 --Element-Centric mapping
Select @message_body = N'<AsyncRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ParamList> <Param>Bruce</Param>
<Param>Wa''yne</Param>
<Param>[email protected]</Param>
<Param>Coke</Param>
<Param>20000</Param>
<Param xsi:nil="true"/>
<Param></Param>
</ParamList>
</AsyncRequest>';
Set @dataPath = '/AsyncRequest/ParamList/Param'
EXEC sp_xml_preparedocument @docRef output, @message_body
INSERT INTO @XMLParameterData(ParamValue)
Select * From OpenXML(@docRef, @dataPath, @mappingType)
WITH
(
valx varchar(max) '.'
)
-- the xml document ref needs to be released ASAP
EXEC sp_xml_removedocument @docRef
SELECT * From @XMLParameterData
DECLARE @CSVString varchar(max)
SELECT @CSVString = STUFF(
(SELECT ', ' +
CHAR(34) + ParamValue + CHAR(34)
FROM @XMLParameterData
ORDER BY SeqID
FOR XML PATH('')
), 1, 1, '')
SELECT @CSVString as CSVTest
Output :- "Bruce", "Wa'yne", "[email protected]", "Coke", "20000", "", ""
Desired output :- "Bruce", "Wa'yne", "[email protected]", "Coke", "20000", NULL, ""
Upvotes: 3
Views: 1914
Reputation: 9143
What are you trying to achieve is not a standard behavior. You propbably expect following:
DECLARE @message_body XML = N'<AsyncRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ParamList>
<Param>Bruce</Param>
<Param>Wa''yne</Param>
<Param>[email protected]</Param>
<Param>Coke</Param>
<Param>20000</Param>
<Param xsi:nil="true"/>
<Param></Param>
</ParamList>
</AsyncRequest>';
SELECT X.value('.[not(@xsi:nil="true")]', 'nvarchar(MAX)') Value
FROM @message_body.nodes('//Param') T(X)
Which yields:
Value
-----
Bruce
Wa'yne
[email protected]
Coke
20000
NULL
(empty string here)
You may want text from nodes, which is more standarized:
SELECT X.value('text()[1]', 'nvarchar(MAX)') Value
FROM @message_body.nodes('//Param') T(X)
Value
-----
Bruce
Wa'yne
[email protected]
Coke
20000
NULL
NULL
Note that <element/>
and <element></element>
are synonyms. It's empty, no matter how you write. Ask yourself: is first <element/>
empty string? That would lead to long discussion - it's all a matter of interpretation. You may also consider xml:space
attribute to handle whitespaces.
Upvotes: 0
Reputation: 15997
Keep it simple! Use CASE WHEN
to check if @xsi:nil="true"
and .nodes
instead of OPENXML
:
DECLARE @message_body XML,
@output nvarchar(max);
select @message_body = N'<AsyncRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ParamList>
<Param>Bruce</Param>
<Param>Wa''yne</Param>
<Param>[email protected]</Param>
<Param>Coke</Param>
<Param>20000</Param>
<Param xsi:nil="true"/>
<Param></Param>
</ParamList>
</AsyncRequest>';
SELECT @output = STUFF((
SELECT
CASE WHEN t.v.value('@xsi:nil','nvarchar(max)') = 'true' THEN ',NULL'
ELSE ',"'+t.v.value('.','nvarchar(max)') + '"'
END
FROM @message_body.nodes('AsyncRequest/ParamList/Param') as t(v)
FOR XML PATH('')
),1,1,'')
SELECT @output
Will return:
"Bruce","Wa'yne","[email protected]","Coke","20000",NULL,""
Upvotes: 2
Reputation: 7763
How about this (I have slightly simplified your code by using xml.nodes rather than an xml document).
It uses the xml query expression .[not(@xsi:nil = "true")]
to return a null where xsi:nil is true.
I then use COALESCE
to return the string 'NULL' when a NULL
is returned:
DECLARE @message_body XML;
DECLARE @XMLParameterData Table
(SeqID INT Identity(1,1),
ParamValue varchar(max))
Select @message_body = N'<AsyncRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ParamList><Param>Bruce</Param><Param>Wa''yne</Param>
<Param>[email protected]</Param>
<Param>Coke</Param>
<Param>20000</Param>
<Param xsi:nil="true"/>
<Param></Param>
</ParamList>
</AsyncRequest>';
INSERT INTO @XMLParameterData(ParamValue)
SELECT T.c.value('.[not(@xsi:nil = "true")]', 'varchar(max)') AS result
FROM @message_body.nodes('/AsyncRequest/ParamList/Param')T(c)
SELECT * From @XMLParameterData
DECLARE @CSVString varchar(max)
SELECT @CSVString = STUFF(
(SELECT ', ' +
CHAR(34) + COALESCE(ParamValue, 'NULL') + CHAR(34)
FROM @XMLParameterData
ORDER BY SeqID
FOR XML PATH('')
), 1, 1, '')
SELECT @CSVString as CSVTest
This returns: "Bruce", "Wa'yne", "[email protected]", "Coke", "20000", "NULL", ""
Upvotes: 2