[DMAAP-48] Initial code import
[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 Copyright (c) 2008 JSON.org\r
27 \r
28 Permission is hereby granted, free of charge, to any person obtaining a copy\r
29 of this software and associated documentation files (the "Software"), to deal\r
30 in the Software without restriction, including without limitation the rights\r
31 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
32 copies of the Software, and to permit persons to whom the Software is\r
33 furnished to do so, subject to the following conditions:\r
34 \r
35 The above copyright notice and this permission notice shall be included in all\r
36 copies or substantial portions of the Software.\r
37 \r
38 The Software shall be used for Good, not Evil.\r
39 \r
40 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
41 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
42 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
43 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
44 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
45 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
46 SOFTWARE.\r
47 */\r
48 \r
49 import java.util.Iterator;\r
50 \r
51 \r
52 /**\r
53  * This provides static methods to convert an XML text into a JSONArray or\r
54  * JSONObject, and to covert a JSONArray or JSONObject into an XML text using\r
55  * the JsonML transform.\r
56  *\r
57  * @author JSON.org\r
58  * @version 2012-03-28\r
59  */\r
60 public class JSONML {\r
61 \r
62     /**\r
63      * Parse XML values and store them in a JSONArray.\r
64      * @param x       The XMLTokener containing the source string.\r
65      * @param arrayForm true if array form, false if object form.\r
66      * @param ja      The JSONArray that is containing the current tag or null\r
67      *     if we are at the outermost level.\r
68      * @return A JSONArray if the value is the outermost tag, otherwise null.\r
69      * @throws JSONException\r
70      */\r
71     private static Object parse(\r
72         XMLTokener x,\r
73         boolean    arrayForm,\r
74         JSONArray  ja\r
75     ) throws JSONException {\r
76         String     attribute;\r
77         char       c;\r
78         String       closeTag = null;\r
79         int        i;\r
80         JSONArray  newja = null;\r
81         JSONObject newjo = null;\r
82         Object     token;\r
83         String       tagName = null;\r
84 \r
85 // Test for and skip past these forms:\r
86 //      <!-- ... -->\r
87 //      <![  ... ]]>\r
88 //      <!   ...   >\r
89 //      <?   ...  ?>\r
90 \r
91         while (true) {\r
92             if (!x.more()) {\r
93                 throw x.syntaxError("Bad XML");\r
94             }\r
95             token = x.nextContent();\r
96             if (token == XML.LT) {\r
97                 token = x.nextToken();\r
98                 if (token instanceof Character) {\r
99                     if (token == XML.SLASH) {\r
100 \r
101 // Close tag </\r
102 \r
103                         token = x.nextToken();\r
104                         if (!(token instanceof String)) {\r
105                             throw new JSONException(\r
106                                     "Expected a closing name instead of '" +\r
107                                     token + "'.");\r
108                         }\r
109                         if (x.nextToken() != XML.GT) {\r
110                             throw x.syntaxError("Misshaped close tag");\r
111                         }\r
112                         return token;\r
113                     } else if (token == XML.BANG) {\r
114 \r
115 // <!\r
116 \r
117                         c = x.next();\r
118                         if (c == '-') {\r
119                             if (x.next() == '-') {\r
120                                 x.skipPast("-->");\r
121                             } else {\r
122                                 x.back();\r
123                             }\r
124                         } else if (c == '[') {\r
125                             token = x.nextToken();\r
126                             if (token.equals("CDATA") && x.next() == '[') {\r
127                                 if (ja != null) {\r
128                                     ja.put(x.nextCDATA());\r
129                                 }\r
130                             } else {\r
131                                 throw x.syntaxError("Expected 'CDATA['");\r
132                             }\r
133                         } else {\r
134                             i = 1;\r
135                             do {\r
136                                 token = x.nextMeta();\r
137                                 if (token == null) {\r
138                                     throw x.syntaxError("Missing '>' after '<!'.");\r
139                                 } else if (token == XML.LT) {\r
140                                     i += 1;\r
141                                 } else if (token == XML.GT) {\r
142                                     i -= 1;\r
143                                 }\r
144                             } while (i > 0);\r
145                         }\r
146                     } else if (token == XML.QUEST) {\r
147 \r
148 // <?\r
149 \r
150                         x.skipPast("?>");\r
151                     } else {\r
152                         throw x.syntaxError("Misshaped tag");\r
153                     }\r
154 \r
155 // Open tag <\r
156 \r
157                 } else {\r
158                     if (!(token instanceof String)) {\r
159                         throw x.syntaxError("Bad tagName '" + token + "'.");\r
160                     }\r
161                     tagName = (String)token;\r
162                     newja = new JSONArray();\r
163                     newjo = new JSONObject();\r
164                     if (arrayForm) {\r
165                         newja.put(tagName);\r
166                         if (ja != null) {\r
167                             ja.put(newja);\r
168                         }\r
169                     } else {\r
170                         newjo.put("tagName", tagName);\r
171                         if (ja != null) {\r
172                             ja.put(newjo);\r
173                         }\r
174                     }\r
175                     token = null;\r
176                     for (;;) {\r
177                         if (token == null) {\r
178                             token = x.nextToken();\r
179                         }\r
180                         if (token == null) {\r
181                             throw x.syntaxError("Misshaped tag");\r
182                         }\r
183                         if (!(token instanceof String)) {\r
184                             break;\r
185                         }\r
186 \r
187 // attribute = value\r
188 \r
189                         attribute = (String)token;\r
190                         if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) {\r
191                             throw x.syntaxError("Reserved attribute.");\r
192                         }\r
193                         token = x.nextToken();\r
194                         if (token == XML.EQ) {\r
195                             token = x.nextToken();\r
196                             if (!(token instanceof String)) {\r
197                                 throw x.syntaxError("Missing value");\r
198                             }\r
199                             newjo.accumulate(attribute, XML.stringToValue((String)token));\r
200                             token = null;\r
201                         } else {\r
202                             newjo.accumulate(attribute, "");\r
203                         }\r
204                     }\r
205                     if (arrayForm && newjo.length() > 0) {\r
206                         newja.put(newjo);\r
207                     }\r
208 \r
209 // Empty tag <.../>\r
210 \r
211                     if (token == XML.SLASH) {\r
212                         if (x.nextToken() != XML.GT) {\r
213                             throw x.syntaxError("Misshaped tag");\r
214                         }\r
215                         if (ja == null) {\r
216                             if (arrayForm) {\r
217                                 return newja;\r
218                             } else {\r
219                                 return newjo;\r
220                             }\r
221                         }\r
222 \r
223 // Content, between <...> and </...>\r
224 \r
225                     } else {\r
226                         if (token != XML.GT) {\r
227                             throw x.syntaxError("Misshaped tag");\r
228                         }\r
229                         closeTag = (String)parse(x, arrayForm, newja);\r
230                         if (closeTag != null) {\r
231                             if (!closeTag.equals(tagName)) {\r
232                                 throw x.syntaxError("Mismatched '" + tagName +\r
233                                         "' and '" + closeTag + "'");\r
234                             }\r
235                             tagName = null;\r
236                             if (!arrayForm && newja.length() > 0) {\r
237                                 newjo.put("childNodes", newja);\r
238                             }\r
239                             if (ja == null) {\r
240                                 if (arrayForm) {\r
241                                     return newja;\r
242                                 } else {\r
243                                     return newjo;\r
244                                 }\r
245                             }\r
246                         }\r
247                     }\r
248                 }\r
249             } else {\r
250                 if (ja != null) {\r
251                     ja.put(token instanceof String\r
252                         ? XML.stringToValue((String)token)\r
253                         : token);\r
254                 }\r
255             }\r
256         }\r
257     }\r
258 \r
259 \r
260     /**\r
261      * Convert a well-formed (but not necessarily valid) XML string into a\r
262      * JSONArray using the JsonML transform. Each XML tag is represented as\r
263      * a JSONArray in which the first element is the tag name. If the tag has\r
264      * attributes, then the second element will be JSONObject containing the\r
265      * name/value pairs. If the tag contains children, then strings and\r
266      * JSONArrays will represent the child tags.\r
267      * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.\r
268      * @param string The source string.\r
269      * @return A JSONArray containing the structured data from the XML string.\r
270      * @throws JSONException\r
271      */\r
272     public static JSONArray toJSONArray(String string) throws JSONException {\r
273         return toJSONArray(new XMLTokener(string));\r
274     }\r
275 \r
276 \r
277     /**\r
278      * Convert a well-formed (but not necessarily valid) XML string into a\r
279      * JSONArray using the JsonML transform. Each XML tag is represented as\r
280      * a JSONArray in which the first element is the tag name. If the tag has\r
281      * attributes, then the second element will be JSONObject containing the\r
282      * name/value pairs. If the tag contains children, then strings and\r
283      * JSONArrays will represent the child content and tags.\r
284      * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.\r
285      * @param x An XMLTokener.\r
286      * @return A JSONArray containing the structured data from the XML string.\r
287      * @throws JSONException\r
288      */\r
289     public static JSONArray toJSONArray(XMLTokener x) throws JSONException {\r
290         return (JSONArray)parse(x, true, null);\r
291     }\r
292 \r
293 \r
294     /**\r
295      * Convert a well-formed (but not necessarily valid) XML string into a\r
296      * JSONObject using the JsonML transform. Each XML tag is represented as\r
297      * a JSONObject with a "tagName" property. If the tag has attributes, then\r
298      * the attributes will be in the JSONObject as properties. If the tag\r
299      * contains children, the object will have a "childNodes" property which\r
300      * will be an array of strings and JsonML JSONObjects.\r
301 \r
302      * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.\r
303      * @param x An XMLTokener of the XML source text.\r
304      * @return A JSONObject containing the structured data from the XML string.\r
305      * @throws JSONException\r
306      */\r
307     public static JSONObject toJSONObject(XMLTokener x) throws JSONException {\r
308            return (JSONObject)parse(x, false, null);\r
309     }\r
310 \r
311 \r
312     /**\r
313      * Convert a well-formed (but not necessarily valid) XML string into a\r
314      * JSONObject using the JsonML transform. Each XML tag is represented as\r
315      * a JSONObject with a "tagName" property. If the tag has attributes, then\r
316      * the attributes will be in the JSONObject as properties. If the tag\r
317      * contains children, the object will have a "childNodes" property which\r
318      * will be an array of strings and JsonML JSONObjects.\r
319 \r
320      * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.\r
321      * @param string The XML source text.\r
322      * @return A JSONObject containing the structured data from the XML string.\r
323      * @throws JSONException\r
324      */\r
325     public static JSONObject toJSONObject(String string) throws JSONException {\r
326         return toJSONObject(new XMLTokener(string));\r
327     }\r
328 \r
329 \r
330     /**\r
331      * Reverse the JSONML transformation, making an XML text from a JSONArray.\r
332      * @param ja A JSONArray.\r
333      * @return An XML string.\r
334      * @throws JSONException\r
335      */\r
336     public static String toString(JSONArray ja) throws JSONException {\r
337         int             i;\r
338         JSONObject   jo;\r
339         String       key;\r
340         Iterator<String> keys;\r
341         int             length;\r
342         Object         object;\r
343         StringBuffer sb = new StringBuffer();\r
344         String       tagName;\r
345         String       value;\r
346 \r
347 // Emit <tagName\r
348 \r
349         tagName = ja.getString(0);\r
350         XML.noSpace(tagName);\r
351         tagName = XML.escape(tagName);\r
352         sb.append('<');\r
353         sb.append(tagName);\r
354 \r
355         object = ja.opt(1);\r
356         if (object instanceof JSONObject) {\r
357             i = 2;\r
358             jo = (JSONObject)object;\r
359 \r
360 // Emit the attributes\r
361 \r
362             keys = jo.keys();\r
363             while (keys.hasNext()) {\r
364                 key = keys.next().toString();\r
365                 XML.noSpace(key);\r
366                 value = jo.optString(key);\r
367                 if (value != null) {\r
368                     sb.append(' ');\r
369                     sb.append(XML.escape(key));\r
370                     sb.append('=');\r
371                     sb.append('"');\r
372                     sb.append(XML.escape(value));\r
373                     sb.append('"');\r
374                 }\r
375             }\r
376         } else {\r
377             i = 1;\r
378         }\r
379 \r
380 //Emit content in body\r
381 \r
382         length = ja.length();\r
383         if (i >= length) {\r
384             sb.append('/');\r
385             sb.append('>');\r
386         } else {\r
387             sb.append('>');\r
388             do {\r
389                 object = ja.get(i);\r
390                 i += 1;\r
391                 if (object != null) {\r
392                     if (object instanceof String) {\r
393                         sb.append(XML.escape(object.toString()));\r
394                     } else if (object instanceof JSONObject) {\r
395                         sb.append(toString((JSONObject)object));\r
396                     } else if (object instanceof JSONArray) {\r
397                         sb.append(toString((JSONArray)object));\r
398                     }\r
399                 }\r
400             } while (i < length);\r
401             sb.append('<');\r
402             sb.append('/');\r
403             sb.append(tagName);\r
404             sb.append('>');\r
405         }\r
406         return sb.toString();\r
407     }\r
408 \r
409     /**\r
410      * Reverse the JSONML transformation, making an XML text from a JSONObject.\r
411      * The JSONObject must contain a "tagName" property. If it has children,\r
412      * then it must have a "childNodes" property containing an array of objects.\r
413      * The other properties are attributes with string values.\r
414      * @param jo A JSONObject.\r
415      * @return An XML string.\r
416      * @throws JSONException\r
417      */\r
418     public static String toString(JSONObject jo) throws JSONException {\r
419         StringBuffer sb = new StringBuffer();\r
420         int          i;\r
421         JSONArray    ja;\r
422         String       key;\r
423         Iterator<String> keys;\r
424         int          length;\r
425         Object         object;\r
426         String       tagName;\r
427         String       value;\r
428 \r
429 //Emit <tagName\r
430 \r
431         tagName = jo.optString("tagName");\r
432         if (tagName == null) {\r
433             return XML.escape(jo.toString());\r
434         }\r
435         XML.noSpace(tagName);\r
436         tagName = XML.escape(tagName);\r
437         sb.append('<');\r
438         sb.append(tagName);\r
439 \r
440 //Emit the attributes\r
441 \r
442         keys = jo.keys();\r
443         while (keys.hasNext()) {\r
444             key = keys.next().toString();\r
445             if (!"tagName".equals(key) && !"childNodes".equals(key)) {\r
446                 XML.noSpace(key);\r
447                 value = jo.optString(key);\r
448                 if (value != null) {\r
449                     sb.append(' ');\r
450                     sb.append(XML.escape(key));\r
451                     sb.append('=');\r
452                     sb.append('"');\r
453                     sb.append(XML.escape(value));\r
454                     sb.append('"');\r
455                 }\r
456             }\r
457         }\r
458 \r
459 //Emit content in body\r
460 \r
461         ja = jo.optJSONArray("childNodes");\r
462         if (ja == null) {\r
463             sb.append('/');\r
464             sb.append('>');\r
465         } else {\r
466             sb.append('>');\r
467             length = ja.length();\r
468             for (i = 0; i < length; i += 1) {\r
469                 object = ja.get(i);\r
470                 if (object != null) {\r
471                     if (object instanceof String) {\r
472                         sb.append(XML.escape(object.toString()));\r
473                     } else if (object instanceof JSONObject) {\r
474                         sb.append(toString((JSONObject)object));\r
475                     } else if (object instanceof JSONArray) {\r
476                         sb.append(toString((JSONArray)object));\r
477                     } else {\r
478                         sb.append(object.toString());\r
479                     }\r
480                 }\r
481             }\r
482             sb.append('<');\r
483             sb.append('/');\r
484             sb.append(tagName);\r
485             sb.append('>');\r
486         }\r
487         return sb.toString();\r
488     }\r
489 }\r