web-dev-qa-db-ja.com

XMLパラメーターのあるCLRプロシージャがルートレベルのデータを返しますが無効です。行1、位置1

次の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);
    }

ここで何が問題になっていますか?

3
Muflix

問題は、SqlXml.ToString()メソッドによって返される値について誤った仮定を行った後、Visual Studioのテストで値を挿入したが、ToString()が何であるかを確認しなかったということです。実際に返されます( "System.Data.SqlTypes.SqlXml")。 SqlContext.Pipe.Send(inputXml);行をxmlDoc.LoadXml(inputXml);行の上に配置した場合は、おそらくこれを目にしたことでしょう;-)。

Sql*タイプを操作する場合、ほとんどすべての場合にValueプロパティを介してそれらにアクセスする必要があります。 Valueプロパティは、取得したいXMLの文字列バージョンを返します。ただし、XMLを文字列に変換するため、これは理想的とは言えません。XmlDocument.LoadXml()を呼び出したときにXMLに再度変換するだけです。

より良い方法は、XmlReaderを返すSqlXml.CreateReader()メソッドを使用することです。これは、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>

追伸SQL ServerはUTF-16 LEであるため、特にSQL Server内から生成されたNCHAR/NVARCHAR/XMLデータの場合、UTF-8について心配する必要はありません。

4
Solomon Rutzky