4faaa3230dc3d9dd08a465df88247f3031d33209
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / json / JSONML.java
1 /*******************************************************************************\r
2  * ============LICENSE_START==================================================\r
3  * * org.onap.dmaap\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package org.json;\r
24 \r
25 \r
26 \r
27 import java.util.Iterator;\r
28 \r
29 public class JSONML {\r
30 \r
31     /**\r
32      * Parse XML values and store them in a JSONArray.\r
33      * @param x       The XMLTokener containing the source string.\r
34      * @param arrayForm true if array form, false if object form.\r
35      * @param ja      The JSONArray that is containing the current tag or null\r
36      *     if we are at the outermost level.\r
37      * @return A JSONArray if the value is the outermost tag, otherwise null.\r
38      * @throws JSONException\r
39      */\r
40     private static Object parse(\r
41         XMLTokener x,\r
42         boolean    arrayForm,\r
43         JSONArray  ja\r
44     ) throws JSONException {\r
45         String     attribute;\r
46         char       c;\r
47         String       closeTag = null;\r
48         int        i;\r
49         JSONArray  newja = null;\r
50         JSONObject newjo = null;\r
51         Object     token;\r
52         String       tagName = null;\r
53 \r
54 // Test for and skip past these forms:\r
55 //      <!-- ... -->\r
56 //      <![  ... ]]>\r
57 //      <!   ...   >\r
58 //      <?   ...  ?>\r
59 \r
60         while (true) {\r
61             if (!x.more()) {\r
62                 throw x.syntaxError("Bad XML");\r
63             }\r
64             token = x.nextContent();\r
65             if (token == XML.LT) {\r
66                 token = x.nextToken();\r
67                 if (token instanceof Character) {\r
68                     if (token == XML.SLASH) {\r
69 \r
70 // Close tag </\r
71 \r
72                         token = x.nextToken();\r
73                         if (!(token instanceof String)) {\r
74                             throw new JSONException(\r
75                                     "Expected a closing name instead of '" +\r
76                                     token + "'.");\r
77                         }\r
78                         if (x.nextToken() != XML.GT) {\r
79                             throw x.syntaxError("Misshaped close tag");\r
80                         }\r
81                         return token;\r
82                     } else if (token == XML.BANG) {\r
83 \r
84 // <!\r
85 \r
86                         c = x.next();\r
87                         if (c == '-') {\r
88                             if (x.next() == '-') {\r
89                                 x.skipPast("-->");\r
90                             } else {\r
91                                 x.back();\r
92                             }\r
93                         } else if (c == '[') {\r
94                             token = x.nextToken();\r
95                             if (token.equals("CDATA") && x.next() == '[') {\r
96                                 if (ja != null) {\r
97                                     ja.put(x.nextCDATA());\r
98                                 }\r
99                             } else {\r
100                                 throw x.syntaxError("Expected 'CDATA['");\r
101                             }\r
102                         } else {\r
103                             i = 1;\r
104                             do {\r
105                                 token = x.nextMeta();\r
106                                 if (token == null) {\r
107                                     throw x.syntaxError("Missing '>' after '<!'.");\r
108                                 } else if (token == XML.LT) {\r
109                                     i += 1;\r
110                                 } else if (token == XML.GT) {\r
111                                     i -= 1;\r
112                                 }\r
113                             } while (i > 0);\r
114                         }\r
115                     } else if (token == XML.QUEST) {\r
116 \r
117 // <?\r
118 \r
119                         x.skipPast("?>");\r
120                     } else {\r
121                         throw x.syntaxError("Misshaped tag");\r
122                     }\r
123 \r
124 // Open tag <\r
125 \r
126                 } else {\r
127                     if (!(token instanceof String)) {\r
128                         throw x.syntaxError("Bad tagName '" + token + "'.");\r
129                     }\r
130                     tagName = (String)token;\r
131                     newja = new JSONArray();\r
132                     newjo = new JSONObject();\r
133                     if (arrayForm) {\r
134                         newja.put(tagName);\r
135                         if (ja != null) {\r
136                             ja.put(newja);\r
137                         }\r
138                     } else {\r
139                         newjo.put("tagName", tagName);\r
140                         if (ja != null) {\r
141                             ja.put(newjo);\r
142                         }\r
143                     }\r
144                     token = null;\r
145                     for (;;) {\r
146                         if (token == null) {\r
147                             token = x.nextToken();\r
148                         }\r
149                         if (token == null) {\r
150                             throw x.syntaxError("Misshaped tag");\r
151                         }\r
152                         if (!(token instanceof String)) {\r
153                             break;\r
154                         }\r
155 \r
156 // attribute = value\r
157 \r
158                         attribute = (String)token;\r
159                         if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) {\r
160                             throw x.syntaxError("Reserved attribute.");\r
161                         }\r
162                         token = x.nextToken();\r
163                         if (token == XML.EQ) {\r
164                             token = x.nextToken();\r
165                             if (!(token instanceof String)) {\r
166                                 throw x.syntaxError("Missing value");\r
167                             }\r
168                             newjo.accumulate(attribute, XML.stringToValue((String)token));\r
169                             token = null;\r
170                         } else {\r
171                             newjo.accumulate(attribute, "");\r
172                         }\r
173                     }\r
174                     if (arrayForm && newjo.length() > 0) {\r
175                         newja.put(newjo);\r
176                     }\r
177 \r
178 // Empty tag <.../>\r
179 \r
180                     if (token == XML.SLASH) {\r
181                         if (x.nextToken() != XML.GT) {\r
182                             throw x.syntaxError("Misshaped tag");\r
183                         }\r
184                         if (ja == null) {\r
185                             if (arrayForm) {\r
186                                 return newja;\r
187                             } else {\r
188                                 return newjo;\r
189                             }\r
190                         }\r
191 \r
192 // Content, between <...> and </...>\r
193 \r
194                     } else {\r
195                         if (token != XML.GT) {\r
196                             throw x.syntaxError("Misshaped tag");\r
197                         }\r
198                         closeTag = (String)parse(x, arrayForm, newja);\r
199                         if (closeTag != null) {\r
200                             if (!closeTag.equals(tagName)) {\r
201                                 throw x.syntaxError("Mismatched '" + tagName +\r
202                                         "' and '" + closeTag + "'");\r
203                             }\r
204                             tagName = null;\r
205                             if (!arrayForm && newja.length() > 0) {\r
206                                 newjo.put("childNodes", newja);\r
207                             }\r
208                             if (ja == null) {\r
209                                 if (arrayForm) {\r
210                                     return newja;\r
211                                 } else {\r
212                                     return newjo;\r
213                                 }\r
214                             }\r
215                         }\r
216                     }\r
217                 }\r
218             } else {\r
219                 if (ja != null) {\r
220                     ja.put(token instanceof String\r
221                         ? XML.stringToValue((String)token)\r
222                         : token);\r
223                 }\r
224             }\r
225         }\r
226     }\r
227 \r
228 \r
229     /**\r
230      * Convert a well-formed (but not necessarily valid) XML string into a\r
231      * JSONArray using the JsonML transform. Each XML tag is represented as\r
232      * a JSONArray in which the first element is the tag name. If the tag has\r
233      * attributes, then the second element will be JSONObject containing the\r
234      * name/value pairs. If the tag contains children, then strings and\r
235      * JSONArrays will represent the child tags.\r
236      * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.\r
237      * @param string The source string.\r
238      * @return A JSONArray containing the structured data from the XML string.\r
239      * @throws JSONException\r
240      */\r
241     public static JSONArray toJSONArray(String string) throws JSONException {\r
242         return toJSONArray(new XMLTokener(string));\r
243     }\r
244 \r
245 \r
246     /**\r
247      * Convert a well-formed (but not necessarily valid) XML string into a\r
248      * JSONArray using the JsonML transform. Each XML tag is represented as\r
249      * a JSONArray in which the first element is the tag name. If the tag has\r
250      * attributes, then the second element will be JSONObject containing the\r
251      * name/value pairs. If the tag contains children, then strings and\r
252      * JSONArrays will represent the child content and tags.\r
253      * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.\r
254      * @param x An XMLTokener.\r
255      * @return A JSONArray containing the structured data from the XML string.\r
256      * @throws JSONException\r
257      */\r
258     public static JSONArray toJSONArray(XMLTokener x) throws JSONException {\r
259         return (JSONArray)parse(x, true, null);\r
260     }\r
261 \r
262 \r
263     /**\r
264      * Convert a well-formed (but not necessarily valid) XML string into a\r
265      * JSONObject using the JsonML transform. Each XML tag is represented as\r
266      * a JSONObject with a "tagName" property. If the tag has attributes, then\r
267      * the attributes will be in the JSONObject as properties. If the tag\r
268      * contains children, the object will have a "childNodes" property which\r
269      * will be an array of strings and JsonML JSONObjects.\r
270 \r
271      * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.\r
272      * @param x An XMLTokener of the XML source text.\r
273      * @return A JSONObject containing the structured data from the XML string.\r
274      * @throws JSONException\r
275      */\r
276     public static JSONObject toJSONObject(XMLTokener x) throws JSONException {\r
277            return (JSONObject)parse(x, false, null);\r
278     }\r
279 \r
280 \r
281     /**\r
282      * Convert a well-formed (but not necessarily valid) XML string into a\r
283      * JSONObject using the JsonML transform. Each XML tag is represented as\r
284      * a JSONObject with a "tagName" property. If the tag has attributes, then\r
285      * the attributes will be in the JSONObject as properties. If the tag\r
286      * contains children, the object will have a "childNodes" property which\r
287      * will be an array of strings and JsonML JSONObjects.\r
288 \r
289      * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.\r
290      * @param string The XML source text.\r
291      * @return A JSONObject containing the structured data from the XML string.\r
292      * @throws JSONException\r
293      */\r
294     public static JSONObject toJSONObject(String string) throws JSONException {\r
295         return toJSONObject(new XMLTokener(string));\r
296     }\r
297 \r
298 \r
299     /**\r
300      * Reverse the JSONML transformation, making an XML text from a JSONArray.\r
301      * @param ja A JSONArray.\r
302      * @return An XML string.\r
303      * @throws JSONException\r
304      */\r
305     public static String toString(JSONArray ja) throws JSONException {\r
306         int             i;\r
307         JSONObject   jo;\r
308         String       key;\r
309         Iterator<String> keys;\r
310         int             length;\r
311         Object         object;\r
312         StringBuffer sb = new StringBuffer();\r
313         String       tagName;\r
314         String       value;\r
315 \r
316 // Emit <tagName\r
317 \r
318         tagName = ja.getString(0);\r
319         XML.noSpace(tagName);\r
320         tagName = XML.escape(tagName);\r
321         sb.append('<');\r
322         sb.append(tagName);\r
323 \r
324         object = ja.opt(1);\r
325         if (object instanceof JSONObject) {\r
326             i = 2;\r
327             jo = (JSONObject)object;\r
328 \r
329 // Emit the attributes\r
330 \r
331             keys = jo.keys();\r
332             while (keys.hasNext()) {\r
333                 key = keys.next().toString();\r
334                 XML.noSpace(key);\r
335                 value = jo.optString(key);\r
336                 if (value != null) {\r
337                     sb.append(' ');\r
338                     sb.append(XML.escape(key));\r
339                     sb.append('=');\r
340                     sb.append('"');\r
341                     sb.append(XML.escape(value));\r
342                     sb.append('"');\r
343                 }\r
344             }\r
345         } else {\r
346             i = 1;\r
347         }\r
348 \r
349 //Emit content in body\r
350 \r
351         length = ja.length();\r
352         if (i >= length) {\r
353             sb.append('/');\r
354             sb.append('>');\r
355         } else {\r
356             sb.append('>');\r
357             do {\r
358                 object = ja.get(i);\r
359                 i += 1;\r
360                 if (object != null) {\r
361                     if (object instanceof String) {\r
362                         sb.append(XML.escape(object.toString()));\r
363                     } else if (object instanceof JSONObject) {\r
364                         sb.append(toString((JSONObject)object));\r
365                     } else if (object instanceof JSONArray) {\r
366                         sb.append(toString((JSONArray)object));\r
367                     }\r
368                 }\r
369             } while (i < length);\r
370             sb.append('<');\r
371             sb.append('/');\r
372             sb.append(tagName);\r
373             sb.append('>');\r
374         }\r
375         return sb.toString();\r
376     }\r
377 \r
378     /**\r
379      * Reverse the JSONML transformation, making an XML text from a JSONObject.\r
380      * The JSONObject must contain a "tagName" property. If it has children,\r
381      * then it must have a "childNodes" property containing an array of objects.\r
382      * The other properties are attributes with string values.\r
383      * @param jo A JSONObject.\r
384      * @return An XML string.\r
385      * @throws JSONException\r
386      */\r
387     public static String toString(JSONObject jo) throws JSONException {\r
388         StringBuffer sb = new StringBuffer();\r
389         int          i;\r
390         JSONArray    ja;\r
391         String       key;\r
392         Iterator<String> keys;\r
393         int          length;\r
394         Object         object;\r
395         String       tagName;\r
396         String       value;\r
397 \r
398 //Emit <tagName\r
399 \r
400         tagName = jo.optString("tagName");\r
401         if (tagName == null) {\r
402             return XML.escape(jo.toString());\r
403         }\r
404         XML.noSpace(tagName);\r
405         tagName = XML.escape(tagName);\r
406         sb.append('<');\r
407         sb.append(tagName);\r
408 \r
409 //Emit the attributes\r
410 \r
411         keys = jo.keys();\r
412         while (keys.hasNext()) {\r
413             key = keys.next().toString();\r
414             if (!"tagName".equals(key) && !"childNodes".equals(key)) {\r
415                 XML.noSpace(key);\r
416                 value = jo.optString(key);\r
417                 if (value != null) {\r
418                     sb.append(' ');\r
419                     sb.append(XML.escape(key));\r
420                     sb.append('=');\r
421                     sb.append('"');\r
422                     sb.append(XML.escape(value));\r
423                     sb.append('"');\r
424                 }\r
425             }\r
426         }\r
427 \r
428 //Emit content in body\r
429 \r
430         ja = jo.optJSONArray("childNodes");\r
431         if (ja == null) {\r
432             sb.append('/');\r
433             sb.append('>');\r
434         } else {\r
435             sb.append('>');\r
436             length = ja.length();\r
437             for (i = 0; i < length; i += 1) {\r
438                 object = ja.get(i);\r
439                 if (object != null) {\r
440                     if (object instanceof String) {\r
441                         sb.append(XML.escape(object.toString()));\r
442                     } else if (object instanceof JSONObject) {\r
443                         sb.append(toString((JSONObject)object));\r
444                     } else if (object instanceof JSONArray) {\r
445                         sb.append(toString((JSONArray)object));\r
446                     } else {\r
447                         sb.append(object.toString());\r
448                     }\r
449                 }\r
450             }\r
451             sb.append('<');\r
452             sb.append('/');\r
453             sb.append(tagName);\r
454             sb.append('>');\r
455         }\r
456         return sb.toString();\r
457     }\r
458 }\r