Sql-Server

帶有 XML 參數的 CLR 過程返回根級別的數據無效。第 1 行,位置 1

  • February 10, 2017

我有以下 CLR 儲存過程,該過程在此命令上引發錯誤

xmlDoc.LoadXml(inputXml);

程式碼

   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;
   }

當 XML 文本作為文本在 Visual Studio 內的變數中時,它執行良好。但是當我將程式碼作為 CLR 上傳到 SQL 伺服器並嘗試從 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

然後拋出這個錯誤:

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)

我嘗試使用以下程式碼解決錯誤,因為我雖然 utf8 字節可能導致錯誤,但它沒有幫助。

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

這裡有什麼問題?

問題是您對該SqlXml.ToString()方法返回的值做出了錯誤的假設,然後在 Visual Studio 中進行測試時,您注入了一個值但沒有檢查ToString()實際返回的內容(即:“System.Data.SqlTypes .SqlXml”)。SqlContext.Pipe.Send(inputXml);儘管如果您將線放線上的上方,您可能會看到這一點xmlDoc.LoadXml(inputXml);;-)。

在使用這些Sql*類型時,您幾乎總是希望通過Value它們都擁有的屬性來訪問它們。該Value屬性確實返回了您想要獲取的 XML 的字元串版本。但是,這不太理想,因為您會將 XML 轉換為字元串,只是在您呼叫XmlDocument.LoadXml().

更好的方法是使用SqlXml.CreateReader()返回 的方法XmlReader,並且可以與該XmlDocument.Load()方法一起使用。

我重新編寫了您的測試程式碼(如下),作為顯示所有 3 種變體的範例:

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;
   }
}

使用原始測試 SQL 執行上面的程式碼會在“消息”選項卡中返回以下內容:

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>

PS 你不需要擔心 UTF-8,特別是對於從 SQL Server 內部生成的 NCHAR / NVARCHAR / XML 數據,因為 SQL Server 是 UTF-16 LE。

引用自:https://dba.stackexchange.com/questions/129798