Eu tenho o seguinte procedimento armazenado CLR, que está lançando erro neste comando
xmlDoc.LoadXml(inputXml);
código
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;
}
funciona bem, quando o texto XML está dentro da variável dentro do visual studio como um texto. Mas quando carrego o código no servidor SQL como CLR e tento executá-lo no 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
então este erro é lançado:
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)
Tentei resolver o erro com o código a seguir, porque pensei que o byte utf8 poderia causar o erro, mas não ajudou.
// if byte mark exception happens
string _byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
if (inputXml.StartsWith(_byteOrderMarkUtf8))
{
inputXml = inputXml.Remove(0, _byteOrderMarkUtf8.Length);
}
O que há de errado aqui?
O problema é que você fez uma suposição errada sobre qual valor é retornado pelo
SqlXml.ToString()
método e, em seguida, no teste no Visual Studio, você injetou um valor, mas não verificou o queToString()
realmente estava retornando (que é: "System.Data.SqlTypes .SqlXml"). Embora você provavelmente tenha visto isso se tivesse colocado aSqlContext.Pipe.Send(inputXml);
linha acima daxmlDoc.LoadXml(inputXml);
linha ;-).Ao trabalhar com os
Sql*
tipos, você quase sempre deseja acessá-los por meio daValue
propriedade, que todos eles possuem. AValue
propriedade retorna a versão de string do XML que você deseja obter. No entanto, isso não é o ideal, pois você converterá o XML em uma string, apenas para convertê-lo novamente em XML quando chamarXmlDocument.LoadXml()
.Uma maneira melhor é usar o
SqlXml.CreateReader()
método que retorna umXmlReader
, e que pode ser usado com oXmlDocument.Load()
método.Reformulei seu código de teste (abaixo) para ser um exemplo mostrando todas as 3 dessas variações:
A execução do código acima com o SQL de teste original retorna o seguinte na guia "Mensagens":
PS Você não precisa se preocupar com UTF-8, especialmente para dados NCHAR / NVARCHAR / XML gerados de dentro do SQL Server, já que o SQL Server é UTF-16 LE.