NVarchar(max)到XML解析错误

时间:2016-09-05 19:46:47

标签: sql-server xml delphi nvarchar firedac

具有以下配置: 德尔福XE7 MS SQL Server 2008 使用FireDAC连接到SQL服务器

我使用存储过程检索表格,其中包含来自SQL服务器的所有详细记录,格式转换为nvarchar(max)。这是一个例子:

CREATE PROCEDURE uspUsers_GetAll
  @ReturnData nvarchar(max) = NULL OUTPUT
AS
BEGIN
  SET NOCOUNT ON;
  SET @ReturnData = CONVERT(nvarchar(max),
                (SELECT *, (  SELECT UserID, RightType
                              FROM UserRights
                              WHERE UserRights.UserID = Users.ID
                              FOR XML RAW('UserRight'), 
                              ROOT('UserRights'), ELEMENTS, TYPE)
                FROM Users
                FOR XML RAW('Users'), 
                ROOT('root') , ELEMENTS));
END;

在Delphi方面,我调用这个存储过程,将其加载到XML中,我试图解析它以将其转换为本地对象列表。像这样:

procedure TUsers.LoadFromDatabase;
 var
  usersXML: String;
  xmlDoc: IXMLDocument;
  workNode: IXMLNode;
  userObj: TUser;
begin
  Items.Clear;

  with dmApp.uspWork do
  begin
    Close;
    if Prepared then
      Prepared := False;
    Params.Clear;
    StoredProcName := 'uspUsers_GetAll';
    Prepare;
    ExecProc;
  end;

  usersXML := dmApp.uspWork.Params.ParamByName('@ReturnData').Value;
  xmlDoc := TXMLDocument.Create(nil);
  xmlDoc.LoadFromXML(usersXML);
  workNode := xmlDoc.DocumentElement;
  workNode := workNode.ChildNodes.FindNode('Users');

  while (workNode <> nil) and (workNode.NodeName = 'Users') do
  begin
    userObj := TUser.Create;
    userObj.LoadFromXMLNode(workNode);
    Items.Add(userObj);

    workNode := workNode.NextSibling;
  end;
end;

在上面的代码中

workNode := workNode.ChildNodes.FindNode('Users');

行在Xml.XMLDoc单元的深处返回一个异常。不是我可以解决的特定问题的错误消息。尝试将xmlDoc保存到xml文件中并且看起来没问题(可以使用Firefox等所有类型的工具打开它)。

奇怪的是,如果我将@ReturnData更改为varchar(max),我就不会再出现此错误。

知道我做错了吗?

1 个答案:

答案 0 :(得分:0)

对于XML,请避免使用*和未命名的列。此外,不要在嵌套XML中使用ROOT,而是将其声明为命名字段。例如:

CREATE PROCEDURE uspUsers_GetAll
  @ReturnData nvarchar(max) = NULL OUTPUT
AS
BEGIN
  SET NOCOUNT ON;
  SET @ReturnData = CONVERT(nvarchar(max),
                (SELECT givenname = Users.GivenName,surname = Users.Surname   , emailaddress = Users.Email , userrights = (  SELECT userid = UserRights.UserID, righttype = UserRights.RightType
                              FROM UserRights
                              WHERE UserRights.UserID = Users.ID
                              FOR XML RAW('userrights'), 
                              ELEMENTS, TYPE)
                FROM Users
                FOR XML RAW('user'), 
                ROOT('root') , ELEMENTS));
END;
BTW我总是避免使用大写的xml标签,叫我老式。另请注意行标记&#39;用户&#39;应该是&#39;用户&#39;因为这指的是单个用户。这应该给你

<root>
    <user>
       <givenname>Jo</givenname>
       <surname>Shmo</surname>
              <userrights>
                     <userid>12</userid>
                     <righttype>some_type</righttype>
              </userrights>
              <userrights>
                     <userid>12</userid>
                     <righttype>some_type</righttype>
              </userrights>
   </user>
   <user>
    ....
   </user>
</root>