【问题标题】:How to dump out XML in an elegant way?如何以优雅的方式转储 XML?
【发布时间】:2014-04-12 08:11:08
【问题描述】:

我想将一些信息从已解析的 ttf 文件转储到 XML 文件中。 ttf中有几个表,例如cmap,头,呵呵。我已经定义了这些表的结构,例如:

class Font_Header{
public:
    FIXED   table_version_number;
    FIXED   font_revision;
    ULONG   checksum_adjustment;
// some other field...
    SHORT   index_to_loc_format;
    SHORT   glygh_data_format;
// some member functions...
};

现在我想写一个名为dump_info的函数来转储这个结构的内存布局。

void Font_Header::dump_info(FILE *fp, size_t indent){
    INDENT(fp, indent); fprintf(fp, "<head>\n");
    ++indent;
    INDENT(fp, indent); fprintf(fp, "<tableVersion value=\"0x%08x\"/>\n", table_version_number);
// some other lines...
    INDENT(fp, indent); fprintf(fp, "<glyphDataFormat value=\"%d\"/>\n", glygh_data_format);
    --indent;
    INDENT(fp, indent); fprintf(fp, "</head>\n");
}

我的问题是:

  1. 是否有更好的解决方案来实现这一目标?我已经写了N 行来定义结构,现在我必须写另一个N 行到dump_info。这不酷。我想要的东西是这样的:

    foreach field in fields
        dump(indent);
        dumpLn("<$1 value=\"$2\">", field.name, field.value);
        // Fields of different type are dumped in different format!
    end
    
  2. 如何巧妙地完成缩进?我定义了以下宏

    #define INDENT(fp, indent) for(size_t i = 0; i < (indent); ++i) fprintf((fp), "\t")
    

并将这个宏附加到每一行......我想知道是否有一种优雅的方式来完成这项任务。

【问题讨论】:

标签: c++ c xml indentation


【解决方案1】:

如果您只做几个案例,只需手工完成并忍受重复。

如果您只是为 很多 简单结构执行此操作,我会考虑使用简单的解析器将给定头文件中的结构转换为源以转储结构。

如果我希望能够更多地自定义 XML 输出(这似乎很可能),我会从一些元数据文件生成结构和结构打印函数。

如果您不只是为简单的结构执行此操作,那么我会将我的数据部分包装在一个简单的结构中并按照上述方式执行。

例如,您可以使用以下内容:(我可能会使用 XML 或 JSON 元数据,因为这样更容易解析 - 取决于您要编写生成器的语言)

FontHeaderData.crazymeta

struct_name : Font_Header_data
dumper_name : Font_Header_data_to_xml
xml_root_node : head
FIXED table_version_number tableVersionNumber 0x%08x
...

那么您的主文件将如下所示:

Font_Header.h

#include "Font_Header_data.h"
#include "Font_Header_data_to_xml.h"

class Font_Header {
    Font_Header_data data;
    void dump_info(FILE *fp, size_t indent){
        Font_Header_data_to_xml(fp,indent);
    }
};

Font_Header_data.hFont_Header_data_to_xml.hFont_Header_data_to_xml.c 是由您的解析器生成的。

请记住将文件的生成与正确的依赖项挂钩到构建过程中,以便在正确的时间重新构建它们。

“有趣”的部分是将元数据写入.c.h 转换器。

在过去,我做过类似的事情来保持大量 MySQL 表与其 C++ 对应表不同步,并生成正确的 C API INSERT/UPDATE 命令来连接两者。虽然要从头开始做很多工作,但它确实为我节省了很多小时的痛苦。

【讨论】:

    【解决方案2】:

    以下代码是我的尝试。我将类字段的信息存储到Notation 数组中。我假设ULL,即unsigned long long,是消耗最大内存(8B)的类型,并且总是从每个字段的指针中获取8B。应该特别小心处理的一件事是,我应该始终确保我在Notation 中正确分配了format。例如,如果我想打印一个 short 值(我只需要 2B)但我将 format 分配给 "%d"(为我获取 4B),我会得到错误的答案。

    两个问题仍然困扰着我:

    1. 该方法不可移植。不同的平台可能会为 ULL 分配不同大小的内存。
    2. 由于我总是从内存中获得 8B,抛开效率不谈,这可能会导致读取内存冲突

    好吧,更新...我将mask 添加到Notation 以获得正确的值,即使format 没有正确分配。

    请参阅 ttf 中的 OS/2 表。它由近 40 个字段组成。现在我已经写了 40 行来定义表,40 行来读取表和 40 行来转储它的信息!天啊。也许将来我必须添加一些其他的 40 行、40 行和 40 行……如果我不能自动执行此任务,请杀了我。


    #include <stdio.h>
    
    class X{
    public:
      char      a;
      short     b;
      int       c;
      double    d;
      X(char a, short b, int c, double d) : a(a), b(b), c(c), d(d) {}
    };
    
    typedef unsigned long long ULL;
    #define FIELD(c, x)             (((c*)0)->x)
    #define OFFSET(c, x)            ((size_t)&FIELD(c, x))
    #define SIZE(c, x)              (sizeof(FIELD(c, x)))
    #define MASK(c, x)              (((ULL)~0) >> ((sizeof(ULL) - SIZE(c, x)) << 3))
    #define NOTATION(c, x, s)       { SIZE(c, x), OFFSET(c, x), #x, s, MASK(c, x) }
    #define PTR(c, f)               ((void*)((size_t)&c + f->offset))
    #define VALUE(c, f)             (f->mask & *(ULL*)PTR(x, f))
    struct Notation{
      size_t        size;
      size_t        offset;
      const char    *name;
      const char    *format;
      ULL           mask;
    };
    
    Notation X_field[] = {
      NOTATION(X, a, "%c"),
      NOTATION(X, b, "%d"),  // The right 'format' of short should be %hd. I intentionally set it wrong.
      NOTATION(X, c, "%d"),
      NOTATION(X, d, "%lf")
    };
    
    #define PRINT(x, f, s) \
      printf("name: %s, size: %u, ptr: %p, value: " s "\n", #f, sizeof(x.f), &x.f, x.f)
    
    int main(){
      X x('z', 3, 2, 1.5);
      printf("--------------------MANUAL--------------------\n");
      PRINT(x, a, "%c");
      PRINT(x, b, "%hd");
      PRINT(x, c, "%d");
      PRINT(x, d, "%lf");
      printf("--------------------MASK--------------------\n");
      printf("0x%016hhx, %hhu\n", (char)~0, (char)~0);
      printf("0x%016hx, %hu\n", (short)~0, (short)~0);
      printf("0x%016x, %u\n", (int)~0, (int)~0);
      printf("0x%016llx, %llu\n", (ULL)~0, (ULL)~0);
      printf("--------------------FIELD--------------------\n");
      Notation *field = NULL;
      int i = 0;
      for(i = 0, field = X_field; i < 4; ++i, ++field){
        printf("size: %u, offset: %u, name: %s, format: %s, mask: 0x%016llx\n",
          field->size, field->offset, field->name, field->format, field->mask);
      }
    
      printf("--------------------AUTO--------------------\n");
      for(i = 0, field = X_field; i < 4; ++i, ++field){
        printf("name: %s, size: %u, ptr: %p, value: ", field->name, field->size, PTR(x, field));
        printf(field->format, VALUE(x, field));
        printf("\n");
      }
      return 0;
    }
    

    输出:

    --------------------MANUAL--------------------
    name: a, size: 1, ptr: 0x22ac18, value: z
    name: b, size: 2, ptr: 0x22ac1a, value: 3
    name: c, size: 4, ptr: 0x22ac1c, value: 2
    name: d, size: 8, ptr: 0x22ac20, value: 1.500000
    --------------------MASK--------------------
    0x00000000000000ff, 255
    0x000000000000ffff, 65535
    0x00000000ffffffff, 4294967295
    0xffffffffffffffff, 18446744073709551615
    --------------------FIELD--------------------
    size: 1, offset: 0, name: a, format: %c, mask: 0x00000000000000ff
    size: 2, offset: 2, name: b, format: %d, mask: 0x000000000000ffff
    size: 4, offset: 4, name: c, format: %d, mask: 0x00000000ffffffff
    size: 8, offset: 8, name: d, format: %lf, mask: 0xffffffffffffffff
    --------------------AUTO--------------------
    name: a, size: 1, ptr: 0x22ac18, value: z
    name: b, size: 2, ptr: 0x22ac1a, value: 3
    name: c, size: 4, ptr: 0x22ac1c, value: 2
    name: d, size: 8, ptr: 0x22ac20, value: 1.500000
    

    【讨论】:

      猜你喜欢
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 2015-10-29
      • 2014-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-13
      相关资源
      最近更新 更多