Package: XMLParser

XMLParser

nameinstructionbranchcomplexitylinemethod
XMLParser(byte[])
M: 154 C: 0
0%
M: 12 C: 0
0%
M: 7 C: 0
0%
M: 32 C: 0
0%
M: 1 C: 0
0%
checkFor(XMLParser.Token)
M: 24 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
checkFor(char)
M: 24 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
isStart(char)
M: 10 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
main(String[])
M: 11 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
rdCh()
M: 25 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
rdQuoted()
M: 26 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
rdQuotedData()
M: 23 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
rdTag()
M: 25 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
rdToken()
M: 173 C: 0
0%
M: 21 C: 0
0%
M: 15 C: 0
0%
M: 60 C: 0
0%
M: 1 C: 0
0%
readAttributes()
M: 31 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
readDataNode()
M: 50 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 12 C: 0
0%
M: 1 C: 0
0%
readNode()
M: 24 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
readStop()
M: 14 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
readTagNode()
M: 123 C: 0
0%
M: 13 C: 0
0%
M: 8 C: 0
0%
M: 25 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: *
3: *        Copyright (c) 2009 Fujitsu Services Ltd.
4: *
5: *        Author: Nick Battle
6: *
7: *        This file is part of VDMJ.
8: *
9: *        VDMJ is free software: you can redistribute it and/or modify
10: *        it under the terms of the GNU General Public License as published by
11: *        the Free Software Foundation, either version 3 of the License, or
12: *        (at your option) any later version.
13: *
14: *        VDMJ is distributed in the hope that it will be useful,
15: *        but WITHOUT ANY WARRANTY; without even the implied warranty of
16: *        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17: *        GNU General Public License for more details.
18: *
19: *        You should have received a copy of the GNU General Public License
20: *        along with VDMJ. If not, see <http://www.gnu.org/licenses/>.
21: *
22: ******************************************************************************/
23:
24: package org.overture.combinatorialtesting.vdmj.server.xml;
25:
26: import java.io.IOException;
27: import java.util.List;
28: import java.util.Properties;
29: import java.util.Vector;
30:
31: public class XMLParser
32: {
33:         private static final String STREAM_ENCODING = "UTF-8";
34:         private StringBuilder buffer;
35:         private int end;
36:         private int pos;
37:         private char ch;
38:         private Token token;
39:         private String value; // Tag and quoted tokens have values
40:
41:         private enum Token
42:         {
43:                 OPEN("<"), CLOSE(">"), QOPEN("<?"), QCLOSE("?>"), COMPLETE("/>"), STOP(
44:                                 "</"), TAG("tag"), EQUALS("="), QUOTED("quoted value"), CDATA(
45:                                 "<![CDATA["), CDEND("]]>"), EOF("EOF");
46:
47:                 private String value;
48:
49:                 Token(String s)
50:                 {
51:                         value = s;
52:                 }
53:
54:                 @Override
55:                 public String toString()
56:                 {
57:                         return value;
58:                 }
59:         }
60:
61:         public XMLParser(byte[] xml) throws IOException
62:         {
63:•                if (xml[0] == '<' && xml[1] == '?')
64:                 {
65:                         String ascii = new String(xml, STREAM_ENCODING); // header is ASCII
66:                         buffer = new StringBuilder(ascii);
67:                         end = ascii.length();
68:                         pos = 0;
69:                         rdCh();
70:                         rdToken();
71:
72:                         checkFor(Token.QOPEN);
73:
74:                         // Check header, like <?xml version="1.0" encoding="UTF-8"?>
75:
76:•                        if (token != Token.TAG || !value.equals("xml"))
77:                         {
78:                                 throw new IOException("Expecting '<?xml' at " + pos);
79:                         }
80:
81:                         rdToken();
82:                         Properties p = readAttributes();
83:                         checkFor(Token.QCLOSE);
84:
85:                         String version = p.getProperty("version");
86:                         String encoding = p.getProperty("encoding");
87:
88:•                        if (version == null || !version.equals("1.0"))
89:                         {
90:                                 throw new IOException("Expecting XML version 1.0 at " + pos);
91:                         }
92:
93:                         // Re-encode the remainder using the header encoding
94:
95:                         String body = new String(ascii.substring(pos - 2).getBytes(STREAM_ENCODING), encoding);
96:                         buffer = new StringBuilder(body);
97:                         end = body.length();
98:                         pos = 0;
99:                         rdCh();
100:                         rdToken();
101:                 } else
102:                 {
103:                         String s = new String(xml); // default platform encoding
104:                         buffer = new StringBuilder(s);
105:                         end = s.length();
106:                         pos = 0;
107:                         rdCh();
108:                         rdToken();
109:                 }
110:         }
111:
112:         private char rdCh()
113:         {
114:•                if (pos == end)
115:                 {
116:                         ch = 0; // EOF
117:                 } else
118:                 {
119:                         ch = buffer.charAt(pos);
120:                         pos++;
121:                 }
122:
123:                 return ch;
124:         }
125:
126:         private void checkFor(char c) throws IOException
127:         {
128:•                if (ch == c)
129:                 {
130:                         rdCh();
131:                         return;
132:                 }
133:
134:                 throw new IOException("Expecting '" + c + "' at pos " + pos);
135:         }
136:
137:         private void checkFor(Token tok) throws IOException
138:         {
139:•                if (token == tok)
140:                 {
141:                         rdToken();
142:                         return;
143:                 }
144:
145:                 throw new IOException("Expecting '" + tok + "' at pos " + pos);
146:         }
147:
148:         private boolean isStart(char c)
149:         {
150:•                return Character.isLetter(c) || c == '_';
151:         }
152:
153:         private String rdTag()
154:         {
155:                 StringBuilder tag = new StringBuilder();
156:
157:•                while (isStart(ch) || Character.isDigit(ch))
158:                 {
159:                         tag.append(ch);
160:                         rdCh();
161:                 }
162:
163:                 return tag.toString();
164:         }
165:
166:         private String rdQuoted() throws IOException
167:         {
168:                 StringBuilder sb = new StringBuilder();
169:                 rdCh();
170:
171:•                while (ch != '"')
172:                 {
173:                         sb.append(ch);
174:                         rdCh();
175:                 }
176:
177:                 checkFor('"');
178:
179:                 return sb.toString();
180:         }
181:
182:         private Token rdToken() throws IOException
183:         {
184:                 boolean rdch = true;
185:                 value = null;
186:
187:•                while (Character.isWhitespace(ch))
188:                 {
189:                         rdCh();
190:                 }
191:
192:•                switch (ch)
193:                 {
194:                         case '<':
195:•                                if (rdCh() == '!')
196:                                 {
197:                                         rdCh();
198:                                         checkFor('[');
199:                                         checkFor('C');
200:                                         checkFor('D');
201:                                         checkFor('A');
202:                                         checkFor('T');
203:                                         checkFor('A');
204:                                         checkFor('[');
205:                                         token = Token.CDATA;
206:                                         rdch = false;
207:•                                } else if (ch == '?')
208:                                 {
209:                                         token = Token.QOPEN;
210:•                                } else if (ch == '/')
211:                                 {
212:                                         token = Token.STOP;
213:                                 } else
214:                                 {
215:                                         token = Token.OPEN;
216:                                         rdch = false;
217:                                 }
218:                                 break;
219:
220:                         case '/':
221:                                 rdCh();
222:                                 checkFor('>');
223:                                 token = Token.COMPLETE;
224:                                 rdch = false;
225:                                 break;
226:
227:                         case '?':
228:                                 rdCh();
229:                                 checkFor('>');
230:                                 token = Token.QCLOSE;
231:                                 rdch = false;
232:                                 break;
233:
234:                         case '>':
235:                                 token = Token.CLOSE;
236:                                 break;
237:
238:                         case ']':
239:                                 rdCh();
240:                                 checkFor(']');
241:                                 checkFor('>');
242:                                 token = Token.CDEND;
243:                                 rdch = false;
244:                                 break;
245:
246:                         case '=':
247:                                 token = Token.EQUALS;
248:                                 break;
249:
250:                         case '"':
251:                                 value = rdQuoted();
252:                                 token = Token.QUOTED;
253:                                 rdch = false;
254:                                 break;
255:
256:                         case 0:
257:                                 token = Token.EOF;
258:                                 break;
259:
260:                         default:
261:•                                if (isStart(ch))
262:                                 {
263:                                         value = rdTag();
264:                                         token = Token.TAG;
265:                                         rdch = false;
266:                                 } else
267:                                 {
268:                                         throw new IOException("Unexpected char '" + ch
269:                                                         + "' at pos " + pos);
270:                                 }
271:                                 break;
272:                 }
273:
274:•                if (rdch)
275:                 {
276:                         rdCh();
277:                 }
278:                 return token;
279:         }
280:
281:         public XMLNode readNode() throws IOException
282:         {
283:•                switch (token)
284:                 {
285:                         case OPEN:
286:                                 return readTagNode();
287:
288:                         case CDATA:
289:                                 return readDataNode();
290:
291:                         default:
292:                                 throw new IOException("Expecting <tag or <![CDATA[ at " + pos);
293:                 }
294:         }
295:
296:         private XMLNode readTagNode() throws IOException
297:         {
298:                 checkFor(Token.OPEN);
299:                 String tag = value;
300:                 checkFor(Token.TAG);
301:
302:                 Properties attr = null;
303:                 List<XMLNode> children = new Vector<XMLNode>();
304:
305:•                if (token == Token.TAG)
306:                 {
307:                         attr = readAttributes();
308:                 } else
309:                 {
310:                         attr = new Properties();
311:                 }
312:
313:•                switch (token)
314:                 {
315:                         case CLOSE:
316:•                                if (ch != '<')
317:                                 {
318:                                         children.add(new XMLTextNode(rdQuotedData()));
319:                                         rdToken();
320:                                 } else
321:                                 {
322:                                         rdToken();
323:
324:•                                        while (token == Token.OPEN || token == Token.CDATA)
325:                                         {
326:                                                 XMLNode node = readNode();
327:                                                 children.add(node);
328:                                         }
329:                                 }
330:
331:                                 String finish = readStop();
332:
333:•                                if (!finish.equals(tag))
334:                                 {
335:                                         throw new IOException("Expecting </" + tag + "> at " + pos);
336:                                 }
337:
338:                                 return new XMLOpenTagNode(tag, attr, children);
339:
340:                         case COMPLETE:
341:                                 rdToken();
342:                                 return new XMLTagNode(tag, attr);
343:
344:                         default:
345:                                 throw new IOException("Expecting </" + tag + "> at " + pos);
346:                 }
347:         }
348:
349:         private String rdQuotedData()
350:         {
351:                 StringBuilder sb = new StringBuilder();
352:
353:•                while (ch != '<' && ch != 0)
354:                 {
355:                         sb.append(ch);
356:                         rdCh();
357:                 }
358:
359:                 // De-quote the text...
360:
361:                 return sb.toString();
362:         }
363:
364:         private XMLDataNode readDataNode() throws IOException
365:         {
366:                 StringBuilder sb = new StringBuilder();
367:
368:                 while (true)
369:                 {
370:•                        if (ch == ']')
371:                         {
372:•                                if (buffer.substring(pos - 1, pos + 2).equals("]]>"))
373:                                 {
374:                                         rdCh();
375:                                         rdCh();
376:                                         rdCh();
377:                                         break;
378:                                 }
379:                         }
380:
381:                         sb.append(ch);
382:                         rdCh();
383:                 }
384:
385:                 rdToken();
386:                 return new XMLDataNode(sb.toString());
387:         }
388:
389:         private String readStop() throws IOException
390:         {
391:                 checkFor(Token.STOP);
392:                 String tag = value;
393:                 checkFor(Token.TAG);
394:                 checkFor(Token.CLOSE);
395:                 return tag;
396:         }
397:
398:         private Properties readAttributes() throws IOException
399:         {
400:                 Properties p = new Properties();
401:
402:•                while (token == Token.TAG)
403:                 {
404:                         String attr = value;
405:                         rdToken();
406:                         checkFor(Token.EQUALS);
407:                         String aval = value;
408:                         checkFor(Token.QUOTED);
409:
410:                         p.put(attr, aval);
411:                 }
412:
413:                 return p;
414:         }
415:
416:         public static void main(String[] args) throws IOException
417:         {
418:                 XMLParser p = new XMLParser("<![CDATA[]]]>".getBytes());
419:                 System.out.println(p.readNode());
420:         }
421: }