X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Forg%2Fjson%2FJSONML.java;h=1a434fe6de1f93317fddcfa8381d90870a80a246;hb=453fa24ab502aaca4ffccf3590f97c897b9580b3;hp=acec7b869c8ef4f9bd3e4a0e177dc20a3becf073;hpb=6e56c166e45d1af37c5531b4cbe909a3e110927e;p=jalview.git diff --git a/src/org/json/JSONML.java b/src/org/json/JSONML.java index acec7b8..1a434fe 100644 --- a/src/org/json/JSONML.java +++ b/src/org/json/JSONML.java @@ -32,511 +32,652 @@ SOFTWARE. * @author JSON.org * @version 2016-01-30 */ -public class JSONML { - /** - * Parse XML values and store them in a JSONArray. - * @param x The XMLTokener containing the source string. - * @param arrayForm true if array form, false if object form. - * @param ja The JSONArray that is containing the current tag or null - * if we are at the outermost level. - * @param keepStrings Don't type-convert text nodes and attribute values - * @return A JSONArray if the value is the outermost tag, otherwise null. - * @throws JSONException - */ - private static Object parse( - XMLTokener x, - boolean arrayForm, - JSONArray ja, - boolean keepStrings - ) throws JSONException { - String attribute; - char c; - String closeTag = null; - int i; - JSONArray newja = null; - JSONObject newjo = null; - Object token; - String tagName = null; - -// Test for and skip past these forms: -// -// -// -// - - while (true) { - if (!x.more()) { - throw x.syntaxError("Bad XML"); +public class JSONML +{ + /** + * Parse XML values and store them in a JSONArray. + * + * @param x + * The XMLTokener containing the source string. + * @param arrayForm + * true if array form, false if object form. + * @param ja + * The JSONArray that is containing the current tag or null if we are + * at the outermost level. + * @param keepStrings + * Don't type-convert text nodes and attribute values + * @return A JSONArray if the value is the outermost tag, otherwise null. + * @throws JSONException + */ + private static Object parse(XMLTokener x, boolean arrayForm, JSONArray ja, + boolean keepStrings) throws JSONException + { + String attribute; + char c; + String closeTag = null; + int i; + JSONArray newja = null; + JSONObject newjo = null; + Object token; + String tagName = null; + + // Test for and skip past these forms: + // + // + // + // + + while (true) + { + if (!x.more()) + { + throw x.syntaxError("Bad XML"); + } + token = x.nextContent(); + if (token == XML.LT) + { + token = x.nextToken(); + if (token instanceof Character) + { + if (token == XML.SLASH) + { + + // Close tag "); - } else { - x.back(); - } - } else if (c == '[') { - token = x.nextToken(); - if (token.equals("CDATA") && x.next() == '[') { - if (ja != null) { - ja.put(x.nextCDATA()); - } - } else { - throw x.syntaxError("Expected 'CDATA['"); - } - } else { - i = 1; - do { - token = x.nextMeta(); - if (token == null) { - throw x.syntaxError("Missing '>' after ' 0); - } - } else if (token == XML.QUEST) { - -// "); - } else { - throw x.syntaxError("Misshaped tag"); - } - -// Open tag < - - } else { - if (!(token instanceof String)) { - throw x.syntaxError("Bad tagName '" + token + "'."); - } - tagName = (String)token; - newja = new JSONArray(); - newjo = new JSONObject(); - if (arrayForm) { - newja.put(tagName); - if (ja != null) { - ja.put(newja); - } - } else { - newjo.put("tagName", tagName); - if (ja != null) { - ja.put(newjo); - } - } - token = null; - for (;;) { - if (token == null) { - token = x.nextToken(); - } - if (token == null) { - throw x.syntaxError("Misshaped tag"); - } - if (!(token instanceof String)) { - break; - } - -// attribute = value - - attribute = (String)token; - if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { - throw x.syntaxError("Reserved attribute."); - } - token = x.nextToken(); - if (token == XML.EQ) { - token = x.nextToken(); - if (!(token instanceof String)) { - throw x.syntaxError("Missing value"); - } - newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token)); - token = null; - } else { - newjo.accumulate(attribute, ""); - } - } - if (arrayForm && newjo.length() > 0) { - newja.put(newjo); - } - -// Empty tag <.../> - - if (token == XML.SLASH) { - if (x.nextToken() != XML.GT) { - throw x.syntaxError("Misshaped tag"); - } - if (ja == null) { - if (arrayForm) { - return newja; - } - return newjo; - } - -// Content, between <...> and - - } else { - if (token != XML.GT) { - throw x.syntaxError("Misshaped tag"); - } - closeTag = (String)parse(x, arrayForm, newja, keepStrings); - if (closeTag != null) { - if (!closeTag.equals(tagName)) { - throw x.syntaxError("Mismatched '" + tagName + - "' and '" + closeTag + "'"); - } - tagName = null; - if (!arrayForm && newja.length() > 0) { - newjo.put("childNodes", newja); - } - if (ja == null) { - if (arrayForm) { - return newja; - } - return newjo; - } - } - } + if (x.nextToken() != XML.GT) + { + throw x.syntaxError("Misshaped close tag"); + } + return token; + } + else if (token == XML.BANG) + { + + // "); + } + else + { + x.back(); + } + } + else if (c == '[') + { + token = x.nextToken(); + if (token.equals("CDATA") && x.next() == '[') + { + if (ja != null) + { + ja.put(x.nextCDATA()); + } + } + else + { + throw x.syntaxError("Expected 'CDATA['"); + } + } + else + { + i = 1; + do + { + token = x.nextMeta(); + if (token == null) + { + throw x.syntaxError("Missing '>' after ' 0); } - } - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONArray using the JsonML transform. Each XML tag is represented as - * a JSONArray in which the first element is the tag name. If the tag has - * attributes, then the second element will be JSONObject containing the - * name/value pairs. If the tag contains children, then strings and - * JSONArrays will represent the child tags. - * Comments, prologs, DTDs, and <[ [ ]]> are ignored. - * @param string The source string. - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(String string) throws JSONException { - return (JSONArray)parse(new XMLTokener(string), true, null, false); - } + } + else if (token == XML.QUEST) + { + // <[ [ ]]> are ignored. - * @param string The source string. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { - return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); - } + x.skipPast("?>"); + } + else + { + throw x.syntaxError("Misshaped tag"); + } + // Open tag < - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONArray using the JsonML transform. Each XML tag is represented as - * a JSONArray in which the first element is the tag name. If the tag has - * attributes, then the second element will be JSONObject containing the - * name/value pairs. If the tag contains children, then strings and - * JSONArrays will represent the child content and tags. - * As opposed to toJSONArray this method does not attempt to convert - * any text node or attribute value to any type - * but just leaves it as a string. - * Comments, prologs, DTDs, and <[ [ ]]> are ignored. - * @param x An XMLTokener. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONArray)parse(x, true, null, keepStrings); - } + } + else + { + if (!(token instanceof String)) + { + throw x.syntaxError("Bad tagName '" + token + "'."); + } + tagName = (String) token; + newja = new JSONArray(); + newjo = new JSONObject(); + if (arrayForm) + { + newja.put(tagName); + if (ja != null) + { + ja.put(newja); + } + } + else + { + newjo.put("tagName", tagName); + if (ja != null) + { + ja.put(newjo); + } + } + token = null; + for (;;) + { + if (token == null) + { + token = x.nextToken(); + } + if (token == null) + { + throw x.syntaxError("Misshaped tag"); + } + if (!(token instanceof String)) + { + break; + } + // attribute = value - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONArray using the JsonML transform. Each XML tag is represented as - * a JSONArray in which the first element is the tag name. If the tag has - * attributes, then the second element will be JSONObject containing the - * name/value pairs. If the tag contains children, then strings and - * JSONArrays will represent the child content and tags. - * Comments, prologs, DTDs, and <[ [ ]]> are ignored. - * @param x An XMLTokener. - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(XMLTokener x) throws JSONException { - return (JSONArray)parse(x, true, null, false); - } + attribute = (String) token; + if (!arrayForm && ("tagName".equals(attribute) + || "childNode".equals(attribute))) + { + throw x.syntaxError("Reserved attribute."); + } + token = x.nextToken(); + if (token == XML.EQ) + { + token = x.nextToken(); + if (!(token instanceof String)) + { + throw x.syntaxError("Missing value"); + } + newjo.accumulate(attribute, keepStrings ? ((String) token) + : XML.stringToValue((String) token)); + token = null; + } + else + { + newjo.accumulate(attribute, ""); + } + } + if (arrayForm && newjo.length() > 0) + { + newja.put(newjo); + } + + // Empty tag <.../> + + if (token == XML.SLASH) + { + if (x.nextToken() != XML.GT) + { + throw x.syntaxError("Misshaped tag"); + } + if (ja == null) + { + if (arrayForm) + { + return newja; + } + return newjo; + } + // Content, between <...> and - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and <[ [ ]]> are ignored. - * @param string The XML source text. - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(String string) throws JSONException { - return (JSONObject)parse(new XMLTokener(string), false, null, false); + } + else + { + if (token != XML.GT) + { + throw x.syntaxError("Misshaped tag"); + } + closeTag = (String) parse(x, arrayForm, newja, keepStrings); + if (closeTag != null) + { + if (!closeTag.equals(tagName)) + { + throw x.syntaxError("Mismatched '" + tagName + "' and '" + + closeTag + "'"); + } + tagName = null; + if (!arrayForm && newja.length() > 0) + { + newjo.put("childNodes", newja); + } + if (ja == null) + { + if (arrayForm) + { + return newja; + } + return newjo; + } + } + } + } + } + else + { + if (ja != null) + { + ja.put(token instanceof String + ? keepStrings ? XML.unescape((String) token) + : XML.stringToValue((String) token) + : token); + } + } } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and <[ [ ]]> are ignored. - * @param string The XML source text. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { - return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as a + * JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and JSONArrays + * will represent the child tags. Comments, prologs, DTDs, and + * <[ [ ]]> are ignored. + * + * @param string + * The source string. + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException + * Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(String string) throws JSONException + { + return (JSONArray) parse(new XMLTokener(string), true, null, false); + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as a + * JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and JSONArrays + * will represent the child tags. As opposed to toJSONArray this method does + * not attempt to convert any text node or attribute value to any type but + * just leaves it as a string. Comments, prologs, DTDs, and + * <[ [ ]]> are ignored. + * + * @param string + * The source string. + * @param keepStrings + * If true, then values will not be coerced into boolean or numeric + * values and will instead be left as strings + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException + * Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(String string, boolean keepStrings) + throws JSONException + { + return (JSONArray) parse(new XMLTokener(string), true, null, + keepStrings); + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as a + * JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and JSONArrays + * will represent the child content and tags. As opposed to toJSONArray this + * method does not attempt to convert any text node or attribute value to any + * type but just leaves it as a string. Comments, prologs, DTDs, and + * <[ [ ]]> are ignored. + * + * @param x + * An XMLTokener. + * @param keepStrings + * If true, then values will not be coerced into boolean or numeric + * values and will instead be left as strings + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException + * Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) + throws JSONException + { + return (JSONArray) parse(x, true, null, keepStrings); + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as a + * JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and JSONArrays + * will represent the child content and tags. Comments, prologs, DTDs, and + * <[ [ ]]> are ignored. + * + * @param x + * An XMLTokener. + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException + * Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(XMLTokener x) throws JSONException + { + return (JSONArray) parse(x, true, null, false); + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as a + * JSONObject with a "tagName" property. If the tag has attributes, then the + * attributes will be in the JSONObject as properties. If the tag contains + * children, the object will have a "childNodes" property which will be an + * array of strings and JsonML JSONObjects. + * + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * + * @param string + * The XML source text. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException + * Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(String string) throws JSONException + { + return (JSONObject) parse(new XMLTokener(string), false, null, false); + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as a + * JSONObject with a "tagName" property. If the tag has attributes, then the + * attributes will be in the JSONObject as properties. If the tag contains + * children, the object will have a "childNodes" property which will be an + * array of strings and JsonML JSONObjects. + * + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * + * @param string + * The XML source text. + * @param keepStrings + * If true, then values will not be coerced into boolean or numeric + * values and will instead be left as strings + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException + * Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(String string, boolean keepStrings) + throws JSONException + { + return (JSONObject) parse(new XMLTokener(string), false, null, + keepStrings); + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as a + * JSONObject with a "tagName" property. If the tag has attributes, then the + * attributes will be in the JSONObject as properties. If the tag contains + * children, the object will have a "childNodes" property which will be an + * array of strings and JsonML JSONObjects. + * + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * + * @param x + * An XMLTokener of the XML source text. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException + * Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(XMLTokener x) throws JSONException + { + return (JSONObject) parse(x, false, null, false); + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as a + * JSONObject with a "tagName" property. If the tag has attributes, then the + * attributes will be in the JSONObject as properties. If the tag contains + * children, the object will have a "childNodes" property which will be an + * array of strings and JsonML JSONObjects. + * + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * + * @param x + * An XMLTokener of the XML source text. + * @param keepStrings + * If true, then values will not be coerced into boolean or numeric + * values and will instead be left as strings + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException + * Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) + throws JSONException + { + return (JSONObject) parse(x, false, null, keepStrings); + } + + /** + * Reverse the JSONML transformation, making an XML text from a JSONArray. + * + * @param ja + * A JSONArray. + * @return An XML string. + * @throws JSONException + * Thrown on error converting to a string + */ + public static String toString(JSONArray ja) throws JSONException + { + int i; + JSONObject jo; + int length; + Object object; + StringBuilder sb = new StringBuilder(); + String tagName; + + // Emit <[ [ ]]> are ignored. - * @param x An XMLTokener of the XML source text. - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(XMLTokener x) throws JSONException { - return (JSONObject)parse(x, false, null, false); + else + { + i = 1; } + // Emit content in body - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and <[ [ ]]> are ignored. - * @param x An XMLTokener of the XML source text. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONObject)parse(x, false, null, keepStrings); + length = ja.length(); + if (i >= length) + { + sb.append('/'); + sb.append('>'); } - - - /** - * Reverse the JSONML transformation, making an XML text from a JSONArray. - * @param ja A JSONArray. - * @return An XML string. - * @throws JSONException Thrown on error converting to a string - */ - public static String toString(JSONArray ja) throws JSONException { - int i; - JSONObject jo; - int length; - Object object; - StringBuilder sb = new StringBuilder(); - String tagName; - -// Emit '); + do + { + object = ja.get(i); + i += 1; + if (object != null) + { + if (object instanceof String) + { + sb.append(XML.escape(object.toString())); + } + else if (object instanceof JSONObject) + { + sb.append(toString((JSONObject) object)); + } + else if (object instanceof JSONArray) + { + sb.append(toString((JSONArray) object)); + } + else + { + sb.append(object.toString()); + } } - -// Emit content in body - - length = ja.length(); - if (i >= length) { - sb.append('/'); - sb.append('>'); - } else { - sb.append('>'); - do { - object = ja.get(i); - i += 1; - if (object != null) { - if (object instanceof String) { - sb.append(XML.escape(object.toString())); - } else if (object instanceof JSONObject) { - sb.append(toString((JSONObject)object)); - } else if (object instanceof JSONArray) { - sb.append(toString((JSONArray)object)); - } else { - sb.append(object.toString()); - } - } - } while (i < length); - sb.append('<'); - sb.append('/'); - sb.append(tagName); - sb.append('>'); + } while (i < length); + sb.append('<'); + sb.append('/'); + sb.append(tagName); + sb.append('>'); + } + return sb.toString(); + } + + /** + * Reverse the JSONML transformation, making an XML text from a JSONObject. + * The JSONObject must contain a "tagName" property. If it has children, then + * it must have a "childNodes" property containing an array of objects. The + * other properties are attributes with string values. + * + * @param jo + * A JSONObject. + * @return An XML string. + * @throws JSONException + * Thrown on error converting to a string + */ + public static String toString(JSONObject jo) throws JSONException + { + StringBuilder sb = new StringBuilder(); + int i; + JSONArray ja; + int length; + Object object; + String tagName; + Object value; + + // Emit '); - } else { - sb.append('>'); - length = ja.length(); - for (i = 0; i < length; i += 1) { - object = ja.get(i); - if (object != null) { - if (object instanceof String) { - sb.append(XML.escape(object.toString())); - } else if (object instanceof JSONObject) { - sb.append(toString((JSONObject)object)); - } else if (object instanceof JSONArray) { - sb.append(toString((JSONArray)object)); - } else { - sb.append(object.toString()); - } - } - } - sb.append('<'); - sb.append('/'); - sb.append(tagName); - sb.append('>'); + ja = jo.optJSONArray("childNodes"); + if (ja == null) + { + sb.append('/'); + sb.append('>'); + } + else + { + sb.append('>'); + length = ja.length(); + for (i = 0; i < length; i += 1) + { + object = ja.get(i); + if (object != null) + { + if (object instanceof String) + { + sb.append(XML.escape(object.toString())); + } + else if (object instanceof JSONObject) + { + sb.append(toString((JSONObject) object)); + } + else if (object instanceof JSONArray) + { + sb.append(toString((JSONArray) object)); + } + else + { + sb.append(object.toString()); + } } - return sb.toString(); + } + sb.append('<'); + sb.append('/'); + sb.append(tagName); + sb.append('>'); } + return sb.toString(); + } }