blob: 4e4225cb57066d4cb05643b3e78a86922a1f7141 [file] [log] [blame]
package org.unicode.cldr.tool;
import java.io.File;
import java.io.PrintWriter;
import java.util.EnumMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import org.unicode.cldr.util.AttributeValueValidity;
import org.unicode.cldr.util.AttributeValueValidity.AttributeValueSpec;
import org.unicode.cldr.util.AttributeValueValidity.LocaleSpecific;
import org.unicode.cldr.util.AttributeValueValidity.Status;
import org.unicode.cldr.util.CLDRConfig;
import org.unicode.cldr.util.CLDRPaths;
import org.unicode.cldr.util.ChainedMap;
import org.unicode.cldr.util.DayPeriodInfo;
import org.unicode.cldr.util.DayPeriodInfo.DayPeriod;
import org.unicode.cldr.util.DayPeriodInfo.Type;
import org.unicode.cldr.util.DtdData;
import org.unicode.cldr.util.DtdData.Attribute;
import org.unicode.cldr.util.DtdData.Element;
import org.unicode.cldr.util.DtdType;
import org.unicode.cldr.util.SupplementalDataInfo;
import org.unicode.cldr.util.SupplementalDataInfo.PluralType;
import org.unicode.cldr.util.XMLFileReader;
import org.unicode.cldr.util.XMLFileReader.SimpleHandler;
import org.unicode.cldr.util.XPathParts;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.ibm.icu.impl.Row.R3;
import com.ibm.icu.util.Output;
public class VerifyAttributeValues extends SimpleHandler {
private static final File BASE_DIR = new File(CLDRPaths.BASE_DIRECTORY);
private static final SupplementalDataInfo supplementalData = CLDRConfig.getInstance().getSupplementalDataInfo();
public static final Joiner SPACE_JOINER = Joiner.on(' ');
public static final Splitter SPACE_SPLITTER = Splitter.on(' ').trimResults().omitEmptyStrings();
public final static class Errors {
@SuppressWarnings({ "unchecked", "rawtypes" })
final ChainedMap.M3<String, AttributeValueSpec, String> file_element_attribute = ChainedMap.of(new TreeMap(), new TreeMap(), String.class);
public void put(String file, DtdType dtdType, String element, String attribute, String attributeValue, String problem) {
file_element_attribute.put(file, new AttributeValueSpec(dtdType, element, attribute, attributeValue), problem);
}
public Iterable<R3<String, AttributeValueSpec, String>> getRows() {
return file_element_attribute.rows();
}
}
private DtdData dtdData; // set from first element read
private final Errors file_element_attribute;
private final String file;
private final EnumMap<LocaleSpecific, Set<String>> localeSpecific = new EnumMap<>(LocaleSpecific.class);
private final Set<AttributeValueSpec> missing;
private VerifyAttributeValues(String fileName, Errors file_element_attribute, Set<AttributeValueSpec> missing) {
this.file_element_attribute = file_element_attribute;
this.file = fileName.startsWith(BASE_DIR.toString()) ? fileName.substring(BASE_DIR.toString().length()) : fileName;
this.missing = missing;
}
/**
* Check the filename—note that the errors and missing are <b>added to<b>, so clear if you want a fresh start!
* @param fileName
* @param errors
* @param missing
*/
public static void check(String fileName, Errors errors, Set<AttributeValueSpec> missing) {
try {
final VerifyAttributeValues platformHandler = new VerifyAttributeValues(fileName, errors, missing);
new XMLFileReader()
.setHandler(platformHandler)
.read(fileName, -1, true);
} catch (Exception e) {
throw new IllegalArgumentException(fileName, e);
}
}
public void handlePathValue(String path, String value) {
XPathParts parts = XPathParts.getFrozenInstance(path);
if (dtdData == null) {
dtdData = DtdData.getInstance(DtdType.valueOf(parts.getElement(0)));
if (dtdData.dtdType == DtdType.ldml) {
String name = file;
String locale = name.substring(name.lastIndexOf('/') + 1, name.lastIndexOf('.'));
localeSpecific.put(LocaleSpecific.pluralCardinal, supplementalData.getPlurals(PluralType.cardinal, locale).getPluralRules().getKeywords());
localeSpecific.put(LocaleSpecific.pluralOrdinal, supplementalData.getPlurals(PluralType.ordinal, locale).getPluralRules().getKeywords());
localeSpecific.put(LocaleSpecific.dayPeriodFormat, getPeriods(Type.format, locale));
localeSpecific.put(LocaleSpecific.dayPeriodSelection, getPeriods(Type.selection, locale));
} else {
localeSpecific.clear();
}
AttributeValueValidity.setLocaleSpecifics(localeSpecific);
}
for (int i = 0; i < parts.size(); ++i) {
if (parts.getAttributeCount(i) == 0) continue;
Map<String, String> attributes = parts.getAttributes(i);
String element = parts.getElement(i);
if (element.equals("attributeValues")) {
continue; // don't look at ourselves in the mirror
}
Element elementInfo = dtdData.getElementFromName().get(element);
for (String attribute : attributes.keySet()) {
Attribute attributeInfo = elementInfo.getAttributeNamed(attribute);
if (!attributeInfo.values.isEmpty()) {
// we don't need to check, since the DTD will enforce values
continue;
}
String attributeValue = attributes.get(attribute);
if (dtdData.isDeprecated(element, attribute, attributeValue)) {
file_element_attribute.put(file, dtdData.dtdType, element, attribute, attributeValue, "deprecated");
continue;
}
Output<String> reason = new Output<>();
Status haveTest = AttributeValueValidity.check(dtdData, element, attribute, attributeValue, reason);
switch (haveTest) {
case ok:
break;
case deprecated:
case illegal:
file_element_attribute.put(file, dtdData.dtdType, element, attribute, attributeValue, reason.value);
break;
case noTest:
missing.add(new AttributeValueSpec(dtdData.dtdType, element, attribute, attributeValue));
break;
}
}
}
}
private Set<String> getPeriods(Type selection, String locale) {
Set<String> result = new TreeSet<>();
final DayPeriodInfo dayPeriods = supplementalData.getDayPeriods(Type.format, locale);
for (DayPeriod period : dayPeriods.getPeriods()) {
result.add(period.toString());
}
;
result.add("am");
result.add("pm");
return new LinkedHashSet<>(result);
}
public static int findAttributeValues(File file, int max, Matcher fileMatcher, Errors errors, Set<AttributeValueSpec> allMissing, PrintWriter out) {
final String name = file.getName();
if (file.isDirectory()
&& !name.equals("specs")
&& !name.equals("tools")
&& !file.toString().contains(".svn")
// && !name.equals("keyboards") // TODO reenable keyboards
) {
int processed = 0;
int count = max;
for (File subfile : file.listFiles()) {
final String subname = subfile.getName();
if (--count < 0
&& !"en.xml".equals(subname)
&& !"root.xml".equals(subname)) {
continue;
}
processed += findAttributeValues(subfile, max, fileMatcher, errors, allMissing, out);
}
if (out != null) {
out.println("Processed files: " + processed + " \tin " + file);
out.flush();
}
return processed;
} else if (name.endsWith(".xml")) {
if (fileMatcher == null || fileMatcher.reset(name.substring(0, name.length() - 4)).matches()) {
check(file.toString(), errors, allMissing);
return 1;
}
}
return 0;
}
}