diff --git a/XML.java b/XML.java index faa5b65e1..10122d715 100644 --- a/XML.java +++ b/XML.java @@ -25,7 +25,6 @@ of this software and associated documentation files (the "Software"), to deal */ import java.util.Iterator; -import java.util.Map.Entry; /** * This provides static methods to convert an XML text into a JSONObject, and to @@ -141,7 +140,7 @@ public static String escape(String string) { if (mustEscape(cp)) { sb.append("&#x"); sb.append(Integer.toHexString(cp)); - sb.append(';'); + sb.append(";"); } else { sb.appendCodePoint(cp); } @@ -191,12 +190,36 @@ public static String unescape(String string) { final int semic = string.indexOf(';', i); if (semic > i) { final String entity = string.substring(i + 1, semic); - sb.append(XMLTokener.unescapeEntity(entity)); + if (entity.charAt(0) == '#') { + int cp; + if (entity.charAt(1) == 'x') { + // hex encoded unicode + cp = Integer.parseInt(entity.substring(2), 16); + } else { + // decimal encoded unicode + cp = Integer.parseInt(entity.substring(1)); + } + sb.appendCodePoint(cp); + } else { + if ("quot".equalsIgnoreCase(entity)) { + sb.append('"'); + } else if ("amp".equalsIgnoreCase(entity)) { + sb.append('&'); + } else if ("apos".equalsIgnoreCase(entity)) { + sb.append('\''); + } else if ("lt".equalsIgnoreCase(entity)) { + sb.append('<'); + } else if ("gt".equalsIgnoreCase(entity)) { + sb.append('>'); + } else { + sb.append('&').append(entity).append(';'); + } + } // skip past the entity we just parsed. i += entity.length() + 1; } else { // this shouldn't happen in most cases since the parser - // errors on unclosed entries. + // errors on unclosed enties. sb.append(c); } } else { @@ -340,7 +363,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, bool throw x.syntaxError("Missing value"); } jsonobject.accumulate(string, - keepStrings ? ((String)token) : stringToValue((String) token)); + keepStrings ? unescape((String)token) : stringToValue((String) token)); token = null; } else { jsonobject.accumulate(string, ""); @@ -355,7 +378,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, bool if (jsonobject.length() > 0) { context.accumulate(tagName, jsonobject); } else { - context.accumulate(tagName, ""); + context.accumulate(tagName, JSONObject.NULL); } return false; @@ -372,7 +395,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, bool string = (String) token; if (string.length() > 0) { jsonobject.accumulate("content", - keepStrings ? string : stringToValue(string)); + keepStrings ? unescape(string) : stringToValue(string)); } } else if (token == LT) { @@ -399,14 +422,18 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, bool } /** - * This method is the same as {@link JSONObject#stringToValue(String)} + * This method is the same as {@link JSONObject.stringToValue(String)} * except that this also tries to unescape String values. * * @param string String to convert * @return JSON value of this string or the string */ public static Object stringToValue(String string) { - return JSONObject.stringToValue(string); + Object ret = JSONObject.stringToValue(string); + if(ret instanceof String){ + return unescape((String)ret); + } + return ret; } /** @@ -481,12 +508,15 @@ public static String toString(Object object) throws JSONException { * @return A string. * @throws JSONException Thrown if there is an error parsing the string */ - public static String toString(final Object object, final String tagName) + public static String toString(Object object, String tagName) throws JSONException { StringBuilder sb = new StringBuilder(); JSONArray ja; JSONObject jo; + String key; + Iterator keys; String string; + Object value; if (object instanceof JSONObject) { @@ -502,11 +532,12 @@ public static String toString(final Object object, final String tagName) for (final Entry entry : jo.entrySet()) { final String key = entry.getKey(); Object value = entry.getValue(); - if (value == null) { - value = ""; + if (JSONObject.NULL.equals(value)) { + value = null; } else if (value.getClass().isArray()) { value = new JSONArray(value); } + string = value instanceof String ? (String) value : null; // Emit content in body if ("content".equals(key)) { @@ -521,7 +552,7 @@ public static String toString(final Object object, final String tagName) i++; } } else { - sb.append(escape(value.toString())); + sb.append(escape(String.valueOf(value))); } // Emit an array of similar keys @@ -544,10 +575,20 @@ public static String toString(final Object object, final String tagName) } else if ("".equals(value)) { sb.append('<'); sb.append(key); - sb.append("/>"); + sb.append('>'); + sb.append("'); // Emit a new tag + } else if (value == null) { + sb.append('<'); + sb.append(key); + sb.append("/>"); + + // Emit a new empty tag + } else { sb.append(toString(value, key)); } @@ -563,19 +604,21 @@ public static String toString(final Object object, final String tagName) } - if (object != null && (object instanceof JSONArray || object.getClass().isArray())) { - if(object.getClass().isArray()) { - ja = new JSONArray(object); - } else { - ja = (JSONArray) object; + if (object != null) { + if (object.getClass().isArray()) { + object = new JSONArray(object); } - for (Object val : ja) { - // XML does not have good support for arrays. If an array - // appears in a place where XML is lacking, synthesize an - // element. - sb.append(toString(val, tagName == null ? "array" : tagName)); + + if (object instanceof JSONArray) { + ja = (JSONArray) object; + for (Object val : ja) { + // XML does not have good support for arrays. If an array + // appears in a place where XML is lacking, synthesize an + // element. + sb.append(toString(val, tagName == null ? "array" : tagName)); + } + return sb.toString(); } - return sb.toString(); } string = (object == null) ? "null" : escape(object.toString());