每次完成一個任務的時候,都要看看有沒有什么潛在的可以把功能是現成庫的地方。這十分有利于提高自己的水平。但至于你寫出來的庫會不會有人用,那是另一回事情了。
這次為了完成一個多編程語言+多自然語言的文檔編寫工具,不得不做一個可以一次生成一大批文本文件的模板結構出來。有了模板必然有元數據,元數據必然是類似字符串的東西,所以順手就支持了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利用這個庫實現一個文檔生成器。
posted on 2011-04-18 05:34
陳梓瀚(vczh) 閱讀(3279)
評論(3) 編輯 收藏 引用 所屬分類:
VL++3.0開發紀事