1 /* 2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package build.tools.cldrconverter; 27 28 import build.tools.cldrconverter.CLDRConverter.DraftType; 29 import java.util.HashMap; 30 import java.util.Map; 31 import java.util.Set; 32 import org.xml.sax.Attributes; 33 import org.xml.sax.SAXException; 34 import org.xml.sax.SAXParseException; 35 import org.xml.sax.helpers.DefaultHandler; 36 37 /** 38 * This is an abstract class for general LDML parsing purpose. 39 * LDMLParseHandler, SupplementLDMLParseHandler, and NumberingLDMLParseHandler 40 * are the subclasses of this class. 41 */ 42 43 abstract class AbstractLDMLHandler<V> extends DefaultHandler { 44 static final Map<String, String> DAY_OF_WEEK_MAP = new HashMap<>(); 45 static { 46 DAY_OF_WEEK_MAP.put("sun", "1"); 47 DAY_OF_WEEK_MAP.put("mon", "2"); 48 DAY_OF_WEEK_MAP.put("tue", "3"); 49 DAY_OF_WEEK_MAP.put("wed", "4"); 50 DAY_OF_WEEK_MAP.put("thu", "5"); 51 DAY_OF_WEEK_MAP.put("fri", "6"); 52 DAY_OF_WEEK_MAP.put("sat", "7"); 53 } 54 // Collected data in JRE locale data format. 55 private Map<String, V> data = new HashMap<>(); 56 57 // The root Container 58 Container currentContainer = new Container("$ROOT", null); 59 60 AbstractLDMLHandler() { 61 } 62 63 Map<String, V> getData() { 64 return data; 65 } 66 67 V put(String key, V value) { 68 return data.put(key, value); 69 } 70 71 V get(String key) { 72 return data.get(key); 73 } 74 75 Set<String> keySet() { 76 return data.keySet(); 77 } 78 79 /* 80 * It returns true if the data should be ignored based on the user 81 * defined acceptance level, which is listed with draft attribute in 82 * the cldr locale xml files. 83 * When the alt attribute is present, the data is always ignored since 84 * we always use the primary data 85 */ 86 boolean isIgnored(Attributes attributes) { 87 if (attributes.getValue("alt") != null) { 88 return true; 89 } 90 String draftValue = attributes.getValue("draft"); 91 if (draftValue != null) { 92 return DraftType.getDefault().ordinal() > DraftType.forKeyword(draftValue).ordinal(); 93 } 94 return false; 95 } 96 97 void pushContainer(String qName, Attributes attributes) { 98 if (isIgnored(attributes) || currentContainer instanceof IgnoredContainer) { 99 currentContainer = new IgnoredContainer(qName, currentContainer); 100 } else { 101 currentContainer = new Container(qName, currentContainer); 102 } 103 } 104 105 void pushIgnoredContainer(String qName) { 106 currentContainer = new IgnoredContainer(qName, currentContainer); 107 } 108 109 void pushKeyContainer(String qName, Attributes attributes, String key) { 110 if (!pushIfIgnored(qName, attributes)) { 111 currentContainer = new KeyContainer(qName, currentContainer, key); 112 } 113 } 114 115 /** 116 * start an element that defines a string entry, with the value provided by the element's text. 117 */ 118 void pushStringEntry(String qName, Attributes attributes, String key) { 119 if (!pushIfIgnored(qName, attributes)) { 120 currentContainer = new StringEntry(qName, currentContainer, key); 121 } 122 } 123 124 /** 125 * start an element that defines an alias entry, with the value provided by the element's alias. 126 */ 127 void pushAliasEntry(String qName, Attributes attributes, String key) { 128 if (!pushIfIgnored(qName, attributes)) { 129 currentContainer = new AliasEntry(qName, currentContainer, key); 130 } 131 } 132 133 /** 134 * start an element that defines a string entry, with the value provided by an attribute value. 135 */ 136 void pushStringEntry(String qName, Attributes attributes, String key, String value) { 137 if (!pushIfIgnored(qName, attributes)) { 138 currentContainer = new StringEntry(qName, currentContainer, key, value); 139 } 140 } 141 142 void pushStringArrayEntry(String qName, Attributes attributes, String key, int length) { 143 if (!pushIfIgnored(qName, attributes)) { 144 currentContainer = new StringArrayEntry(qName, currentContainer, key, length); 145 } 146 } 147 148 void pushStringArrayElement(String qName, Attributes attributes, int index) { 149 if (!pushIfIgnored(qName, attributes)) { 150 currentContainer = new StringArrayElement(qName, currentContainer, index); 151 } 152 } 153 154 void pushStringListEntry(String qName, Attributes attributes, String key) { 155 if (!pushIfIgnored(qName, attributes)) { 156 currentContainer = new StringListEntry(qName, currentContainer, key); 157 } 158 } 159 160 void pushStringListElement(String qName, Attributes attributes, int index) { 161 if (!pushIfIgnored(qName, attributes)) { 162 currentContainer = new StringListElement(qName, currentContainer, index); 163 } 164 } 165 166 167 private boolean pushIfIgnored(String qName, Attributes attributes) { 168 if (isIgnored(attributes) || currentContainer instanceof IgnoredContainer) { 169 pushIgnoredContainer(qName); 170 return true; 171 } 172 return false; 173 } 174 175 /** 176 * Obtains the key from the innermost containing container that provides one. 177 */ 178 String getContainerKey() { 179 Container current = currentContainer; 180 while (current != null) { 181 if (current instanceof KeyContainer) { 182 return ((KeyContainer) current).getKey(); 183 } 184 current = current.getParent(); 185 } 186 return null; 187 } 188 189 @Override 190 public void characters(char[] ch, int start, int length) throws SAXException { 191 currentContainer.addCharacters(ch, start, length); 192 } 193 194 @SuppressWarnings(value = "CallToThreadDumpStack") 195 @Override 196 public void warning(SAXParseException e) throws SAXException { 197 e.printStackTrace(); 198 } 199 200 @SuppressWarnings(value = "CallToThreadDumpStack") 201 @Override 202 public void error(SAXParseException e) throws SAXException { 203 e.printStackTrace(); 204 } 205 206 @SuppressWarnings(value = "CallToThreadDumpStack") 207 @Override 208 public void fatalError(SAXParseException e) throws SAXException { 209 e.printStackTrace(); 210 super.fatalError(e); 211 } 212 }