Skip to content

Commit 829a11b

Browse files
committed
Sync with underscore-java.
1 parent 11e8163 commit 829a11b

File tree

4 files changed

+106
-25
lines changed

4 files changed

+106
-25
lines changed

src/main/java/com/github/underscore/lodash/U.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ public enum Mode {
9797
REPLACE_SELF_CLOSING_WITH_NULL,
9898
REPLACE_SELF_CLOSING_WITH_EMPTY,
9999
REPLACE_EMPTY_VALUE_WITH_NULL,
100-
FORCE_ATTRIBUTE_USAGE
100+
FORCE_ATTRIBUTE_USAGE,
101+
DEFINE_ROOT_NAME,
102+
FORCE_ATTRIBUTE_USAGE_AND_DEFINE_ROOT_NAME
101103
}
102104

103105
public U(final Iterable<T> iterable) {
@@ -2220,6 +2222,7 @@ public static Map<String, Object> fromJsonMap(final String string) {
22202222
return getStringObjectMap(object);
22212223
}
22222224

2225+
@SuppressWarnings("unchecked")
22232226
private static Map<String, Object> getStringObjectMap(Object object) {
22242227
final Map<String, Object> result;
22252228
if (object instanceof Map) {
@@ -2240,12 +2243,16 @@ public Object fromXml() {
22402243
}
22412244

22422245
@SuppressWarnings("unchecked")
2243-
public static String jsonToXml(String json, Xml.XmlStringBuilder.Step identStep, Mode mode) {
2246+
public static String jsonToXml(String json, Xml.XmlStringBuilder.Step identStep, Mode mode, String newRootName) {
22442247
Object object = Json.fromJson(json);
22452248
final String result;
22462249
if (object instanceof Map) {
22472250
if (mode == Mode.FORCE_ATTRIBUTE_USAGE) {
22482251
result = Xml.toXml(forceAttributeUsage((Map) object), identStep);
2252+
} else if (mode == Mode.DEFINE_ROOT_NAME) {
2253+
result = Xml.toXml((Map) object, identStep, newRootName);
2254+
} else if (mode == Mode.FORCE_ATTRIBUTE_USAGE_AND_DEFINE_ROOT_NAME) {
2255+
result = Xml.toXml(forceAttributeUsage((Map) object), identStep, newRootName);
22492256
} else {
22502257
result = Xml.toXml((Map) object, identStep);
22512258
}
@@ -2255,11 +2262,19 @@ public static String jsonToXml(String json, Xml.XmlStringBuilder.Step identStep,
22552262
}
22562263

22572264
public static String jsonToXml(String json, Mode mode) {
2258-
return jsonToXml(json, Xml.XmlStringBuilder.Step.TWO_SPACES, mode);
2265+
return jsonToXml(json, Xml.XmlStringBuilder.Step.TWO_SPACES, mode, null);
2266+
}
2267+
2268+
public static String jsonToXml(String json, Mode mode, String newRootName) {
2269+
return jsonToXml(json, Xml.XmlStringBuilder.Step.TWO_SPACES, mode, newRootName);
2270+
}
2271+
2272+
public static String jsonToXml(String json, String newRootName) {
2273+
return jsonToXml(json, Xml.XmlStringBuilder.Step.TWO_SPACES, Mode.DEFINE_ROOT_NAME, newRootName);
22592274
}
22602275

22612276
public static String jsonToXml(String json) {
2262-
return jsonToXml(json, Xml.XmlStringBuilder.Step.TWO_SPACES, null);
2277+
return jsonToXml(json, Xml.XmlStringBuilder.Step.TWO_SPACES, null, null);
22632278
}
22642279

22652280
@SuppressWarnings("unchecked")

src/main/java/com/github/underscore/lodash/Xml.java

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public final class Xml {
6363
private static final String QUOT = "&quot;";
6464
private static final String XML_HEADER = "<?xml ";
6565
private static final String DOCTYPE_TEXT = "!DOCTYPE";
66+
private static final String ROOT = "root";
6667
private static final String DOCTYPE_HEADER = "<" + DOCTYPE_TEXT + " ";
6768
private static final java.nio.charset.Charset UTF_8 = java.nio.charset.Charset.forName("UTF-8");
6869
private static final java.util.regex.Pattern ATTRS = java.util.regex.Pattern.compile(
@@ -795,7 +796,7 @@ private static void escape(String s, StringBuilder sb) {
795796
sb.append("\n");
796797
break;
797798
case '\r':
798-
sb.append("\\r");
799+
sb.append("&#xD;");
799800
break;
800801
case '\t':
801802
sb.append("\t");
@@ -889,6 +890,10 @@ public static String toXml(Collection collection) {
889890
}
890891

891892
public static String toXml(Map map, XmlStringBuilder.Step identStep) {
893+
return toXml(map, identStep, ROOT);
894+
}
895+
896+
public static String toXml(Map map, XmlStringBuilder.Step identStep, String newRootName) {
892897
final XmlStringBuilder builder;
893898
final Map localMap;
894899
if (map != null && map.containsKey(ENCODING)) {
@@ -907,11 +912,11 @@ public static String toXml(Map map, XmlStringBuilder.Step identStep) {
907912
builder = new XmlStringBuilderWithoutRoot(identStep, UTF_8.name(), "");
908913
localMap = map;
909914
}
910-
checkLocalMap(builder, localMap);
915+
checkLocalMap(builder, localMap, newRootName);
911916
return builder.toString();
912917
}
913918

914-
private static void checkLocalMap(final XmlStringBuilder builder, final Map localMap) {
919+
private static void checkLocalMap(final XmlStringBuilder builder, final Map localMap, final String newRootName) {
915920
final Map localMap2;
916921
if (localMap != null && localMap.containsKey(DOCTYPE_TEXT)) {
917922
localMap2 = (Map) U.clone(localMap);
@@ -926,11 +931,12 @@ private static void checkLocalMap(final XmlStringBuilder builder, final Map loca
926931
if ("root".equals(XmlValue.getMapKey(localMap2))) {
927932
writeArray((List) XmlValue.getMapValue(localMap2), builder);
928933
} else {
929-
XmlObject.writeXml(localMap2, getRootName(localMap2), builder, false,
934+
XmlObject.writeXml(localMap2, getRootName(localMap2, newRootName), builder, false,
930935
U.<String>newLinkedHashSet(), false);
931936
}
932937
} else {
933-
XmlObject.writeXml(localMap2, getRootName(localMap2), builder, false, U.<String>newLinkedHashSet(), false);
938+
XmlObject.writeXml(localMap2, getRootName(localMap2, newRootName), builder,
939+
false, U.<String>newLinkedHashSet(), false);
934940
}
935941
}
936942

@@ -964,7 +970,7 @@ private static XmlStringBuilder checkStandalone(String encoding, XmlStringBuilde
964970
}
965971

966972
@SuppressWarnings("unchecked")
967-
private static String getRootName(final Map localMap) {
973+
private static String getRootName(final Map localMap, final String newRootName) {
968974
int foundAttrs = 0;
969975
int foundElements = 0;
970976
int foundListElements = 0;
@@ -982,15 +988,15 @@ private static String getRootName(final Map localMap) {
982988
}
983989
}
984990
}
985-
return foundAttrs == 0 && foundElements == 1 && foundListElements == 0 ? null : "root";
991+
return foundAttrs == 0 && foundElements == 1 && foundListElements == 0 ? null : newRootName;
986992
}
987993

988994
public static String toXml(Map map) {
989-
return toXml(map, XmlStringBuilder.Step.TWO_SPACES);
995+
return toXml(map, XmlStringBuilder.Step.TWO_SPACES, ROOT);
990996
}
991997

992998
@SuppressWarnings("unchecked")
993-
private static Object getValue(final Object value, final FromType fromType) {
999+
private static Object getValue(final String name, final Object value, final FromType fromType) {
9941000
final Object localValue;
9951001
if (value instanceof Map && ((Map<String, Object>) value).entrySet().size() == 1) {
9961002
final Map.Entry<String, Object> entry = ((Map<String, Object>) value).entrySet().iterator().next();
@@ -1003,7 +1009,8 @@ private static Object getValue(final Object value, final FromType fromType) {
10031009
} else {
10041010
localValue = value;
10051011
}
1006-
return localValue instanceof String ? XmlValue.unescape((String) localValue) : localValue;
1012+
return localValue instanceof String && name.startsWith("-")
1013+
? XmlValue.unescape((String) localValue) : localValue;
10071014
}
10081015

10091016
public static Object stringToNumber(String number) {
@@ -1099,9 +1106,9 @@ private static Object checkArray(final Map<String, Object> map, final String nam
10991106
localMap4.remove(ARRAY);
11001107
localMap4.remove(SELF_CLOSING);
11011108
object = name.equals(XmlValue.getMapKey(localMap4))
1102-
? U.newArrayList(Collections.singletonList(getValue(XmlValue.getMapValue(localMap4),
1109+
? U.newArrayList(Collections.singletonList(getValue(name, XmlValue.getMapValue(localMap4),
11031110
FromType.FOR_CONVERT)))
1104-
: U.newArrayList(Collections.singletonList(getValue(localMap4, FromType.FOR_CONVERT)));
1111+
: U.newArrayList(Collections.singletonList(getValue(name, localMap4, FromType.FOR_CONVERT)));
11051112
} else {
11061113
object = localMap;
11071114
}
@@ -1250,13 +1257,13 @@ private static void addNodeValue(final Map<String, Object> map, final String nam
12501257
final String elementName = unescapeName(elementMapper.apply(name, namespaces));
12511258
if (map.containsKey(elementName)) {
12521259
if (TEXT.equals(elementName)) {
1253-
map.put(elementName + uniqueIds[0], nodeMapper.apply(getValue(value, fromType)));
1260+
map.put(elementName + uniqueIds[0], nodeMapper.apply(getValue(name, value, fromType)));
12541261
uniqueIds[0] += 1;
12551262
} else if (COMMENT.equals(elementName)) {
1256-
map.put(elementName + uniqueIds[1], nodeMapper.apply(getValue(value, fromType)));
1263+
map.put(elementName + uniqueIds[1], nodeMapper.apply(getValue(name, value, fromType)));
12571264
uniqueIds[1] += 1;
12581265
} else if (CDATA.equals(elementName)) {
1259-
map.put(elementName + uniqueIds[2], nodeMapper.apply(getValue(value, fromType)));
1266+
map.put(elementName + uniqueIds[2], nodeMapper.apply(getValue(name, value, fromType)));
12601267
uniqueIds[2] += 1;
12611268
} else {
12621269
final Object object = map.get(elementName);
@@ -1271,7 +1278,7 @@ private static void addNodeValue(final Map<String, Object> map, final String nam
12711278
}
12721279
} else {
12731280
if (elementName != null) {
1274-
map.put(elementName, nodeMapper.apply(getValue(value, fromType)));
1281+
map.put(elementName, nodeMapper.apply(getValue(name, value, fromType)));
12751282
}
12761283
}
12771284
}
@@ -1292,7 +1299,7 @@ private static void addText(final Map<String, Object> map, final String name, fi
12921299
objects.add(index, item);
12931300
lastIndex -= 1;
12941301
}
1295-
final Object newValue = getValue(value, fromType);
1302+
final Object newValue = getValue(name, value, fromType);
12961303
if (newValue instanceof List) {
12971304
objects.add(((List) newValue).get(0));
12981305
} else {
@@ -1340,7 +1347,7 @@ private static boolean checkResult(final String xml, org.w3c.dom.Document docume
13401347
} else if (headerAttributes.containsKey(STANDALONE.substring(1))) {
13411348
((Map) result).put(STANDALONE, headerAttributes.get(STANDALONE.substring(1)));
13421349
} else if (fromType == FromType.FOR_CONVERT
1343-
&& ((Map.Entry) ((Map) result).entrySet().iterator().next()).getKey().equals("root")
1350+
&& ((Map.Entry) ((Map) result).entrySet().iterator().next()).getKey().equals(ROOT)
13441351
&& (((Map.Entry) ((Map) result).entrySet().iterator().next()).getValue() instanceof List
13451352
|| ((Map.Entry) ((Map) result).entrySet().iterator().next()).getValue() instanceof Map)) {
13461353
if (xml.startsWith(XML_HEADER)) {
@@ -1498,7 +1505,7 @@ public static Object fromXmlWithoutNamespacesAndAttributes(final String xml) {
14981505

14991506
public static String formatXml(String xml, XmlStringBuilder.Step identStep) {
15001507
Object result = fromXml(xml, FromType.FOR_FORMAT);
1501-
return toXml((Map) result, identStep);
1508+
return toXml((Map) result, identStep, ROOT);
15021509
}
15031510

15041511
public static String formatXml(String xml) {
@@ -1511,7 +1518,7 @@ public static String changeXmlEncoding(String xml, XmlStringBuilder.Step identSt
15111518
if (result instanceof Map) {
15121519
((Map) result).put(ENCODING, encoding);
15131520
}
1514-
return toXml((Map) result, identStep);
1521+
return toXml((Map) result, identStep, ROOT);
15151522
}
15161523

15171524
public static String changeXmlEncoding(String xml, String encoding) {

src/test/java/com/github/underscore/lodash/LodashTest.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,13 @@ public void xmlToJson() {
620620
U.replaceEmptyValueWithNull(map3);
621621
}
622622

623+
@Test
624+
public void xmlToJson2() {
625+
assertEquals("{\n"
626+
+ " \"debug\": \"&amp;\"\n"
627+
+ "}", U.xmlToJson("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<debug>&amp;amp;</debug>"));
628+
}
629+
623630
@Test
624631
public void removeMapKey() {
625632
Map<String, Object> map = U.newLinkedHashMap();
@@ -657,6 +664,19 @@ public void renameMapKey() {
657664
U.rename(map2, "test", "test1");
658665
}
659666

667+
@Test
668+
public void renameRoot() {
669+
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<json></json>",
670+
U.jsonToXml("{}", "json"));
671+
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<json>\n"
672+
+ " <a>b</a>\n"
673+
+ " <c>d</c>\n"
674+
+ "</json>",
675+
U.jsonToXml("{\"a\": \"b\", \"c\": \"d\"}", "json"));
676+
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<json a=\"b\" c=\"d\"></json>",
677+
U.jsonToXml("{\"a\": \"b\", \"c\": \"d\"}", U.Mode.FORCE_ATTRIBUTE_USAGE_AND_DEFINE_ROOT_NAME, "json"));
678+
}
679+
660680
@Test
661681
public void updateMapKey() {
662682
Map<String, Object> map = U.newLinkedHashMap();
@@ -1185,4 +1205,43 @@ public void sqlru2() {
11851205
// https://www.sql.ru/forum/1321326/kolichestvo-naydennyh-slov-v-stroke
11861206
assertEquals(2, U.countBy(U.words("Маша ищет Мишу а Миша ищет Машу")).get("ищет").intValue());
11871207
}
1208+
1209+
@Test
1210+
public void stackoverflow7() {
1211+
String json = U.objectBuilder()
1212+
.add("key1", "value1")
1213+
.add("key2", "value2")
1214+
.add("key3", U.objectBuilder()
1215+
.add("innerKey1", "value3"))
1216+
.toJson();
1217+
assertEquals("{\n \"key1\": \"value1\",\n"
1218+
+ " \"key2\": \"value2\",\n"
1219+
+ " \"key3\": {\n"
1220+
+ " \"innerKey1\": \"value3\"\n"
1221+
+ " }\n"
1222+
+ "}", json);
1223+
}
1224+
1225+
@Test
1226+
public void stackoverflow8() {
1227+
class Customer {
1228+
String name;
1229+
int age;
1230+
int id;
1231+
}
1232+
Customer customer = new Customer();
1233+
customer.name = "John";
1234+
customer.age = 30;
1235+
customer.id = 12345;
1236+
String xml = U.objectBuilder().add("customer", U.objectBuilder()
1237+
.add("name", customer.name)
1238+
.add("age", customer.age)
1239+
.add("id", customer.id)).toXml();
1240+
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1241+
+ "<customer>\n"
1242+
+ " <name>John</name>\n"
1243+
+ " <age number=\"true\">30</age>\n"
1244+
+ " <id number=\"true\">12345</id>\n"
1245+
+ "</customer>", xml);
1246+
}
11881247
}

src/test/java/com/github/underscore/lodash/StringTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,7 @@ public void escapeXml() {
10581058
assertEquals("\\b", Xml.XmlValue.escape("\b"));
10591059
assertEquals("\\f", Xml.XmlValue.escape("\f"));
10601060
assertEquals("\n", Xml.XmlValue.escape("\n"));
1061-
assertEquals("\\r", Xml.XmlValue.escape("\r"));
1061+
assertEquals("&#xD;", Xml.XmlValue.escape("\r"));
10621062
assertEquals("\t", Xml.XmlValue.escape("\t"));
10631063
assertEquals("/", Xml.XmlValue.escape("/"));
10641064
assertEquals("&#x0000;", Xml.XmlValue.escape("\u0000"));

0 commit comments

Comments
 (0)