1 /*******************************************************************************
\r
2 * ============LICENSE_START==================================================
\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
11 * * http://www.apache.org/licenses/LICENSE-2.0
\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
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
27 import java.util.Iterator;
\r
29 public class JSONML {
\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
40 private static Object parse(
\r
44 ) throws JSONException {
\r
47 String closeTag = null;
\r
49 JSONArray newja = null;
\r
50 JSONObject newjo = null;
\r
52 String tagName = null;
\r
54 // Test for and skip past these forms:
\r
62 throw x.syntaxError("Bad XML");
\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
72 token = x.nextToken();
\r
73 if (!(token instanceof String)) {
\r
74 throw new JSONException(
\r
75 "Expected a closing name instead of '" +
\r
78 if (x.nextToken() != XML.GT) {
\r
79 throw x.syntaxError("Misshaped close tag");
\r
82 } else if (token == XML.BANG) {
\r
88 if (x.next() == '-') {
\r
93 } else if (c == '[') {
\r
94 token = x.nextToken();
\r
95 if (token.equals("CDATA") && x.next() == '[') {
\r
97 ja.put(x.nextCDATA());
\r
100 throw x.syntaxError("Expected 'CDATA['");
\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
110 } else if (token == XML.GT) {
\r
115 } else if (token == XML.QUEST) {
\r
121 throw x.syntaxError("Misshaped tag");
\r
127 if (!(token instanceof String)) {
\r
128 throw x.syntaxError("Bad tagName '" + token + "'.");
\r
130 tagName = (String)token;
\r
131 newja = new JSONArray();
\r
132 newjo = new JSONObject();
\r
134 newja.put(tagName);
\r
139 newjo.put("tagName", tagName);
\r
146 if (token == null) {
\r
147 token = x.nextToken();
\r
149 if (token == null) {
\r
150 throw x.syntaxError("Misshaped tag");
\r
152 if (!(token instanceof String)) {
\r
156 // attribute = value
\r
158 attribute = (String)token;
\r
159 if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) {
\r
160 throw x.syntaxError("Reserved attribute.");
\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
168 newjo.accumulate(attribute, XML.stringToValue((String)token));
\r
171 newjo.accumulate(attribute, "");
\r
174 if (arrayForm && newjo.length() > 0) {
\r
178 // Empty tag <.../>
\r
180 if (token == XML.SLASH) {
\r
181 if (x.nextToken() != XML.GT) {
\r
182 throw x.syntaxError("Misshaped tag");
\r
192 // Content, between <...> and </...>
\r
195 if (token != XML.GT) {
\r
196 throw x.syntaxError("Misshaped tag");
\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
205 if (!arrayForm && newja.length() > 0) {
\r
206 newjo.put("childNodes", newja);
\r
220 ja.put(token instanceof String
\r
221 ? XML.stringToValue((String)token)
\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><[ [ ]]></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
241 public static JSONArray toJSONArray(String string) throws JSONException {
\r
242 return toJSONArray(new XMLTokener(string));
\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><[ [ ]]></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
258 public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
\r
259 return (JSONArray)parse(x, true, null);
\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
271 * Comments, prologs, DTDs, and <code><[ [ ]]></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
276 public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
\r
277 return (JSONObject)parse(x, false, null);
\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
289 * Comments, prologs, DTDs, and <code><[ [ ]]></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
294 public static JSONObject toJSONObject(String string) throws JSONException {
\r
295 return toJSONObject(new XMLTokener(string));
\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
305 public static String toString(JSONArray ja) throws JSONException {
\r
309 Iterator<String> keys;
\r
312 StringBuffer sb = new StringBuffer();
\r
318 tagName = ja.getString(0);
\r
319 XML.noSpace(tagName);
\r
320 tagName = XML.escape(tagName);
\r
322 sb.append(tagName);
\r
324 object = ja.opt(1);
\r
325 if (object instanceof JSONObject) {
\r
327 jo = (JSONObject)object;
\r
329 // Emit the attributes
\r
332 while (keys.hasNext()) {
\r
333 key = keys.next().toString();
\r
335 value = jo.optString(key);
\r
336 if (value != null) {
\r
338 sb.append(XML.escape(key));
\r
341 sb.append(XML.escape(value));
\r
349 //Emit content in body
\r
351 length = ja.length();
\r
358 object = ja.get(i);
\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
369 } while (i < length);
\r
372 sb.append(tagName);
\r
375 return sb.toString();
\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
387 public static String toString(JSONObject jo) throws JSONException {
\r
388 StringBuffer sb = new StringBuffer();
\r
392 Iterator<String> keys;
\r
400 tagName = jo.optString("tagName");
\r
401 if (tagName == null) {
\r
402 return XML.escape(jo.toString());
\r
404 XML.noSpace(tagName);
\r
405 tagName = XML.escape(tagName);
\r
407 sb.append(tagName);
\r
409 //Emit the attributes
\r
412 while (keys.hasNext()) {
\r
413 key = keys.next().toString();
\r
414 if (!"tagName".equals(key) && !"childNodes".equals(key)) {
\r
416 value = jo.optString(key);
\r
417 if (value != null) {
\r
419 sb.append(XML.escape(key));
\r
422 sb.append(XML.escape(value));
\r
428 //Emit content in body
\r
430 ja = jo.optJSONArray("childNodes");
\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
447 sb.append(object.toString());
\r
453 sb.append(tagName);
\r
456 return sb.toString();
\r