3

I have following CLR stored procedure, which is throwing error on this command

xmlDoc.LoadXml(inputXml);

code

 public static int spGetTaxOfficeXML(SqlXml _inputXml)
 {
 // this procedure rename Row elements name with NodeName attribute value
 string inputXml = _inputXml.ToString();
 XmlDocument xmlDoc = new XmlDocument();
 xmlDoc.LoadXml(inputXml);
// procedure Logic
 SqlContext.Pipe.Send(inputXml);
 return 0;
 }

it works well, when the XML text is inside variable inside visual studio as a text. But when i upload code to the SQL server as CLR, and try to execute it from SQL Management Studio:

DECLARE @XML XML
SET @XML = '<NodeA><NodeB></NodeB><NodeC AttributeX=""><Row NodeName="RowA" AttributeA="" AttributeB="abcd" AttributeC="efgh" /><Row NodeName="RowB" AttributeA="wxyz" /><Row NodeName="RowC" AttributeB="qwer" AttributeC="tyui" /><Row NodeName="RowD" AttributeA="stuv" AttributeB="erty" AttributeC="fghj" /></NodeC></NodeA>'
EXEC dbo.spGetTaxOfficeXML @XML

then this error is throwed:

Msg 6522, Level 16, State 1, Procedure spGetTaxOfficeXML, Line 0
A .NET Framework error occurred during execution of user-defined routine or aggregate "spGetTaxOfficeXML": 
System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
System.Xml.XmlException: 
 at System.Xml.XmlTextReaderImpl.Throw(Exception e)
 at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
 at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
 at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
 at System.Xml.XmlDocument.Load(XmlReader reader)
 at System.Xml.XmlDocument.LoadXml(String xml)
 at StoredProcedures.spGetTaxOfficeXML(String inputXml)

I tried to solve the error with following code, because i though the utf8 byte could cause the error, but it did not help.

// if byte mark exception happens
 string _byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
 if (inputXml.StartsWith(_byteOrderMarkUtf8))
 {
 inputXml = inputXml.Remove(0, _byteOrderMarkUtf8.Length);
 }

What is wrong here ?

Solomon Rutzky
70.2k8 gold badges160 silver badges306 bronze badges
asked Feb 19, 2016 at 13:15
0

1 Answer 1

5

The problem is that you made a bad assumption about what value is returned by the SqlXml.ToString() method, and then in testing in Visual Studio, you injected a value but did not check to see what ToString() was actually returning (which is: "System.Data.SqlTypes.SqlXml"). Though you probably would have seen this had you placed the SqlContext.Pipe.Send(inputXml); line above the xmlDoc.LoadXml(inputXml); line ;-).

When working with the Sql* types, you want to almost always access them via the Value property, which they all have. The Value property does return the string version of the XML as you were wanting to get. However, this is less than ideal since you will be converted the XML to a string, only to convert that back to XML again when you call XmlDocument.LoadXml().

A better way is to use the SqlXml.CreateReader() method which returns an XmlReader, and that can be used with the XmlDocument.Load() method.

I reworked your test code (below) to be an example showing all 3 of these variations:

using System.Data.SqlTypes;
using System.Xml;
using Microsoft.SqlServer.Server;
public partial class StoredProcedures
{
 [Microsoft.SqlServer.Server.SqlProcedure()]
 public static int spGetTaxOfficeXML(SqlXml InputXml)
 {
 // this procedure rename Row elements name with NodeName attribute value
 XmlDocument _XmlDoc = new XmlDocument();
 _XmlDoc.Load(InputXml.CreateReader());
 // procedure Logic
 SqlContext.Pipe.Send("Incorrect:\n" + InputXml.ToString());
 SqlContext.Pipe.Send("\nBetter, but not an XmlDocument:\n" + InputXml.Value);
 SqlContext.Pipe.Send("\nCorrect:\n" + _XmlDoc.OuterXml);
 return 0;
 }
}

Running the code above with the original test SQL returns the following in the "Messages" tab:

Incorrect:
System.Data.SqlTypes.SqlXml
Better, but not an XmlDocument:
<NodeA><NodeB /><NodeC AttributeX=""><Row NodeName="RowA" AttributeA="" AttributeB="abcd" AttributeC="efgh" /><Row NodeName="RowB" AttributeA="wxyz" /><Row NodeName="RowC" AttributeB="qwer" AttributeC="tyui" /><Row NodeName="RowD" AttributeA="stuv" AttributeB="erty" AttributeC="fghj" /></NodeC></NodeA>
Correct:
<NodeA><NodeB /><NodeC AttributeX=""><Row NodeName="RowA" AttributeA="" AttributeB="abcd" AttributeC="efgh" /><Row NodeName="RowB" AttributeA="wxyz" /><Row NodeName="RowC" AttributeB="qwer" AttributeC="tyui" /><Row NodeName="RowD" AttributeA="stuv" AttributeB="erty" AttributeC="fghj" /></NodeC></NodeA>

P.S. You don't need to worry about UTF-8, especially for NCHAR / NVARCHAR / XML data generated from within SQL Server, since SQL Server is UTF-16 LE.

answered Feb 19, 2016 at 20:08
1
  • 1
    It works ! Thank you for your explaining answer :-) Commented Feb 22, 2016 at 8:33

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.