11

I have a method that returns a well formed Xml string. How do I cast this string to SqlXml ?

TonyP
  • 5,655
  • 13
  • 60
  • 94
  • This link may solve your problem. http://stackoverflow.com/questions/574928/c-sql-whats-wrong-with-sqldbtype-xml-in-procedures –  Jul 13 '12 at 07:43

5 Answers5

13

Another way in pure C# - for posterity:

using (var memoryStream = new MemoryStream())
{
    using (var xmlWriter = XmlWriter.Create(memoryStream))
    {
        xmlWriter.WriteString(xmlData.ToString().Trim());
        return new System.Data.SqlTypes.SqlXml(memoryStream);
    }
}
ReinhardtB
  • 443
  • 4
  • 12
  • 1
    Your code did not work for me, but put me on the right track. What is a value of xmlData that worked for you? I added my version of the conversion code as an alternative answer. – R. Schreurs Dec 06 '12 at 11:56
  • I had an issue with this code when the XML data I was trying to write out used a single quote to encapsulate attribute values instead of a quote. The xmlWriter.WriteString failed and generated an error about invalid XML. I actually had to use R. Schreurs code to solve the issue. In all honesty, the reason I had to convert to a SqlXml type instead of just using a string is that SQL Server was also choking on single quote vs quote. I don't falut the code at all, just one of those things where this didn't work for me. – Nick Bork Aug 27 '13 at 17:40
10

I know this has been answered, but neither of the answers seemed to work for me. Instead I took another approach using this oneliner

var sqlXml = new SqlXml(new XmlTextReader(new StringReader(stringToParseToSqlXml)));

However this is leaking, but changing it to:

using (var reader = new StringReader(stringToParseToSqlXml))
{
    using (var xmlreader = new XmlTextReader(reader))
    {
        var sqlXml = new SqlXml(xmlreader);
        // Do other stuff
    }
}

I've used this, and it seems to works for me.

Andersnk
  • 857
  • 11
  • 25
  • Thank you, I was constantly getting the closed object message too. Also I like the using refactor. – DubMan Dec 01 '17 at 10:46
7

This is my version of a C# conversion method.

public static SqlXml ConvertString2SqlXml(string xmlData)
{
    UTF8Encoding encoding = new UTF8Encoding();
    MemoryStream m = new MemoryStream(encoding.GetBytes(xmlData));
    return new SqlXml(m);
}

I am not quite please with it, because I would have liked to have the MemoryStream with a using block, but that gave me:

Cannot access a disposed object. Object name: 'Invalid attempt to call Read when the stream is closed.'.

I am willing to accept that issue, because this code is only used in unit-tests, where I want to test an SqlFunction with an SqlXml parameter, which will be deployed to the SQL Server CLR.

The answer of ReinhardtB did not work for me, due to the following issues: When calling this with xmlData "<?xml version=\"1.0\" encoding=\"utf-8\"?><test></test>" (the back slashes are in the C# string literal), I got:

System.InvalidOperationException occurred Message=Token Text in state Start would result in an invalid XML document. Make sure that the ConformanceLevel setting is set to ConformanceLevel.Fragment or ConformanceLevel.Auto if you want to write an XML fragment.

This was easily fixed by the following modification:

XmlWriterSettings settings = new XmlWriterSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
using (var xmlWriter = XmlWriter.Create(memoryStream, settings))

However, this led to the following exception:

System.ObjectDisposedException occurred Message=Cannot access a disposed object. Object name: 'Invalid attempt to call Read when the stream is closed.'. Source=System.Data

This, I could work-around by omitting the using block for the MemoryStream (which is of course a bad idea), just to hit the next issue: when inspecting the value of SqlXml, SqlXml.Value, I found that it contains the value &lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;test&gt;&lt;/test&gt;, that is, < and > have been escaped! This looks like a serious issue with the SqlXml type.

R. Schreurs
  • 8,587
  • 5
  • 43
  • 62
3

In SQL Server, a simple: CAST(MyVarcharString AS xml)

Or assign it to the SQLDbType.Xml in .net as, say, a parameter

gbn
  • 422,506
  • 82
  • 585
  • 676
  • @TonyP: Updated with SQLDbType.Xml info – gbn Jan 31 '11 at 18:32
  • I am not comfortable doing the following , any advice sxml = b.BaanSession(sxml); SqlParameter p = new SqlParameter("@x", SqlDbType.Xml); p.Value = sxml; xmsg =(SqlXml) p.Value; – TonyP Jan 31 '11 at 18:51
  • This works fairly often but the XML we were receiving and trying to parse used single quotes instead of quotes to encapsulate node attributes and when using CAST and CONVERT the it would throw exceptions. – Nick Bork Aug 27 '13 at 17:41
1

SqlParameter works fine if you set the correct length.

comm.Parameters.Add("@XML_Field", SqlDbType.Xml, stringXml.Length)
comm.Prepare()
comm.Parameters("@XML_Field").Value = stringXml

And -1 if you want to set DBNull.Value in some cases :

comm.Parameters.Add("@XML_Field", SqlDbType.Xml, -1)
comm.Prepare()
comm.Parameters("@XML_Field").Value = DBNull.Value
Freewi
  • 111
  • 1
  • 3