【问题标题】:NVarchar(max) to XML parse errorNVarchar(max) 到 XML 解析错误
【发布时间】:2017-01-13 04:36:40
【问题描述】:

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

我正在使用存储过程来检索表,其中包含来自 SQL 服务器的所有详细记录,以 XML 格式转换为 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');

line 在 Xml.XMLDoc 单元深处的某处返回异常。不是我可以修复的特定问题的错误消息。确实尝试将 xmlDoc 保存到 xml 文件中,它看起来不错(可以使用 Firefox 等各种工具打开它)。

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

知道我做错了什么吗?

【问题讨论】:

    标签: sql-server xml delphi nvarchar firedac


    【解决方案1】:

    对于 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;
    

    顺便说一句,我总是避免使用大写的 xml 标签,称我为老式的。另请注意,行标签“用户”应为“用户”,因为这指的是单个用户。这应该给你

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

    【讨论】:

    • 感谢您的回答,但我很久以前就改变了方法,所以我现在无法测试您的解决方案是否正确......
    猜你喜欢
    • 2014-07-07
    • 1970-01-01
    • 2015-02-07
    • 2017-01-05
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多