将记录转换为序列化表单数据以通过 HTTP 发送

2024-05-10

有没有办法转换此记录

TError = record
  code: Word;
  message: String;
end;

TState = record
  caption: String;
  address: Cardinal;
  counters: TArray<Word>;
  errors: TArray<TError>;
end;

序列化表单数据字符串 (Content-Type: application/x-www-form-urlencoded) like

caption=Foo&
address=175896&
counters[]=2&
counters[]=2&
errors[0][code]=52&
errors[0][message]=ERR_NOT_AVAILABLE

通过 HTTP 发送?

也许有一些类似的功能JQuery.param() http://api.jquery.com/jQuery.param/?


好的,这是一个样板解决方案,它也可以适合您的特定序列化或其他用途。

一个记录,TSerializer,执行所有序列化作业并将结果存储在字符串列表中。

要使用它,请调用方法Serialize('state', TValue.From(state),sList); from a TSerializer实例。

您可以添加大多数适合的类型TValue,包括记录、静态数组、动态数组和简单类。所有元素的展开都是通过递归进行的。 (免责声明,这是在 XE2 上测试的,但我认为 Delphi-2010 支持此处使用的所有增强型 RTTI 调用)

您的示例的输出如下所示:

record state:TState
  caption:string=Foo
  address:Cardinal=175896
  dynamic array counters:Word
    counters[0]:Word=2
    counters[1]:Word=2
  end
  dynamic array errors:TError
    record errors[0]:TError
      code:Word=52
      message:string=ERR_NOT_AVAILABLE
    end
  end
end

这是源单位:

unit SerializerBoilerplate;

interface

uses
  System.SysUtils, Classes, RTTI, TypInfo;

Type
  TSerializer = record
  private
    FSumIndent: string;
    procedure IncIndent;
    procedure DecIndent;
  public
    procedure Serialize(const name: string; thing: TValue;
      sList: TStrings; first: boolean = true);
  end;

implementation

procedure TSerializer.IncIndent;
begin
  FSumIndent := FSumIndent + '  ';
end;

procedure TSerializer.DecIndent;
begin
  SetLength(FSumIndent, Length(FSumIndent) - 2);
end;

procedure TSerializer.Serialize(const name: string; thing: TValue;
  sList: TStrings; first: boolean);
type
  PPByte = ^PByte;
var
  LContext: TRTTIContext;
  LField: TRTTIField;
  LProperty: TRTTIProperty;
  LRecord: TRTTIRecordType;
  LClass: TRTTIInstanceType;
  LStaticArray: TRTTIArrayType;
  LDynArray: TRTTIDynamicArrayType;
  LDimType: TRttiOrdinalType;
  LArrayIx: array of integer;
  LArrayMinIx: array of integer;
  LArrayMaxIx: array of integer;
  LNewValue: TValue;
  i: integer;
  // Generic N-dimensional array indexing
  procedure IncIx(var ArrayIx, ArrayMinIx, ArrayMaxIx: array of integer);
  var
    dimIx: integer;
  begin
    dimIx := Length(ArrayIx) - 1;
    repeat
      if (ArrayIx[dimIx] < ArrayMaxIx[dimIx]) then
      begin
        Inc(ArrayIx[dimIx]);
        break;
      end
      else
      begin
        ArrayIx[dimIx] := ArrayMinIx[dimIx];
        Dec(dimIx);
        if (dimIx < 0) then
          break;
      end;
    until (true = false);
  end;
  // Convert N-dimensional index to a string
  function IxToString(const ArrayIx: array of integer): string;
  var
    i: integer;
  begin
    Result := '';
    for i := 0 to High(ArrayIx) do
      Result := Result + '[' + IntToStr(ArrayIx[i]) + ']';
  end;
  // Get correct reference
  function GetValue(Addr: Pointer; Typ: TRTTIType): TValue;
  begin
    TValue.Make(Addr, Typ.Handle, Result);
  end;

begin
  if first then
    FSumIndent := '';

  case thing.Kind of
    { - Number calls }
    tkInteger, // Identifies an ordinal type.
    tkInt64, // Identifies the Int64/UInt64 types.
    tkPointer: // Identifies a pointer type.
      begin
        sList.Add(FSumIndent + name + ':' + thing.TypeInfo.name + '=' +
          thing.ToString);
      end;
    tkEnumeration:
      begin
        if (thing.TypeInfo = TypeInfo(boolean)) then
        begin
          sList.Add(FSumIndent + name + ':' + thing.TypeInfo.name + '=' +
            BoolToStr(thing.AsBoolean));
        end
        else begin
          // ToDO : Implement this
        end;
      end; // Identifies an enumeration type.
    tkSet: // Identifies a set type.
      begin
        // ToDO : Implement this
      end;
    { - Float calls }
    tkFloat: // Identifies a floating-point type. (plus Date,Time,DateTime)
      begin
        if (thing.TypeInfo = TypeInfo(TDate)) then
        begin
          sList.Add(FSumIndent + name + ':' + thing.TypeInfo.name + '=' +
            DateToStr(thing.AsExtended));
        end
        else if (thing.TypeInfo = TypeInfo(TTime)) then
        begin
          sList.Add(FSumIndent + name + ':' + thing.TypeInfo.name + '=' +
            TimeToStr(thing.AsExtended));
        end
        else if (thing.TypeInfo = TypeInfo(TDateTime)) then
        begin
          sList.Add(FSumIndent + name + ':' + thing.TypeInfo.name + '=' +
            DateTimeToStr(thing.AsExtended));
        end
        else
        begin
          sList.Add(FSumIndent + name + ':' + thing.TypeInfo.name + '=' +
            FloatToStr(thing.AsExtended));
        end;
        // ToDO : Handle currency
      end;

    { - String,character calls }
    tkChar, // Identifies a single-byte character.
    tkString, // Identifies a short string type.
    tkLString: // Identifies an AnsiString type.
      begin
        sList.Add(FSumIndent + name + ':' + thing.TypeInfo.name + '=' +
          thing.AsString);
      end;
    tkWString: // Identifies a WideString type.
      begin
        sList.Add(FSumIndent + name + ':' + thing.TypeInfo.name + '=' +
          thing.ToString);
      end;
    tkInterface: // Identifies an interface type.
      begin
        // ToDO : Implement this
      end;
    tkWChar, // Identifies a 2-byte (wide) character type.
    tkUString: // Identifies a UnicodeString type.
      begin
        sList.Add(FSumIndent + name + ':' + thing.TypeInfo.name + '=' +
          thing.AsString);
      end;

    tkVariant: // Identifies a Variant type.
      begin
        // ToDO : Implement this
      end;

    { - Generates recursive calls }
    tkArray: // Identifies a static array type.
      begin
        LStaticArray := LContext.GetType(thing.TypeInfo) as TRTTIArrayType;
        SetLength(LArrayIx, LStaticArray.DimensionCount);
        SetLength(LArrayMinIx, LStaticArray.DimensionCount);
        SetLength(LArrayMaxIx, LStaticArray.DimensionCount);
        sList.Add(FSumIndent + 'static array ' + name + ':' +
          LStaticArray.ElementType.name);
        IncIndent();
        for i := 0 to LStaticArray.DimensionCount - 1 do
        begin
          LDimType := LStaticArray.Dimensions[i] as TRttiOrdinalType;
          LArrayMinIx[i] := LDimType.MinValue;
          LArrayMaxIx[i] := LDimType.MaxValue;
          LArrayIx[i] := LDimType.MinValue;
        end;
        for i := 0 to LStaticArray.TotalElementCount - 1 do
        begin
          Serialize(Name + IxToString(LArrayIx),
            GetValue( PByte(thing.GetReferenceToRawData) +
              LStaticArray.ElementType.TypeSize * i,
              LStaticArray.ElementType),
            sList,false);
          IncIx(LArrayIx, LArrayMinIx, LArrayMaxIx);
        end;
        DecIndent();
        sList.Add(FSumIndent + 'end');
      end;
    tkDynArray: // Identifies a dynamic array type.
      begin
        LDynArray := LContext.GetType(thing.TypeInfo) as TRTTIDynamicArrayType;
        sList.Add(FSumIndent + 'dynamic array ' + name + ':' +
          LDynArray.ElementType.name);
        IncIndent();
        for i := 0 to thing.GetArrayLength - 1 do
        begin
          Serialize(Name + '[' + IntToStr(i) + ']',
            GetValue( PPByte(thing.GetReferenceToRawData)^ +
              LDynArray.ElementType.TypeSize * i,
              LDynArray.ElementType),
            sList,false);
        end;
        DecIndent();
        sList.Add(FSumIndent + 'end');
      end;
    tkRecord: // Identifies a record type.
      begin
        sList.Add(FSumIndent + 'record ' + name +':' +thing.TypeInfo.name);
        LRecord := LContext.GetType(thing.TypeInfo).AsRecord;
        IncIndent();
        for LField in LRecord.GetFields do
        begin
          Serialize(LField.name, LField.GetValue(thing.GetReferenceToRawData),
            sList, false);
        end;
        DecIndent();
        sList.Add(FSumIndent + 'end');
      end;
    tkClass: // Identifies a class type.
      begin
        sList.Add(FSumIndent + 'object ' + name + ':' + thing.TypeInfo.name);
        IncIndent();
        LClass := LContext.GetType(thing.TypeInfo).AsInstance;
        for LField in LClass.GetFields do
        begin
          Serialize(LField.name,
            // A hack to get a reference to the object
            // See https://stackoverflow.com/questions/2802864/rtti-accessing-fields-and-properties-in-complex-data-structures
            GetValue(PPByte(thing.GetReferenceToRawData)^ + LField.Offset,
            LField.FieldType),
            sList,false);
        end;
        // ToDO : Implement a more complete class serializer
        DecIndent();
        sList.Add(FSumIndent + 'end');
      end;

    { - Not implemented }
    tkClassRef: ; // Identifies a metaclass type.
    tkMethod: ; // Identifies a class method type.
    tkProcedure: ; // Identifies a procedural type.
    tkUnknown: ; // Identifies an unknown type that has RTTI.
  end;
end;

end.

和一个测试单元:

program SerializerProj;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Classes,
  SysUtils,
  RTTI,
  SerializerBoilerplate;

Type
  TMyObj = Class
  private
    fI: integer;
    fS: string;
  end;

  TInnerRec = record
    A, B, C: string;
  end;

  TDim1 = 1 .. 3;
  TDim2 = 2 .. 5;
  TMyArr = array [TDim1, TDim2] of integer; // Must be typed dimensions

  TTestRec = record
    s: string;
    ws: WideString;
    st: ShortString;
    ansiCh: AnsiChar;
    ansiS: AnsiString;
    wChar: Char;
    B: boolean;
    i: integer;
    t: TTime;
    d: TDate;
    dt: TDateTime;
    fd: Double;
    fS: Single;
    r: TInnerRec;
    arr: TMyArr;
    dArr: array of string;
    o: TMyObj;
  end;

  TError = record
    code: Word;
    message: String;
  end;

  TState = record
    caption: String;
    address: Cardinal;
    counters: TArray<Word>;
    errors: TArray<TError>;
  end;

var
  tr: TTestRec;
  state: TState;
  sList: TStringList;
  s: string;
  Serializer: TSerializer;

begin
  state.caption := 'Foo';
  state.address := 175896;
  SetLength(state.counters,2);
  state.counters[0] := 2;
  state.counters[1] := 2;
  SetLength(state.errors,1);
  state.errors[0].code := 52;
  state.errors[0].message := 'ERR_NOT_AVAILABLE';

  tr := Default (TTestRec);
  sList := TStringList.Create;
  try
    tr.s := 'A';
    tr.ws := 'WS';
    tr.st := '[100]';
    tr.ansiCh := '@';
    tr.ansiS := '@!';
    tr.wChar := 'Ö';
    tr.B := true;
    tr.i := 100;
    tr.t := Now;
    tr.d := Now;
    tr.dt := Now;
    tr.fd := Pi;
    tr.fS := 2 * Pi;
    tr.r.A := 'AA';
    tr.r.B := 'BB';
    tr.r.C := 'CC';
    tr.arr[1, 2] := 12;
    tr.arr[1, 3] := 13;
    tr.arr[1, 4] := 14;
    tr.arr[1, 5] := 15;
    tr.arr[2, 2] := 22;
    tr.arr[2, 3] := 23;
    tr.arr[2, 4] := 24;
    tr.arr[2, 5] := 25;
    tr.arr[3, 2] := 32;
    tr.arr[3, 3] := 33;
    tr.arr[3, 4] := 34;
    tr.arr[3, 5] := 35;
    SetLength(tr.dArr, 3);
    tr.dArr[0] := 'A';
    tr.dArr[1] := 'B';
    tr.dArr[2] := 'C';
    tr.o := TMyObj.Create;
    tr.o.fI := 11;
    tr.o.fS := '22';

    Serializer.Serialize('tr', TValue.From(tr), sList);
    for s in sList do
      WriteLn(s);
    sList.Clear;
    Serializer.Serialize('state', TValue.From(state),sList);
    for s in sList do
      WriteLn(s);

    ReadLn;
  finally
    sList.Free;
  end;

end.

我在学习上得到了一点帮助巴里·凯利的回答 https://stackoverflow.com/a/2810732/576719对这个问题Rtti 访问复杂数据结构中的字段和属性 https://stackoverflow.com/q/2802864/576719.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将记录转换为序列化表单数据以通过 HTTP 发送 的相关文章

  • 您可以将现有的 div 复制到模式对话框吗

    我有一个带有多个面板的仪表板来显示不同的信息 我希望能够添加一个按钮来以模式显示面板 我正在使用引导程序 我所能找到的只是已经编写的模态 我想复制作为面板的 div 标签的内容 然后将其显示在模型中 但我不确定如何进行 该面板的 html
  • jQuery 中的 $('') 与 $('')

    我看到人们以两种不同的方式在 jQuery 中创建 HTML 元素
  • jQuery 悬停时滚动到 div 并返回到第一个元素

    我基本上有一个具有设定尺寸的 div 和overflow hidden 该 div 包含 7 个子 div 但一次只显示一个 我希望当它们各自的链接悬停时能够平滑地垂直滚动 但是 第一部分 div 没有链接 并且是没有悬停链接时的默认部分
  • Django 将 JSON 数据传递给静态 getJSON/Javascript

    我正在尝试从 models py 中获取数据并将其序列化为views py 中的 JSON 对象 模型 py class Platform models Model platformtype models CharField max len
  • 搜索多维数组 JavaScript

    我有一个如下所示的数组 selected products 0 r1 7up 61 Albertsons selected products 1 r3 Arrowhead 78 Arrowhead selected products 2 r
  • 用javascript调用外部网页(跨域)

    我正在尝试使用以下网络服务来验证提要这个问题 https stackoverflow com questions 11996430 check if a url is a valid feed 但浏览器不允许我向另一台服务器发送 ajax
  • JQuery 删除和内存泄漏

    我正在开发一个游戏 我看到了很多内存消耗 我使用jquery animate 动画完成后 我 remove 元素 我的问题是 从 dom 树中删除一个元素后 对象还存在记忆中吗 Javascript 是一种垃圾收集语言 这意味着当没有代码保
  • 如何在jqplot中显示饼图之外的标签?

    Jqplot 有如下图表 jqplot 图表 http www jqplot com tests pie donut charts php 我的问题是如何在 a 之外显示标签jqplot chart像下面这样high chart 高图表可以
  • Delphi 中表单分发与其生命周期相关的接口对象的安全方法?

    我有一个 Delphi 表单 它提供接口对象背后的功能 代码的其他部分也通过属于该表单的属性获取引用 我无法将接口功能委托给子对象 因为太多的功能是由表单上的控件 组件提供的 我无法使用 TAggregateObject 或 TContai
  • 下划线反跳与参数

    假设我有这个事件处理程序 var mousewheel function e blah 但是 我想消除它 所以我这样做 它按预期工作 var mousewheelDebounced debounce mousewheel 500 docum
  • mouseover 函数在队列中多次出现

    我有这段代码 可以在鼠标悬停时使一个 div 淡出另一个 div 并在光标离开查看区域时淡出 例子 http jsfiddle net 3vgbemgu http jsfiddle net 3vgbemgu under hover func
  • 如何读取和更改 TEdit 控件的值?

    我有一个表格TForm1有 5TEdit and 2 TBitBtn 我还需要该程序 以便在输入数字数据后Edit1 and Edit2 on BitBtn1Click Edit1 and Edit2值将被求和并显示在Edit3 你想做这样
  • 无法将数据加载到 mvc 4 中的 jTable 中

    好的 我第一次尝试 jTable 我可以加载表 但这对我没有什么好处 因为它不会加载我的任何数据 当我调试程序时 我想要的表中的所有行都存储在我的列表中 因此我很困惑为什么当我运行应用程序时会弹出一个对话框 显示 与服务器通信时发生错误 H
  • 在网页上的文本框中键入内容时删除所有空格

    我如何在用户打字时即时删除输入到文本框中的空格 function var txt myTextbox var func function txt val txt val replace s g txt keyup func blur fun
  • jQuery,REAL:不是等价的运算符?

    此代码行选择任何类名不是 id 和 quantity 的 div 内的所有子输入 div item gt div not id quantity gt input live keydown function event 执行相反操作的代码行
  • Jquery 中的动态滚动位置

    请帮助我解决以下情况 我有 3 个页面 当滚动到达第二页时 用户滚动页面 它必须找到特定的 ID 然后触发一个函数 一旦第三页开始 另一个函数就会触发 根据要求我不应该使用任何插件
  • IE 中的 jQuery .width(val) 错误 - 无效参数

    通过ajax加载内部div book table 后 我想调整正文的宽度以适应更大的内容 var new width parseInt book table css width 407 body width new width 在 FF 和
  • 如何通过jquery更改元素的类名

    div class bestAnswerControl div class IsBestAnswer div div 我想补充一下 bestanswer some attribute 我想更换class IsBestAnswer div 到
  • 如何在jquery中获取保存时间和当前时间的差异?

    我想在 javascript 或 jquery 中获取保存时间和当前时间之间的时差 我节省的时间看起来像Sun Oct 24 15 55 56 GMT 05 30 2010 java中的日期格式代码如下 String newDate 201
  • Hibernate 和可序列化实体

    有谁知道是否有一个框架能够从实体类中剥离 Hibernate 集合以使它们可序列化 我查看了 BeanLib 但它似乎只进行实体的深层复制 而不允许我为实体类中的集合类型指定实现映射 BeanLib 目前不适用于 Hibernate 3 5

随机推荐

  • 获取运行云功能的运行时服务帐户

    有没有办法以编程方式从云功能获取运行时服务帐户的电子邮件 我知道我可以 猜测 默认的 App Engine 帐户 因为它始终是 appspot gserviceaccount com 但这不是我想要的 我本来期待有一些环境变量 https
  • ESLint 如何集成到 Create React App 中?

    当我跑步时npx create react app some name 为我创建了一个简单的 React 项目 当我随后窥视package json 似乎有一些 ESLint 存在的证据 因为有 eslintConfig extends r
  • Git 版本控制中忽略父目录

    如何忽略父目录 gitignore 我尝试了这种模式 但似乎它们不起作用 如果您想忽略某个文件夹但不想修改现有的 gitignore 请将 gitignore 放入仅包含星号的文件夹中 下面是一个快速的 BASH 示例 用于完成 idea
  • 无法在 Capistrano 3 的端口 80 上启动我的 Unicorn

    我在尝试运行时收到以下错误 帽子生产独角兽 开始 DEBUG 29ec5890 Command cd home ec2 user apps current RAILS ENV production BUNDLE GEMFILE home e
  • 如何编写完全可移植的 4 字节字符常量的编译时初始化

    遗留 代码大致如下所示 define MAKEID a b c d UInt32 a lt lt 24 UInt32 b lt lt 16 UInt32 c lt lt 8 UInt32 d define ID FORM MAKEID F
  • IE 中带有“删除”方法的 jQuery.ajax 问题

    我有一个页面 用户可以使用按钮编辑各种内容并选择触发 ajax 调用 特别是 一个操作会导致远程调用一个 url 其中包含一些数据和 放置 请求 这 因为我使用的是宁静的 Rails 后端 会触发我的更新操作 我还有一个删除按钮 它调用相同
  • 使用 PHP 将表单数据发送/发布到 URL [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我有一个通过 POST 提交的表单 提交表单后我捕获变量 如何连接表单数据 然后将其 POST 到 url 然后重新定向到感谢页面 这不是确
  • 查找文本文件中每行的行大小

    如何计算每行中的字符或数字数量 是否有类似 EOF 的东西更像是行尾 您可以遍历行中的每个字符并不断增加计数器直到行尾 n 遇到 确保以文本模式打开文件 r 而不是二进制模式 rb 否则流不会自动将不同平台的行结束序列转换为 n 人物 这是
  • 如何在c#中获取斐波那契数

    伙计们 我有一个关于斐波那契的问题 如何获得斐波那契数列 该数字也将以用户输入结束 例如 如果我输入 21 则输出必须为 0 1 1 2 3 5 8 13 21 这是我的代码 static void Main string args int
  • 使用 List.Contains 方法为 LINQ 构建表达式树

    Problem 我正在重构一些LINQ查询我们的 Web 应用程序中的多个报告 并且我尝试将一些重复的查询谓词移至它们自己的中IQueryable扩展方法 以便我们可以将它们重新用于这些报告以及将来的报告 正如您可能推断的那样 我已经重构了
  • docker-compose 规模后如何通过主机名访问其他容器?

    我将 docker compose 1 6 与 docker 1 10 1 和 docker compose yml 版本 2 一起使用 如中所述Compose 中的网络 https docs docker com compose netw
  • 打印绘图时 Octave 崩溃

    Solution 根据用户 Andy 在评论中的建议 最新版本的 Octave 目前 octave 4 0 1 rc4 的更新解决了该问题 并且绘图可以另存为 PNG 我有大量数据在 Octave 中绘制 但是当我尝试保存图像时 程序崩溃了
  • 这个记忆的斐波那契函数是如何工作的?

    在我正在做的函数式编程课程的当前练习作业中 我们必须制作给定函数的记忆版本 为了解释记忆化 给出以下示例 fiblist fibm x x lt 0 fibm 0 0 fibm 1 1 fibm n fiblist n 1 fiblist
  • NPM 全局标志在 Windows 上似乎不一致

    从控制台运行 gt npm root g 或者以编程方式 var npm require npm npm load null function err npm npm config set global true npm root 我在 W
  • 如何在android中获取当前一周的所有天数?

    我想在字符串数组中获取本周的所有日期 我怎样才能做到这一点 提前致谢 I think你想要这样的东西 假设你总是想要从星期一开始的几周 以及 MM dd yyyy 的日期格式 DateFormat format new SimpleDate
  • Django - 缺少 1 个必需的位置参数:'request'

    我收到错误 get indiceComercioVarejista 缺少 1 个必需的位置参数 要求 当尝试访问 get indiceComercioVarejista 方法时 我不知道这是怎么回事 views from django ht
  • MySQL REPLACE 在自动递增行中

    假设我有一个 MySQL 表 其中包含三列 id a and b和名为id is an AUTO INCREMENT场地 如果我将如下查询传递给 MySQL 它将正常工作 REPLACE INTO table id a b VALUES 1
  • REST 资源 url 中的查询字符串

    今天 我与一位同事讨论了在 REST URL 中使用查询字符串的问题 举这两个例子 1 http localhost findbyproductcode 4xxheua 2 http localhost findbyproductcode
  • 作为动画的八度情节点

    我有以下八度脚本 TOTAL POINTS 100 figure 1 for i 1 TOTAL POINTS randX rand 1 randY rand 1 scatter randX randY hold on endfor 当我运
  • 将记录转换为序列化表单数据以通过 HTTP 发送

    有没有办法转换此记录 TError record code Word message String end TState record caption String address Cardinal counters TArray