• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.draft;
2 
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.PrintWriter;
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Collection;
9 import java.util.Collections;
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.LinkedHashMap;
13 import java.util.LinkedHashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.TreeMap;
18 import java.util.TreeSet;
19 
20 import org.unicode.cldr.util.CLDRFile;
21 import org.unicode.cldr.util.CLDRPaths;
22 import org.unicode.cldr.util.DtdType;
23 import org.unicode.cldr.util.ElementAttributeInfo;
24 import org.unicode.cldr.util.Factory;
25 import org.unicode.cldr.util.XPathParts;
26 
27 import com.ibm.icu.impl.Relation;
28 import com.ibm.icu.impl.Row;
29 import com.ibm.icu.impl.Row.R2;
30 import com.ibm.icu.impl.Utility;
31 import com.ibm.icu.util.ICUUncheckedIOException;
32 
33 public class JsonConverter {
34 
35     private static final String FILES = "el.*";
36     private static final String MAIN_DIRECTORY = CLDRPaths.MAIN_DIRECTORY;// CldrUtility.SUPPLEMENTAL_DIRECTORY;
37                                                                           // //CldrUtility.MAIN_DIRECTORY;
38     private static final String OUT_DIRECTORY = CLDRPaths.GEN_DIRECTORY + "/jason/"; // CldrUtility.MAIN_DIRECTORY;
39     private static boolean COMPACT = false;
40     static final Set<String> REPLACING_BASE = !COMPACT ? Collections.EMPTY_SET : new HashSet<>(
41         Arrays.asList("type id key count".split("\\s")));
42     static final Set<String> EXTRA_DISTINGUISHING = new HashSet<>(
43         Arrays.asList("locales territory desired supported".split("\\s")));
44     static final Relation<String, String> mainInfo = ElementAttributeInfo.getInstance(DtdType.ldml)
45         .getElement2Attributes();
46     static final Relation<String, String> suppInfo = ElementAttributeInfo.getInstance(DtdType.supplementalData)
47         .getElement2Attributes();
48 
main(String[] args)49     public static void main(String[] args) throws IOException {
50         final String subdirectory = new File(MAIN_DIRECTORY).getName();
51         final Factory cldrFactory = Factory.make(MAIN_DIRECTORY, FILES);
52         final Set<String> locales = new TreeSet<>(cldrFactory.getAvailable());
53         /*
54          * TODO: "parts" is always empty, so all the code using it is wasted!
55          */
56         final XPathParts parts = new XPathParts();
57         for (String locale : locales) {
58             System.out.println("Converting:\t" + locale);
59             final CLDRFile file = cldrFactory.make(locale, false);
60             Relation<String, String> element2Attributes = file.isNonInheriting() ? suppInfo : mainInfo;
61             final Item main = new TableItem(null);
62             DtdType dtdType = null;
63             for (Iterator<String> it = file.iterator("", file.getComparator()); it.hasNext();) {
64                 final String xpath = it.next();
65                 final String fullXpath = file.getFullXPath(xpath);
66                 String value = file.getStringValue(xpath);
67                 XPathParts oldParts = XPathParts.getFrozenInstance(fullXpath).cloneAsThawed(); // not frozen, rewrite can modify
68                 if (dtdType == null) {
69                     dtdType = DtdType.valueOf(parts.getElement(0));
70                 }
71                 rewrite(dtdType, oldParts, value, element2Attributes, parts);
72                 System.out.println(parts);
73                 Item current = main;
74                 int size = parts.size();
75 
76                 for (int i = 0; i < size - 1; ++i) {
77                     final String element = parts.getElement(i);
78                     Map<String, String> actualAttributeKeys = parts.getAttributes(i);
79                     Set<String> keySet = actualAttributeKeys.keySet();
80                     if (keySet.size() != 0) {
81                         Item temp = current.makeSubItem(element, Item.Type.unorderedItem);
82                         for (String attribute : keySet) {
83                             temp.put(attribute, actualAttributeKeys.get(attribute));
84                         }
85                     }
86                     if (i < size - 2) {
87                         current = current.makeSubItem(element,
88                             actualAttributeKeys.containsKey("_q") ? Item.Type.orderedItem : Item.Type.unorderedItem);
89                     } else {
90                         current.put(element, parts.getElement(i + 1));
91                     }
92                 }
93             }
94             PrintWriter out = FileUtilities.openUTF8Writer(OUT_DIRECTORY + subdirectory, locale + ".json");
95             main.print(out, 0);
96             out.close();
97         }
98     }
99 
100     static Relation<String, String> extraDistinguishing = Relation.of(new TreeMap<String, Set<String>>(), LinkedHashSet.class);
101     static {
putAll(extraDistinguishing, "dayPeriodRule", "earlyMorning", "before", "from")102         putAll(extraDistinguishing, "dayPeriodRule", "earlyMorning", "before", "from");
103     }
104 
putAll(Relation r, K key, V... values)105     static <K, V> void putAll(Relation r, K key, V... values) {
106         r.putAll(key, Arrays.asList(values));
107     }
108 
isDistinguishing(DtdType dtdType, final String element, final String attribute)109     private static boolean isDistinguishing(DtdType dtdType, final String element, final String attribute) {
110         // <mapZone other="Afghanistan" territory="001" type="Asia/Kabul"/> result is the type!
111         // <deprecatedItems elements="variant" attributes="type" values="BOKMAL NYNORSK AALAND POLYTONI"/>
112         // ugly: if there are values, then everything else is distinguishing, ow if there are attibutes, elements are
113         if (element.equals("deprecatedItems")) {
114 
115         }
116         Set<String> extras = extraDistinguishing.getAll(element);
117         if (extras != null && extras.contains(attribute)) return true;
118         if (EXTRA_DISTINGUISHING.contains(attribute)) return true;
119         return CLDRFile.isDistinguishing(dtdType, element, attribute);
120     }
121 
rewrite(DtdType dtdType, XPathParts parts, String value, Relation<String, String> element2Attributes, XPathParts out)122     private static void rewrite(DtdType dtdType, XPathParts parts, String value,
123         Relation<String, String> element2Attributes, XPathParts out) {
124         out.clear();
125         int size = parts.size();
126         for (int i = 1; i < size; ++i) {
127             final String element = parts.getElement(i);
128             out.addElement(element);
129 
130             // turn a path into a revised path. All distinguished attributes (including those not currently on the
131             // string)
132             // get turned into extra element/element pairs, starting with _
133             // all non-distinguishing attributes get turned into separate children
134             // a/b[@non="y"][@dist="x"]/w : z =>
135             // a/b/_dist/x/_non=y
136             // a/b/_dist/x/w=z
137             Collection<String> actualAttributeKeys = parts.getAttributeKeys(i);
138             boolean isOrdered = actualAttributeKeys.contains("_q");
139             Set<String> possibleAttributeKeys = element2Attributes.getAll(element);
140 
141             for (final String attribute : actualAttributeKeys) {
142                 String attributeValue = parts.getAttributeValue(i, attribute);
143                 if (!isDistinguishing(dtdType, element, attribute)) {
144                     out.addAttribute(attribute, attributeValue);
145                 }
146             }
147             if (possibleAttributeKeys != null) {
148                 for (final String attribute : possibleAttributeKeys) {
149                     if (isDistinguishing(dtdType, element, attribute)) {
150                         if (attribute.equals("alt")) {
151                             // TODO fix
152                             System.err.println("Warning: Unhandled ALT: " + parts.toString());
153                         }
154                         String attributeValue = parts.getAttributeValue(i, attribute);
155                         out.addElement("_" + attribute);
156                         if (attributeValue == null) {
157                             attributeValue = "?";
158                         }
159                         out.addElement(attributeValue);
160                     }
161                 }
162             }
163             if (isOrdered) {
164                 Map<String, String> lastAttributes = out.getAttributes(-2);
165                 lastAttributes.put("_q", "_q");
166             }
167         }
168         if (value.length() > 0) {
169             out.addElement(value);
170         }
171 
172         if (!COMPACT) {
173             return;
174         }
175         if (parts.getElement(-1).equals("type")) {
176             String key = parts.getAttributeValue(-1, "key");
177             if (key != null) {
178                 parts.setElement(-2, key + "Key");
179                 parts.putAttributeValue(-1, "key", null);
180             }
181             // fall thru
182         }
183         if (parts.getElement(1).equals("localeDisplayNames")) {
184             String element2 = parts.getElement(2);
185             if (!element2.endsWith("Pattern")) {
186                 if (element2.endsWith("s")) {
187                     element2 = element2.substring(0, element2.length() - 1);
188                 }
189                 parts.setElement(2, element2 + "Names");
190             }
191             parts.removeElement(1);
192         }
193         if (parts.getElement(1).equals("dates")) {
194             parts.removeElement(1);
195             String element1 = parts.getElement(1);
196             if (element1.equals("timeZoneNames")) {
197                 String main = parts.getElement(2);
198                 if (main.equals("zone") || main.equals("metazone")) {
199                     parts.setElement(1, main + "Names");
200                 }
201                 return;
202             }
203         }
204         if (parts.getElement(1).equals("numbers") && parts.getElement(2).equals("currencies")) {
205             parts.removeElement(1);
206             return;
207         }
208     }
209 
210     static class ElementName {
211         String oldBase;
212         String base;
213         boolean replacedBase;
214         StringBuilder suffix = new StringBuilder();
215 
reset(String element)216         public void reset(String element) {
217             suffix.setLength(0);
218             base = oldBase = element;
219             replacedBase = false;
220         }
221 
add(String attribute, String attributeValue)222         public void add(String attribute, String attributeValue) {
223             if (REPLACING_BASE.contains(attribute)) {
224                 if (replacedBase) {
225                     System.out.println("ERROR: Two replacement types on same element!!\t" + oldBase + "," + base + ","
226                         + attribute + "," + attributeValue);
227                 } else {
228                     replacedBase = true;
229                     base = attributeValue;
230                     return;
231                 }
232             }
233             suffix.append('$').append(attribute).append('=').append(attributeValue);
234         }
235 
236         @Override
toString()237         public String toString() {
238             if (suffix == null) {
239                 return base;
240             }
241             return base + suffix;
242         }
243     }
244 
245     static abstract class Item {
246         protected Item parent;
247 
Item(Item parent)248         public Item(Item parent) {
249             this.parent = parent;
250         }
251 
size()252         public abstract int size();
253 
254         enum Type {
255             unorderedItem, orderedItem
256         }
257 
print(Appendable result, int i)258         public abstract Appendable print(Appendable result, int i);
259 
indent(Appendable result, int i)260         protected Appendable indent(Appendable result, int i) throws IOException {
261             return result.append(getIndent(i));
262         }
263 
getIndent(int i)264         protected String getIndent(int i) {
265             return Utility.repeat("    ", i);
266         }
267 
appendString(Appendable result, String string, int indent)268         public Appendable appendString(Appendable result, String string, int indent) throws IOException {
269             result.append('"');
270             for (int i = 0; i < string.length(); ++i) {
271                 // http://www.json.org/
272                 // any-Unicode-character-except-"-or-\-or-control-character
273                 // uses UTF16
274                 char ch = string.charAt(i);
275                 switch (ch) {
276                 case '\"':
277                     result.append("\\\"");
278                     break;
279                 case '\\':
280                     result.append("\\\\");
281                     break;
282                 case '/':
283                     result.append("\\/");
284                     break;
285                 case '\b':
286                     result.append("\\b");
287                     break;
288                 case '\f':
289                     result.append("\\f");
290                     break;
291                 case '\n':
292                     if (indent < 0) {
293                         result.append("\\n");
294                     } else {
295                         result.append('\n').append(getIndent(indent));
296                     }
297                     break;
298                 case '\r':
299                     result.append("\\r");
300                     break;
301                 case '\t':
302                     result.append("\\t");
303                     break;
304                 default:
305                     if (ch <= 0x1F || 0x7F <= ch && ch <= 0x9F) {
306                         result.append("\\u").append(Utility.hex(ch, 4));
307                     } else {
308                         result.append(ch);
309                     }
310                     break;
311                 }
312             }
313             return result.append('"');
314         }
315 
316         @Override
toString()317         public String toString() {
318             return print(new StringBuilder(), 0).toString();
319         }
320 
create(Type ordered)321         protected Item create(Type ordered) {
322             switch (ordered) {
323             case unorderedItem:
324                 return new TableItem(this);
325             case orderedItem:
326                 return new ArrayItem(this);
327             default:
328                 throw new UnsupportedOperationException();
329             }
330         }
331 
makeSubItem(String element, Type ordered)332         public abstract Item makeSubItem(String element, Type ordered);
333 
put(String element, String value)334         public abstract void put(String element, String value);
335 
getRoot()336         public Item getRoot() {
337             if (parent == null) {
338                 return this;
339             } else {
340                 return parent.getRoot();
341             }
342         }
343     }
344 
345     static class TableItem extends Item {
TableItem(Item parent)346         public TableItem(Item parent) {
347             super(parent);
348         }
349 
350         private Map<String, Item> map = new LinkedHashMap<>();
351 
get(String element)352         public Item get(String element) {
353             return map.get(element);
354         }
355 
356         @Override
put(String element, String value)357         public void put(String element, String value) {
358             Item old = map.get(element);
359             if (old != null) {
360                 if (old instanceof StringItem) {
361                     if (value.equals(((StringItem) old).value)) {
362                         return;
363                     }
364                 }
365                 throw new IllegalArgumentException("ERROR: Table already has object: " + element + ", " + old + ", "
366                     + value + ", " + getRoot().toString());
367             }
368             map.put(element, new StringItem(value));
369         }
370 
371         @Override
makeSubItem(String element, Type ordered)372         public Item makeSubItem(String element, Type ordered) {
373             Item result = map.get(element);
374             if (result != null) {
375                 return result;
376             }
377             result = create(ordered);
378             result.parent = this;
379 
380             map.put(element, result);
381             return result;
382         }
383 
384         @Override
print(Appendable result, int i)385         public Appendable print(Appendable result, int i) {
386             try {
387                 if (map.size() == 0) {
388                     result.append("{}");
389                     return result;
390                 }
391                 result.append("{\n");
392                 boolean first = true;
393                 for (String key : map.keySet()) {
394                     Item value = map.get(key);
395                     if (first) {
396                         first = false;
397                     } else {
398                         result.append(",\n");
399                     }
400                     indent(result, i + 1);
401                     appendString(result, key, -1).append(" : ");
402                     value.print(result, i + 1);
403                 }
404                 result.append("\n");
405                 indent(result, i).append("}");
406                 return result;
407             } catch (IOException e) {
408                 throw new ICUUncheckedIOException(e);
409             }
410         }
411 
412         @Override
size()413         public int size() {
414             return map.size();
415         }
416     }
417 
418     static class ArrayItem extends Item {
ArrayItem(Item parent)419         public ArrayItem(Item parent) {
420             super(parent);
421         }
422 
423         private List<Row.R2<String, Item>> list = new ArrayList<>();
424 
425         @Override
print(Appendable result, int i)426         public Appendable print(Appendable result, int i) {
427             try {
428                 if (list.size() == 0) {
429                     result.append("[]");
430                     return result;
431                 }
432 
433                 result.append("[\n");
434                 for (int j = 0; j < list.size(); ++j) {
435                     if (j != 0) {
436                         result.append(",\n");
437                     }
438                     indent(result, i + 1);
439                     R2<String, Item> row = list.get(j);
440                     result.append("{");
441                     appendString(result, row.get0(), i + 1);
442                     result.append(" : ");
443                     row.get1().print(result, i + 1);
444                     result.append("}");
445                 }
446                 result.append("\n");
447                 indent(result, i).append("]");
448                 return result;
449             } catch (IOException e) {
450                 throw new IllegalArgumentException(e);
451             }
452         }
453 
454         @Override
makeSubItem(String element, Type ordered)455         public Item makeSubItem(String element, Type ordered) {
456             Item result = create(ordered);
457             list.add(Row.of(element, result));
458             return result;
459         }
460 
461         @Override
put(String element, String value)462         public void put(String element, String value) {
463             list.add(Row.of(element, (Item) new StringItem(value)));
464         }
465 
466         @Override
size()467         public int size() {
468             return list.size();
469         }
470     }
471 
472     static class StringItem extends Item {
473         private String value;
474 
StringItem(String value2)475         public StringItem(String value2) {
476             super(null);
477             value = value2;
478         }
479 
480         @Override
print(Appendable result, int i)481         public Appendable print(Appendable result, int i) {
482             try {
483                 return appendString(result, value, i + 1);
484             } catch (IOException e) {
485                 throw new IllegalArgumentException(e);
486             }
487         }
488 
489         @Override
makeSubItem(String element, Type ordered)490         public Item makeSubItem(String element, Type ordered) {
491             throw new UnsupportedOperationException();
492         }
493 
494         @Override
put(String element, String value)495         public void put(String element, String value) {
496             throw new UnsupportedOperationException();
497         }
498 
499         @Override
size()500         public int size() {
501             throw new UnsupportedOperationException();
502         }
503     }
504 }
505