• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.IOException;
6 import java.util.Collections;
7 import java.util.HashMap;
8 import java.util.LinkedHashMap;
9 import java.util.LinkedHashSet;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.TreeMap;
13 import java.util.regex.Matcher;
14 
15 import org.xml.sax.InputSource;
16 import org.xml.sax.SAXException;
17 import org.xml.sax.XMLReader;
18 import org.xml.sax.ext.DeclHandler;
19 
20 import com.ibm.icu.impl.Relation;
21 import com.ibm.icu.impl.Row;
22 import com.ibm.icu.impl.Row.R2;
23 import com.ibm.icu.impl.Row.R3;
24 import com.ibm.icu.util.ICUUncheckedIOException;
25 
26 public class ElementAttributeInfo {
27 
28     private DtdType dtdType;
29     private Map<R2<String, String>, R3<Set<String>, String, String>> elementAttribute2Data = new TreeMap<R2<String, String>, R3<Set<String>, String, String>>();
30     private Relation<String, String> element2children = Relation.of(new LinkedHashMap<String, Set<String>>(), LinkedHashSet.class);
31     private Relation<String, String> element2parents = Relation.of(new LinkedHashMap<String, Set<String>>(), LinkedHashSet.class);
32     private Relation<String, String> element2attributes = Relation.of(new LinkedHashMap<String, Set<String>>(), LinkedHashSet.class);
33 
34     static Map<String, Map<DtdType, ElementAttributeInfo>> cache = new HashMap<String, Map<DtdType, ElementAttributeInfo>>(); // new
35     // HashMap<DtdType,
36     // Data>();
37 
getInstance(DtdType dtdType)38     public static final ElementAttributeInfo getInstance(DtdType dtdType) {
39         return getInstance(CLDRPaths.COMMON_DIRECTORY, dtdType);
40     }
41 
getInstance(String commonDirectory, DtdType dtdType)42     public static final ElementAttributeInfo getInstance(String commonDirectory, DtdType dtdType) {
43         Map<DtdType, ElementAttributeInfo> result = cache.get(commonDirectory);
44         if (result == null) {
45             try {
46                 File file = new File(commonDirectory);
47                 String canonicalCommonDirectory;
48                 canonicalCommonDirectory = file.getCanonicalFile().toString();
49                 if (!commonDirectory.equals(canonicalCommonDirectory)) {
50                     result = cache.get(commonDirectory);
51                     if (result != null) {
52                         cache.put(commonDirectory, result);
53                     }
54                 }
55                 if (result == null) {
56                     result = new HashMap<DtdType, ElementAttributeInfo>();
57                     // pick short files that are in repository
58                     result.put(DtdType.ldml, new ElementAttributeInfo(canonicalCommonDirectory + "/main/root.xml",
59                         DtdType.ldml));
60                     result.put(DtdType.supplementalData, new ElementAttributeInfo(canonicalCommonDirectory
61                         + "/supplemental/plurals.xml", DtdType.supplementalData));
62                     result.put(DtdType.ldmlBCP47, new ElementAttributeInfo(canonicalCommonDirectory
63                         + "/bcp47/calendar.xml", DtdType.ldmlBCP47));
64                     result.put(DtdType.keyboard, new ElementAttributeInfo(canonicalCommonDirectory
65                         + "/../keyboards/android/ar-t-k0-android.xml", DtdType.keyboard));
66                     result.put(DtdType.platform, new ElementAttributeInfo(canonicalCommonDirectory
67                         + "/../keyboards/android/_platform.xml", DtdType.keyboard));
68                     cache.put(commonDirectory, result);
69                     cache.put(canonicalCommonDirectory, result);
70                 }
71             } catch (IOException e) {
72                 throw new ICUUncheckedIOException(e);
73             }
74         }
75         return result.get(dtdType);
76     }
77 
78     // static {
79     // try {
80     // addFromDTD(CldrUtility.COMMON_DIRECTORY + "main/en.xml", DtdType.ldml);
81     // addFromDTD(CldrUtility.COMMON_DIRECTORY + "supplemental/characters.xml", DtdType.supplementalData);
82     // addFromDTD(CldrUtility.COMMON_DIRECTORY + "bcp47/calendar.xml", DtdType.ldmlBCP47);
83     // } catch (IOException e) {
84     // throw new IllegalArgumentException(e);
85     // }
86     // }
87 
ElementAttributeInfo(String filename, DtdType type)88     private ElementAttributeInfo(String filename, DtdType type) throws IOException {
89         // StringBufferInputStream fis = new StringBufferInputStream(
90         // "<!DOCTYPE ldml SYSTEM \"http://www.unicode.org/cldr/dtd/1.2/ldml.dtd\"><ldml></ldml>");
91         FileInputStream fis = new FileInputStream(filename);
92         try {
93             XMLReader xmlReader = CLDRFile.createXMLReader(true);
94             this.dtdType = type;
95             MyDeclHandler me = new MyDeclHandler(this);
96             xmlReader.setProperty("http://xml.org/sax/properties/declaration-handler", me);
97             InputSource is = new InputSource(fis);
98             is.setSystemId(filename);
99             // xmlReader.setContentHandler(me);
100             // xmlReader.setErrorHandler(me);
101             xmlReader.parse(is);
102             this.elementAttribute2Data = Collections.unmodifiableMap(getElementAttribute2Data()); // TODO, protect rows
103             getElement2Children().freeze();
104             getElement2Parents().freeze();
105             getElement2Attributes().freeze();
106         } catch (Exception e) {
107             e.printStackTrace();
108         } finally {
109             fis.close();
110         }
111     }
112 
getDtdType()113     private DtdType getDtdType() {
114         return dtdType;
115     }
116 
getElementAttribute2Data()117     public Map<R2<String, String>, R3<Set<String>, String, String>> getElementAttribute2Data() {
118         return elementAttribute2Data;
119     }
120 
getElement2Children()121     public Relation<String, String> getElement2Children() {
122         return element2children;
123     }
124 
getElement2Parents()125     public Relation<String, String> getElement2Parents() {
126         return element2parents;
127     }
128 
getElement2Attributes()129     public Relation<String, String> getElement2Attributes() {
130         return element2attributes;
131     }
132 
133     static class MyDeclHandler implements DeclHandler {
134         private static final boolean SHOW = false;
135         private ElementAttributeInfo myData;
136 
137         Matcher idmatcher = PatternCache.get("[a-zA-Z0-9][-_a-zA-Z0-9]*").matcher("");
138 
MyDeclHandler(ElementAttributeInfo indata)139         public MyDeclHandler(ElementAttributeInfo indata) {
140             myData = indata;
141         }
142 
attributeDecl(String eName, String aName, String type, String mode, String value)143         public void attributeDecl(String eName, String aName, String type, String mode, String value)
144             throws SAXException {
145             if (SHOW)
146                 System.out.println(myData.getDtdType() + "\tAttributeDecl\t" + eName + "\t" + aName + "\t" + type
147                     + "\t" + mode + "\t" + value);
148             R2<String, String> key = Row.of(eName, aName);
149             Set<String> typeSet = getIdentifiers(type);
150             R3<Set<String>, String, String> value2 = Row.of(typeSet, mode, value);
151             R3<Set<String>, String, String> oldValue = myData.getElementAttribute2Data().get(key);
152             if (oldValue != null && !oldValue.equals(value2)) {
153                 throw new IllegalArgumentException("Conflict in data: " + key + "\told: " + oldValue + "\tnew: "
154                     + value2);
155             }
156             myData.getElementAttribute2Data().put(key, value2);
157             myData.getElement2Attributes().put(eName, aName);
158         }
159 
getIdentifiers(String type)160         private Set<String> getIdentifiers(String type) {
161             Set<String> result = new LinkedHashSet<String>();
162             idmatcher.reset(type);
163             while (idmatcher.find()) {
164                 result.add(idmatcher.group());
165             }
166             if (result.size() == 0) {
167                 throw new IllegalArgumentException("No identifiers found in: " + type);
168             }
169             return result;
170         }
171 
elementDecl(String name, String model)172         public void elementDecl(String name, String model) throws SAXException {
173             if (SHOW) System.out.println(myData.getDtdType() + "\tElement\t" + name + "\t" + model);
174             Set<String> identifiers = getIdentifiers(model);
175             // identifiers.remove("special");
176             // identifiers.remove("alias");
177             if (identifiers.size() == 0) {
178                 identifiers.add("EMPTY");
179             }
180             myData.getElement2Children().putAll(name, identifiers);
181             for (String identifier : identifiers) {
182                 myData.getElement2Parents().put(identifier, name);
183             }
184         }
185 
externalEntityDecl(String name, String publicId, String systemId)186         public void externalEntityDecl(String name, String publicId, String systemId) throws SAXException {
187             // TODO Auto-generated method stub
188 
189         }
190 
internalEntityDecl(String name, String value)191         public void internalEntityDecl(String name, String value) throws SAXException {
192             // TODO Auto-generated method stub
193 
194         }
195     }
196 }
197