make/src/classes/build/tools/cldrconverter/LDMLParseHandler.java
Print this page
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
@@ -27,13 +27,15 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Set;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
@@ -45,10 +47,12 @@
private String currentNumberingSystem = "";
private CalendarType currentCalendarType;
private String zoneNameStyle; // "long" or "short" for time zone names
private String zonePrefix;
private final String id;
+ private String currentContext = ""; // "format"/"stand-alone"
+ private String currentWidth = ""; // "wide"/"narrow"/"abbreviated"
LDMLParseHandler(String id) {
this.id = id;
}
@@ -110,13 +114,14 @@
break;
// Calendar or currency
case "displayName":
{
- if (currentCalendarType != null) {
+ if (currentContainer.getqName().equals("field")) {
pushStringEntry(qName, attributes,
- currentCalendarType.keyElementName() + "field." + getContainerKey());
+ (currentCalendarType != null ? currentCalendarType.keyElementName() : "")
+ + "field." + getContainerKey());
} else {
// for CurrencyNames
// need to get the key from the containing <currency> element
// ignore if is has "count" attribute
String containerKey = getContainerKey();
@@ -147,14 +152,12 @@
pushIgnoredContainer(qName);
}
}
break;
case "fields":
- if (currentCalendarType != null) {
+ {
pushContainer(qName, attributes);
- } else {
- pushIgnoredContainer(qName);
}
break;
case "field":
{
String type = attributes.getValue("type");
@@ -181,10 +184,11 @@
{
// for FormatData
// need to keep stand-alone and format, to allow for inheritance in CLDR
String type = attributes.getValue("type");
if ("stand-alone".equals(type) || "format".equals(type)) {
+ currentContext = type;
pushKeyContainer(qName, attributes, type);
} else {
pushIgnoredContainer(qName);
}
}
@@ -192,12 +196,17 @@
case "monthWidth":
{
// for FormatData
// create string array for the two types that the JRE knows
// keep info about the context type so we can sort out inheritance later
+ if (currentCalendarType == null) {
+ pushIgnoredContainer(qName);
+ break;
+ }
String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName();
- switch (attributes.getValue("type")) {
+ currentWidth = attributes.getValue("type");
+ switch (currentWidth) {
case "wide":
pushStringArrayEntry(qName, attributes, prefix + "MonthNames/" + getContainerKey(), 13);
break;
case "abbreviated":
pushStringArrayEntry(qName, attributes, prefix + "MonthAbbreviations/" + getContainerKey(), 13);
@@ -220,10 +229,11 @@
{
// for FormatData
// need to keep stand-alone and format, to allow for multiple inheritance in CLDR
String type = attributes.getValue("type");
if ("stand-alone".equals(type) || "format".equals(type)) {
+ currentContext = type;
pushKeyContainer(qName, attributes, type);
} else {
pushIgnoredContainer(qName);
}
}
@@ -232,11 +242,12 @@
{
// for FormatData
// create string array for the two types that the JRE knows
// keep info about the context type so we can sort out inheritance later
String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName();
- switch (attributes.getValue("type")) {
+ currentWidth = attributes.getValue("type");
+ switch (currentWidth) {
case "wide":
pushStringArrayEntry(qName, attributes, prefix + "DayNames/" + getContainerKey(), 7);
break;
case "abbreviated":
pushStringArrayEntry(qName, attributes, prefix + "DayAbbreviations/" + getContainerKey(), 7);
@@ -261,20 +272,22 @@
// for FormatData
// need to keep stand-alone and format, to allow for multiple inheritance in CLDR
{
String type = attributes.getValue("type");
if ("stand-alone".equals(type) || "format".equals(type)) {
+ currentContext = type;
pushKeyContainer(qName, attributes, type);
} else {
pushIgnoredContainer(qName);
}
}
break;
case "dayPeriodWidth":
// for FormatData
// create string array entry for am/pm. only keeping wide
- switch (attributes.getValue("type")) {
+ currentWidth = attributes.getValue("type");
+ switch (currentWidth) {
case "wide":
pushStringArrayEntry(qName, attributes, "AmPmMarkers/" + getContainerKey(), 2);
break;
case "narrow":
pushStringArrayEntry(qName, attributes, "narrow.AmPmMarkers/" + getContainerKey(), 2);
@@ -360,10 +373,11 @@
{
// for FormatData
// need to keep stand-alone and format, to allow for inheritance in CLDR
String type = attributes.getValue("type");
if ("stand-alone".equals(type) || "format".equals(type)) {
+ currentContext = type;
pushKeyContainer(qName, attributes, type);
} else {
pushIgnoredContainer(qName);
}
}
@@ -371,11 +385,12 @@
case "quarterWidth":
{
// for FormatData
// keep info about the context type so we can sort out inheritance later
String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName();
- switch (attributes.getValue("type")) {
+ currentWidth = attributes.getValue("type");
+ switch (currentWidth) {
case "wide":
pushStringArrayEntry(qName, attributes, prefix + "QuarterNames/" + getContainerKey(), 4);
break;
case "abbreviated":
pushStringArrayEntry(qName, attributes, prefix + "QuarterAbbreviations/" + getContainerKey(), 4);
@@ -448,16 +463,24 @@
}
break;
case "currencyFormat":
// for FormatData
// copy string for later assembly into NumberPatterns
+ if (attributes.getValue("type").equals("standard")) {
pushStringEntry(qName, attributes, "NumberPatterns/currency");
+ } else {
+ pushIgnoredContainer(qName);
+ }
break;
case "percentFormat":
// for FormatData
// copy string for later assembly into NumberPatterns
+ if (attributes.getValue("type").equals("standard")) {
pushStringEntry(qName, attributes, "NumberPatterns/percent");
+ } else {
+ pushIgnoredContainer(qName);
+ }
break;
case "defaultNumberingSystem":
// default numbering system if multiple numbering systems are used.
pushStringEntry(qName, attributes, "DefaultNumberingSystem");
break;
@@ -580,16 +603,16 @@
// copy string for later assembly into DateTimePatterns
String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName();
pushStringEntry(qName, attributes, prefix + "DateTimePatterns/" + attributes.getValue("type") + "-date");
}
break;
- case "dateTimeFormat":
+ case "dateTimeFormatLength":
{
// for FormatData
// copy string for later assembly into DateTimePatterns
String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName();
- pushStringEntry(qName, attributes, prefix + "DateTimePatterns/date-time");
+ pushStringEntry(qName, attributes, prefix + "DateTimePatterns/" + attributes.getValue("type") + "-dateTime");
}
break;
case "localizedPatternChars":
{
// for FormatData
@@ -597,17 +620,209 @@
String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName();
pushStringEntry(qName, attributes, prefix + "DateTimePatternChars");
}
break;
+ // "alias" for root
+ case "alias":
+ {
+ if (id.equals("root") &&
+ !isIgnored(attributes) &&
+ currentCalendarType != null &&
+ !currentCalendarType.lname().startsWith("islamic-")) { // ignore Islamic variants
+ pushAliasEntry(qName, attributes, attributes.getValue("path"));
+ } else {
+ pushIgnoredContainer(qName);
+ }
+ }
+ break;
+
default:
// treat anything else as a container
pushContainer(qName, attributes);
break;
}
}
+ private static final String[] CONTEXTS = {"stand-alone", "format"};
+ private static final String[] WIDTHS = {"wide", "narrow", "abbreviated"};
+ private static final String[] LENGTHS = {"full", "long", "medium", "short"};
+
+ private void populateWidthAlias(String type, Set<String> keys) {
+ for (String context : CONTEXTS) {
+ for (String width : WIDTHS) {
+ String keyName = toJDKKey(type+"Width", context, width);
+ if (keyName.length() > 0) {
+ keys.add(keyName + "," + context + "," + width);
+ }
+ }
+ }
+ }
+
+ private void populateFormatLengthAlias(String type, Set<String> keys) {
+ for (String length: LENGTHS) {
+ String keyName = toJDKKey(type+"FormatLength", currentContext, length);
+ if (keyName.length() > 0) {
+ keys.add(keyName + "," + currentContext + "," + length);
+ }
+ }
+ }
+
+ private Set<String> populateAliasKeys(String qName, String context, String width) {
+ HashSet<String> ret = new HashSet<>();
+ String keyName = qName;
+
+ switch (qName) {
+ case "monthWidth":
+ case "dayWidth":
+ case "quarterWidth":
+ case "dayPeriodWidth":
+ case "dateFormatLength":
+ case "timeFormatLength":
+ case "dateTimeFormatLength":
+ case "eraNames":
+ case "eraAbbr":
+ case "eraNarrow":
+ ret.add(toJDKKey(qName, context, width) + "," + context + "," + width);
+ break;
+ case "days":
+ populateWidthAlias("day", ret);
+ break;
+ case "months":
+ populateWidthAlias("month", ret);
+ break;
+ case "quarters":
+ populateWidthAlias("quarter", ret);
+ break;
+ case "dayPeriods":
+ populateWidthAlias("dayPeriod", ret);
+ break;
+ case "eras":
+ ret.add(toJDKKey("eraNames", context, width) + "," + context + "," + width);
+ ret.add(toJDKKey("eraAbbr", context, width) + "," + context + "," + width);
+ ret.add(toJDKKey("eraNarrow", context, width) + "," + context + "," + width);
+ break;
+ case "dateFormats":
+ populateFormatLengthAlias("date", ret);
+ break;
+ case "timeFormats":
+ populateFormatLengthAlias("time", ret);
+ break;
+ default:
+ break;
+ }
+ return ret;
+ }
+
+ private String translateWidthAlias(String qName, String context, String width) {
+ String keyName = qName;
+ String type = Character.toUpperCase(qName.charAt(0)) + qName.substring(1, qName.indexOf("Width"));
+
+ switch (width) {
+ case "wide":
+ keyName = type + "Names/" + context;
+ break;
+ case "abbreviated":
+ keyName = type + "Abbreviations/" + context;
+ break;
+ case "narrow":
+ keyName = type + "Narrows/" + context;
+ break;
+ default:
+ assert false;
+ }
+
+ return keyName;
+ }
+
+ private String toJDKKey(String containerqName, String context, String type) {
+ String keyName = containerqName;
+
+ switch (containerqName) {
+ case "monthWidth":
+ case "dayWidth":
+ case "quarterWidth":
+ keyName = translateWidthAlias(keyName, context, type);
+ break;
+ case "dayPeriodWidth":
+ switch (type) {
+ case "wide":
+ keyName = "AmPmMarkers/" + context;
+ break;
+ case "narrow":
+ keyName = "narrow.AmPmMarkers/" + context;
+ break;
+ case "abbreviated":
+ keyName = "";
+ break;
+ }
+ break;
+ case "dateFormatLength":
+ case "timeFormatLength":
+ case "dateTimeFormatLength":
+ keyName = "DateTimePatterns/" +
+ type + "-" +
+ keyName.substring(0, keyName.indexOf("FormatLength"));
+ break;
+ case "eraNames":
+ keyName = "long.Eras";
+ break;
+ case "eraAbbr":
+ keyName = "Eras";
+ break;
+ case "eraNarrow":
+ keyName = "narrow.Eras";
+ break;
+ case "dateFormats":
+ case "timeFormats":
+ case "days":
+ case "months":
+ case "quarters":
+ case "dayPeriods":
+ case "eras":
+ break;
+ default:
+ keyName = "";
+ break;
+ }
+
+ return keyName;
+ }
+
+ private String getTarget(String qName, String path, String calType, String context, String width) {
+ // qName
+ int lastSlash = path.lastIndexOf('/');
+ qName = path.substring(lastSlash+1);
+ int bracket = qName.indexOf('[');
+ if (bracket != -1) {
+ qName = qName.substring(0, bracket);
+ }
+
+ // calType
+ String typeKey = "/calendar[@type='";
+ int start = path.indexOf(typeKey);
+ if (start != -1) {
+ calType = path.substring(start+typeKey.length(), path.indexOf("']", start));
+ }
+
+ // context
+ typeKey = "Context[@type='";
+ start = path.indexOf(typeKey);
+ if (start != -1) {
+ context = (path.substring(start+typeKey.length(), path.indexOf("']", start)));
+ }
+
+ // width
+ typeKey = "Width[@type='";
+ start = path.indexOf(typeKey);
+ if (start != -1) {
+ width = path.substring(start+typeKey.length(), path.indexOf("']", start));
+ }
+
+ return calType + "." + toJDKKey(qName, context, width);
+ }
+
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
assert qName.equals(currentContainer.getqName()) : "current=" + currentContainer.getqName() + ", param=" + qName;
switch (qName) {
case "calendar":
@@ -626,27 +841,71 @@
break;
case "timeZoneNames":
zonePrefix = null;
break;
+
case "generic":
case "standard":
case "daylight":
if (zonePrefix != null && (currentContainer instanceof Entry)) {
@SuppressWarnings("unchecked")
Map<String, String> valmap = (Map<String, String>) get(zonePrefix + getContainerKey());
Entry<?> entry = (Entry<?>) currentContainer;
valmap.put(entry.getKey(), (String) entry.getValue());
}
break;
+
+ case "monthWidth":
+ case "dayWidth":
+ case "dayPeriodWidth":
+ case "quarterWidth":
+ currentWidth = "";
+ putIfEntry();
+ break;
+
+ case "monthContext":
+ case "dayContext":
+ case "dayPeriodContext":
+ case "quarterContext":
+ currentContext = "";
+ putIfEntry();
+ break;
+
default:
- if (currentContainer instanceof Entry) {
+ putIfEntry();
+ }
+ currentContainer = currentContainer.getParent();
+ }
+
+ private void putIfEntry() {
+ if (currentContainer instanceof AliasEntry) {
+ Entry<?> entry = (Entry<?>) currentContainer;
+ String containerqName = entry.getParent().getqName();
+ Set<String> keyNames = populateAliasKeys(containerqName, currentContext, currentWidth);
+ if (!keyNames.isEmpty()) {
+ for (String keyName : keyNames) {
+ String[] tmp = keyName.split(",", 3);
+ String calType = currentCalendarType.lname();
+ String src = calType+"."+tmp[0];
+ String target = getTarget(containerqName,
+ entry.getKey(),
+ calType,
+ tmp[1].length()>0 ? tmp[1] : currentContext,
+ tmp[2].length()>0 ? tmp[2] : currentWidth);
+ if (target.substring(target.lastIndexOf('.')+1).equals(containerqName)) {
+ // may not always be correct
+ target = target.substring(0, target.indexOf('.'))+"."+tmp[0];
+ }
+ CLDRConverter.aliases.put(src.replaceFirst("^gregorian.", ""),
+ target.replaceFirst("^gregorian.", ""));
+ }
+ }
+ } else if (currentContainer instanceof Entry) {
Entry<?> entry = (Entry<?>) currentContainer;
Object value = entry.getValue();
if (value != null) {
put(entry.getKey(), value);
}
}
}
- currentContainer = currentContainer.getParent();
- }
}