Vczh Library++3.0开发纪事之流式xml和json读写

Vczh Library++3.0开发纪事之流式xml和json读写

    每次完成一个任务的时候,都要看看有没有什么潜在的可以把功能是现成库的地方。这十分有利于提高自己的水平。但至于你写出来的库会不会有人用,那是另一回事情了。

    这次为了完成一个多编程语言+多自然语言的文档编写工具,不得不做一个可以一次生成一大批文本文件的模板结构出来。有了模板必然有元数据,元数据必然是类似字符串的东西,所以顺手就支持了xml和json。为了应付巨大的xml和json,必然要做出xml和json的流式读写。大家应该听说过SAX吧,大概就是那样的。

    有了xml和json之后,就可以在上面实现query了。把xml和json统一起来是一个比较麻烦的问题,因为本身从结构上来看他们是不相容的。而且为了便于给vlscript.dll添加compiler service的支持,势必要在dll上面做出字符串到语法树或者语法树到字符串这样子的操作。本地dll接口显然不可能做出一个顺眼的异构树结构,因此势必要把语法树表示成xml或者json。因此就有了下面的结构:

    1、一颗简洁但是功能强大的字符串,在上面可以存放xml、json和强类型数据。
    2、可以把xml和树相互转换。
    3、可以把json和树相互转换。
    4、当树存放的是强类型数据(基本类型都会用字符串存放)的时候,树可以映射到一个带有约束的xml或者json结构上去。

    在这里可以展示一下什么是强类型数据。我们知道json表达的结构是弱类型的。当你拿到一个object的时候你不知道它的类型,你只知道他有多少个成员变量。强类型结构要求object有一个类型标记,数组也有一个类型标记(因为我们不能从数组的元素类型推断出数组本身的类型——因为类型可以拥有继承关系),基本类型还要可扩展(json只支持数字、字符串、布尔值和null,显然是不够的)。下面贴一个强类型数据结构的xml和json的表现形式:

 1  < Developer >
 2       < Languages >
 3           < array:String >
 4               < primitive:String  value  = "C++" />
 5               < primitive:String  value  = "C#" />
 6               < primitive:String  value  = "F#" />
 7               < primitive:String  value  = "Haskell" />
 8           </ array:String >
 9       </ Languages >
10       < Name >
11           < primitive:String  value  = "vczh" />
12       </ Name >
13       < Project >
14           < Project >
15               < Host >
16                   < primitive:String  value  = "Codeplex" />
17               </ Host >
18               < Language >
19                   < primitive:String  value  = "C++" />
20               </ Language >
21           </ Project >
22       </ Project >
23  </ Developer >

 1  {
 2       " $object "  :  " Developer " ,
 3       " Languages "  : {
 4           " $array "  :  " String " ,
 5           " value "  : [{
 6               " $primitive "  :  " String " ,
 7               " value "  :  " C++ "
 8          }, {
 9               " $primitive "  :  " String " ,
10               " value "  :  " C# "
11          }, {
12               " $primitive "  :  " String " ,
13               " value "  :  " F# "
14          }, {
15               " $primitive "  :  " String " ,
16               " value "  :  " Haskell "
17          }]
18      },
19       " Name "  : {
20           " $primitive "  :  " String " ,
21           " value "  :  " vczh "
22      },
23       " Project "  : {
24           " $object "  :  " Project " ,
25           " Host "  : {
26               " $primitive "  :  " String " ,
27               " value "  :  " Codeplex "
28          },
29           " Language "  : {
30               " $primitive "  :  " String " ,
31               " value "  :  " C++ "
32          }
33      }
34  }

    上面的xml和json都是对一个相同的强类型数据结构的表示。我们可以看到$array、$object和$primitive是用来区分他们的实际类型的。

    下面是流式xml和json的读写的接口。可以很容易的看出用这种方法来读写xml和json必须将代码做成一个超级复杂的状态机才可以。这里太长贴不下,如果大家有兴趣的话可以去 Vczh Library++3.0下载最新代码并打开
    Library\Entity\TreeXml.cpp
    Library\Entity\TreeJson.cpp
    Library\Entity\TreeQuery.cpp
 1  class  XmlReader
 2  {
 3  public :
 4       enum  ComponentType
 5      {
 6          ElementHeadOpening,         //  name
 7          ElementHeadClosing,         //
 8          ElementClosing,             //
 9          Attribute,                 //  name, value
10          Text,                     //  value
11          CData,                     //  value
12          Comment,                 //  value
13 
14          BeginOfFile,
15          EndOfFile,
16          WrongFormat,
17      };
18  public :
19      XmlReader(stream::TextReader &  _reader);
20       ~ XmlReader();
21 
22      ComponentType                       CurrentComponentType() const  {  return  componentType; }
23       const  WString &                       CurrentName() const  {  return  name; }
24       const  WString &                       CurrentValue() const  {  return  value; }
25       bool                                 Next();
26       bool                                 IsAvailable() const  {  return  componentType != EndOfFile  &&  componentType != WrongFormat; }
27  };
28 
29  class  XmlWriter
30  {
31  public :
32      XmlWriter(stream::TextWriter &  _writer,  bool  _autoNewLine = true const  WString &  _space = L "      " );
33       ~ XmlWriter();
34 
35       bool                                 OpenElement( const  WString &  name);
36       bool                                 CloseElement();
37       bool                                 WriteElement( const  WString &  name,  const  WString &  value);
38       bool                                 WriteAttribute( const  WString &  name,  const  WString &  value);
39       bool                                 WriteText( const  WString &  value);
40       bool                                 WriteCData( const  WString &  value);
41       bool                                 WriteComment( const  WString &  value);
42  };
43 
44  class  JsonReader
45  {
46  public :
47       enum  ComponentType
48      {
49          ObjectOpening,
50          ObjectClosing,
51          Field,
52          ArrayOpening,
53          ArrayClosing,
54          Bool,
55          Int,
56          Double,
57          String,
58          Null,
59 
60          BeginOfFile,
61          EndOfFile,
62          WrongFormat,
63      };
64  public :
65      JsonReader(stream::TextReader &  _reader);
66       ~ JsonReader();
67 
68      ComponentType                       CurrentComponentType() const  {  return  componentType; }
69       const  WString &                       CurrentValue() const  {  return  value; }
70       bool                                 Next();
71       bool                                 IsAvailable() const  {  return  componentType != EndOfFile  &&  componentType != WrongFormat; }
72  };
73 
74  class  JsonWriter
75  {
76  public :
77      JsonWriter(stream::TextWriter &  _writer,  bool  _autoNewLine = true const  WString &  _space = L "      " );
78       ~ JsonWriter();
79 
80       bool                                 OpenObject();
81       bool                                 CloseObject();
82       bool                                 AddField( const  WString &  name);
83       bool                                 OpenArray();
84       bool                                 CloseArray();
85       bool                                 WriteBool( bool  value);
86       bool                                 WriteInt(vint value);
87       bool                                 WriteDouble( double  value);
88       bool                                 WriteString( const  WString &  value);
89       bool                                 WriteNull();
90  };

    有xml自然要有xpath,只不过xpath用来处理json和强类型数据结构都有点力不从心,所以我打算修改xpath,做成适合查询我这种跟它们稍微有点不同的树的查询语句,然后加入到Vczh Library++3.0里面去。有了这个之后就可以做很多事情了,譬如说在模板生成器里面使用query来查询复杂的配置,譬如说在脚本语言里面支持xml和json,还有很多其他的等等。query写完之后就可以开始写一个可以一次生成一大批文本文件的模板生成器了。我会将模板生成本身写成一个可以扩展功能的库,最后再写一个DocWrite.exe利用这个库实现一个文档生成器。

你可能感兴趣的:(Vczh Library++3.0开发纪事之流式xml和json读写)