source: trunk/ab5.0/ablib/src/Classes/ActiveBasic/Xml/Parser.ab

Last change on this file was 465, checked in by dai, 16 years ago

ActiveBasic.Xml.Parserを仮実装。
・SerializeTestのテストケースを追加。
・SimpleTestCaseにおいて、一時ディレクトリを扱えるようにした。
・XmlTestのテストケースを更新。

File size: 6.9 KB
Line 
1Namespace ActiveBasic
2Namespace Xml
3
4
5Class ParserException
6 Inherits System.Exception
7Public
8 Sub ParserException( message As String )
9 Exception( message )
10 End Sub
11End Class
12
13Class Parser
14 xmlString As String
15 currentIndex As Long
16
17 doc As System.Xml.XmlDocument
18
19 Static Const tokenLPar = &H3C ' <
20 Static Const tokenRPar = &H3E ' >
21 Static Const tokenSlash = &H2F ' /
22 Static Const xmlHeaderStr = "<?xml"
23 Static Const commentHeader = "<!--"
24 Static Const cdataHeader = "<![CDATA["
25 Static Const dtdHeader = "<!"
26 Static Const versionAttributeName = "version"
27 Static Const encodingAttributeName = "encoding"
28
29 Static Function IsAlpha( c As Char ) As Boolean
30 Return ( &H41 <= c and c <= &H5A or &H61 <= c and c <= &H7A )
31 End Function
32
33 Static Function IsUnderscore( c As Char ) As Boolean
34 Return ( c = &H5F )
35 End Function
36
37 Static Function IsNumber( c As Char ) As Boolean
38 Return ( &H30 <= c and c <= &H39 )
39 End Function
40
41 Static Function IsWhiteSpace( c As Char ) As Boolean
42 If c = &H20 Then
43 ' 空白
44 Return True
45 ElseIf c = &H09 Then
46 ' タブ文字
47 Return True
48 ElseIf c = &H0A or c = &H0D Then
49 ' 改行
50 Return True
51 End If
52 ' その他
53 Return False
54 End Function
55
56 Sub ts()
57 MessageBox(0,xmlString.Substring(currentIndex),"test",0)
58 End Sub
59
60 Function StringWordEquals( src As String ) As Boolean
61 Dim nextChar = xmlString[currentIndex + src.Length] As Char
62 Return ( xmlString.Substring( currentIndex, src.Length ) = src and Not (IsAlpha( nextChar ) or IsUnderscore( nextChar ) or IsNumber( nextChar ) ) )
63 End Function
64
65 Function ReadName() As String
66 Dim startIndex = currentIndex
67
68 Dim c = xmlString[currentIndex] As Char
69
70 If Not( IsAlpha( c ) or IsUnderscore( c ) ) Then
71 Throw New ParserException( Ex"タグ名がアルファベットまたはアンダースコアから始まっていない" )
72 End If
73
74 While IsAlpha( c ) or IsUnderscore( c ) or IsNumber( c )
75 currentIndex++
76 c = xmlString[currentIndex] As Char
77 Wend
78
79 Return xmlString.Substring( startIndex, currentIndex - startIndex )
80 End Function
81
82 Function ReadStringInDoubleQuotes() As String
83 ' '\"'分を進める
84 currentIndex++
85
86 Dim startIndex = currentIndex
87 Dim endIndex = 0 As Long
88
89 Do
90 If xmlString[currentIndex] = 0 Then
91 Throw New ParserException( Ex"属性の値の閉じ側のダブルクォートが存在しない" )
92 End If
93
94 If xmlString[currentIndex] = &H and xmlString[currentIndex+1] = &H22 Then
95 ' エスケープシーケンス付きのダブルクォートは無視
96 currentIndex += 2
97 Continue
98 End If
99
100 If xmlString[currentIndex] = &H22 Then ' '\"'
101 ' 閉じ側のダブルクォート
102 endIndex = currentIndex
103 currentIndex++
104 Exit Do
105 End If
106
107 currentIndex++
108 Loop
109
110 Return xmlString.Substring( startIndex, endIndex - startIndex )
111 End Function
112
113 Function ReadAttribute() As System.Xml.XmlAttribute
114 Dim attributeName = ReadName()
115 SkipWhiteSpace()
116
117 Dim atr = doc.CreateAttribute( attributeName )
118
119 If Not xmlString[currentIndex] = &H3D Then ' '='
120 Return atr
121 End If
122
123 currentIndex++ ' '='分を進める
124 SkipWhiteSpace()
125
126 If Not xmlString[currentIndex] = &H22 Then '\"'
127 Throw New ParserException( Ex"属性の値がダブルクォートで囲まれていない" )
128 End If
129
130 atr.Value = ReadStringInDoubleQuotes()
131
132 Return atr
133 End Function
134
135 Function ReadTextArea() As String
136 Dim startIndex = currentIndex
137
138 While Not ( xmlString[currentIndex] = tokenLPar or xmlString[currentIndex] = 0 )
139 currentIndex++
140 Wend
141
142 Return xmlString.Substring( startIndex, currentIndex - startIndex )
143 End Function
144
145 Sub SkipWhiteSpace()
146 While IsWhiteSpace( xmlString[currentIndex] )
147 currentIndex++
148 Wend
149 End Sub
150
151 Function ParseDeclaration() As System.Xml.XmlDeclaration
152 Dim versionStr = Nothing As String
153 Dim encodingStr = Nothing As String
154 currentIndex += xmlHeaderStr.Length
155
156 SkipWhiteSpace()
157
158 Do
159 If xmlString[currentIndex] = 0 Then
160 Throw New ParserException( Ex"タグの閉じ括弧が見つからない" )
161 End If
162 If xmlString[currentIndex] = tokenRPar Then
163 currentIndex ++
164 Exit Do
165 End If
166
167 currentIndex ++
168 Loop
169
170 Return doc.CreateXmlDeclaration( "1.0", "shift-jis", Nothing )
171 End Function
172 Function ParseComment() As System.Xml.XmlNode
173 End Function
174 Function ParseCData() As System.Xml.XmlNode
175 End Function
176 Function ParseDtd() As System.Xml.XmlNode
177 End Function
178 Function ParseElement() As System.Xml.XmlElement
179 ' '<'分を進める
180 currentIndex++
181
182 ' タグ名を取得し、要素を作成
183 Dim name = ReadName()
184 Dim xmlElement = doc.CreateElement( name )
185
186 SkipWhiteSpace()
187
188 Do
189 If xmlString[currentIndex] = 0 Then
190 Throw New ParserException( Ex"タグの閉じ括弧が見つからない" )
191 End If
192 If xmlString[currentIndex] = tokenRPar or ( xmlString[currentIndex] = tokenSlash and xmlString[currentIndex+1] = tokenRPar ) Then
193 Exit Do
194 End If
195
196 ' 属性を取得し、要素に追加
197 xmlElement.Attributes.Add( ReadAttribute() )
198
199 SkipWhiteSpace()
200 Loop
201
202 Dim closeTagStr = "</" + xmlElement.LocalName + ">"
203
204 If xmlString[currentIndex] = tokenRPar Then ' '>'
205 ' ">" で閉じられている
206 currentIndex ++
207
208 Do
209 SkipWhiteSpace()
210
211 If xmlString[currentIndex] = 0 Then
212 Throw New ParserException( xmlElement.LocalName + Ex"の閉じタグが見つからない" )
213 End If
214
215 If xmlString[currentIndex] = tokenLPar Then ' '<'
216 ' タグ
217 If StringWordEquals( closeTagStr ) Then
218 ' タグが閉じられた
219 currentIndex += closeTagStr.Length
220 Exit Do
221 End If
222
223 xmlElement.AppendChild( ParseNode() )
224 Else
225 ' タグ以外
226 xmlElement.AppendChild( doc.CreateTextNode( ReadTextArea() ) )
227 End If
228 Loop
229 Else
230 ' "/>" で閉じられている
231 currentIndex += 2
232 End If
233
234 Return xmlElement
235 End Function
236
237 Function ParseNode() As System.Xml.XmlNode
238 If Not xmlString[currentIndex] = tokenLPar Then
239 ' "<" で開始できないとき
240 Throw New ParserException( Ex"\q<\q で開始できない" )
241 End If
242
243 If StringWordEquals( xmlHeaderStr ) Then
244 ' XMLヘッダ
245 Return ParseDeclaration()
246 ElseIf StringWordEquals( commentHeader ) Then
247 ' コメントヘッダ
248 Return ParseComment()
249 ElseIf StringWordEquals( cdataHeader ) Then
250 ' CDATAヘッダ
251 Return ParseCData()
252 ElseIf StringWordEquals( dtdHeader ) Then
253 ' DTDヘッダ
254 Return ParseDtd()
255 Else
256 ' その他のタグ
257 Return ParseElement()
258 End If
259 End Function
260
261Public
262
263 Sub Parser( xmlString As String, doc As System.Xml.XmlDocument )
264 This.xmlString = xmlString
265 This.doc = doc
266 End Sub
267
268 Sub Parse()
269 This.currentIndex = 0
270 This.doc.RemoveAll()
271
272 SkipWhiteSpace()
273
274 While currentIndex < xmlString.Length
275
276 This.doc.AppendChild( ParseNode() )
277
278 SkipWhiteSpace()
279 Wend
280 End Sub
281
282 Static Sub Parse( xmlString As String, doc As System.Xml.XmlDocument )
283 Dim parser = New Parser( xmlString, doc )
284 parser.Parse()
285 End Sub
286End Class
287
288
289End Namespace
290End Namespace
Note: See TracBrowser for help on using the repository browser.