1 |
/* gnu.ldml.Analyzer |
/* |
2 |
Copyright (C) 2004 Free Software Foundation, Inc. |
* gnu.ldml.Analyzer Copyright (C) 2004 Free Software Foundation, Inc. |
3 |
|
* |
4 |
This file is part of GNU Classpath. |
* This file is part of GNU Classpath. |
5 |
|
* |
6 |
GNU Classpath is free software; you can redistribute it and/or modify |
* GNU Classpath is free software; you can redistribute it and/or modify it |
7 |
it under the terms of the GNU General Public License as published by |
* under the terms of the GNU General Public License as published by the Free |
8 |
the Free Software Foundation; either version 2, or (at your option) |
* Software Foundation; either version 2, or (at your option) any later version. |
9 |
any later version. |
* |
10 |
|
* GNU Classpath is distributed in the hope that it will be useful, but WITHOUT |
11 |
GNU Classpath is distributed in the hope that it will be useful, but |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 |
WITHOUT ANY WARRANTY; without even the implied warranty of |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* details. |
14 |
General Public License for more details. |
* |
15 |
|
* You should have received a copy of the GNU General Public License along with |
16 |
You should have received a copy of the GNU General Public License |
* GNU Classpath; see the file COPYING. If not, write to the Free Software |
17 |
along with GNU Classpath; see the file COPYING. If not, write to the |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
18 |
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
*/ |
|
02111-1307 USA. */ |
|
|
|
|
19 |
package gnu.ldml; |
package gnu.ldml; |
20 |
|
|
21 |
import java.util.ArrayList; |
import java.util.ArrayList; |
33 |
import org.xml.sax.XMLReader; |
import org.xml.sax.XMLReader; |
34 |
import org.xml.sax.SAXException; |
import org.xml.sax.SAXException; |
35 |
|
|
36 |
public class Analyzer |
public class Analyzer |
37 |
{ |
{ |
|
private Hashtable parserTable = new Hashtable(); |
|
|
private Parser mainParser; |
|
|
private URL mainFile; |
|
|
private Hashtable treeFlattened; |
|
|
private Collection locales; |
|
|
private boolean is_collation; |
|
|
|
|
|
public Collection getLocales() |
|
|
{ |
|
|
return locales; |
|
|
} |
|
|
|
|
|
public boolean isCollation() |
|
|
{ |
|
|
return is_collation; |
|
|
} |
|
|
|
|
|
public Analyzer(URL mainFile) throws IOException, ParseException |
|
|
{ |
|
|
this.mainFile = mainFile; |
|
|
addResourceFile(mainFile); |
|
|
resolveDependencies(); |
|
|
} |
|
38 |
|
|
39 |
private static Hashtable flattenBranch(Element e) |
private static Hashtable flattenBranch(Element e) |
40 |
{ |
{ |
41 |
Hashtable table = new Hashtable(); |
Hashtable table = new Hashtable(); |
42 |
ArrayList stack = new ArrayList(); |
ArrayList stack = new ArrayList(); |
43 |
int stack_sz; |
int stack_sz; |
|
|
|
44 |
stack.add(e); |
stack.add(e); |
45 |
while (stack.size() != 0) |
while (stack.size() != 0) |
46 |
{ |
{ |
47 |
stack_sz = stack.size(); |
stack_sz = stack.size(); |
48 |
for (int i=0;i<stack_sz;i++) |
for (int i = 0; i < stack_sz; i++) |
49 |
{ |
{ |
50 |
Element elt = (Element)stack.get(i); |
Element elt = (Element) stack.get(i); |
51 |
if (elt.children.size() != 0) |
if (elt.children.size() != 0) |
52 |
{ |
{ |
53 |
stack.addAll(elt.children); |
stack.addAll(elt.children); |
54 |
} |
} |
55 |
table.put(elt.getFullName(), elt); |
table.put(elt.getFullName(), elt); |
56 |
} |
} |
57 |
stack.subList(0, stack_sz).clear(); |
stack.subList(0, stack_sz).clear(); |
58 |
} |
} |
59 |
return table; |
return table; |
60 |
} |
} |
61 |
|
private boolean is_collation; |
62 |
public Hashtable flattenTree() |
private Collection locales; |
63 |
|
private URL mainFile; |
64 |
|
private Parser mainParser; |
65 |
|
private Hashtable parserTable = new Hashtable(); |
66 |
|
private Hashtable treeFlattened; |
67 |
|
|
68 |
|
public Analyzer(URL mainFile) throws IOException, ParseException |
69 |
{ |
{ |
70 |
if (treeFlattened != null) |
this.mainFile = mainFile; |
71 |
return treeFlattened; |
addResourceFile(mainFile); |
72 |
|
resolveDependencies(); |
|
treeFlattened = flattenBranch(mainParser.rootElement); |
|
|
return treeFlattened; |
|
73 |
} |
} |
74 |
|
|
75 |
private Parser addResourceFile(URL resourceFile) throws IOException, ParseException |
private Parser addResourceFile(URL resourceFile) throws IOException, |
76 |
|
ParseException |
77 |
{ |
{ |
78 |
Parser parser = new Parser(); |
Parser parser = new Parser(); |
79 |
XMLReader reader; |
XMLReader reader; |
|
|
|
80 |
try |
try |
81 |
{ |
{ |
82 |
SAXParserFactory factory = SAXParserFactory.newInstance(); |
SAXParserFactory factory = SAXParserFactory.newInstance(); |
83 |
factory.setNamespaceAware(true); // because we use localName |
factory.setNamespaceAware(true); // because we use localName |
84 |
SAXParser saxParser = factory.newSAXParser(); |
SAXParser saxParser = factory.newSAXParser(); |
85 |
reader = saxParser.getXMLReader(); |
reader = saxParser.getXMLReader(); |
86 |
} |
} |
87 |
catch (ParserConfigurationException e) |
catch (ParserConfigurationException e) |
88 |
{ |
{ |
89 |
IOException e2 = |
IOException e2 = new IOException("Error creating the SAX parser for " |
90 |
new IOException("Error creating the SAX parser for " + resourceFile); |
+ resourceFile); |
91 |
e2.initCause(e); |
e2.initCause(e); |
92 |
throw e2; |
throw e2; |
93 |
} |
} |
94 |
catch (SAXException e) |
catch (SAXException e) |
95 |
{ |
{ |
96 |
IOException e2 = |
IOException e2 = new IOException("Error creating the XML reader for " |
97 |
new IOException("Error creating the XML reader for " + resourceFile); |
+ resourceFile); |
98 |
e2.initCause(e); |
e2.initCause(e); |
99 |
throw e2; |
throw e2; |
100 |
} |
} |
|
|
|
101 |
if (mainParser == null) |
if (mainParser == null) |
102 |
mainParser = parser; |
mainParser = parser; |
|
|
|
103 |
parser.setURL(resourceFile); |
parser.setURL(resourceFile); |
|
|
|
104 |
String fileName = resourceFile.getFile(); |
String fileName = resourceFile.getFile(); |
105 |
int idx, idx2; |
int idx, idx2; |
|
|
|
106 |
if ((idx = fileName.lastIndexOf(".xml")) < 0) |
if ((idx = fileName.lastIndexOf(".xml")) < 0) |
107 |
throw new Error("file does not end with .xml"); |
throw new Error("file does not end with .xml"); |
|
|
|
108 |
if ((idx2 = fileName.lastIndexOf("/")) < 0) |
if ((idx2 = fileName.lastIndexOf("/")) < 0) |
109 |
idx2 = -1; |
idx2 = -1; |
110 |
|
parser.setName(fileName.substring(idx2 + 1, idx)); |
|
parser.setName(fileName.substring(idx2+1, idx)); |
|
|
|
|
111 |
try |
try |
112 |
{ |
{ |
113 |
parser.parse(reader); |
parser.parse(reader); |
114 |
} |
} |
115 |
catch (SAXException e) |
catch (SAXException e) |
116 |
{ |
{ |
117 |
ParseException e2 = new ParseException("Error reading XML source file " + resourceFile); |
ParseException e2 = new ParseException("Error reading XML source file " |
118 |
|
+ resourceFile); |
119 |
e2.initCause(e); |
e2.initCause(e); |
120 |
throw e2; |
throw e2; |
121 |
} |
} |
|
|
|
122 |
Hashtable table = flattenTree(); |
Hashtable table = flattenTree(); |
123 |
locales = new HashSet(); |
locales = new HashSet(); |
124 |
Element elt = (Element)table.get("ldml.identity.language"); |
Element elt = (Element) table.get("ldml.identity.language"); |
125 |
String mainIdentity; |
String mainIdentity; |
|
|
|
126 |
if (elt == null) |
if (elt == null) |
127 |
throw new ParseException("No identity.language tag in XML. Cannot identify the resource file."); |
throw new ParseException( |
128 |
|
"No identity.language tag in XML. Cannot identify the resource file."); |
129 |
mainIdentity = elt.defaultType.intern(); |
mainIdentity = elt.defaultType.intern(); |
130 |
|
elt = (Element) table.get("ldml.identity.territory"); |
|
elt = (Element)table.get("ldml.identity.territory"); |
|
131 |
if (elt != null) |
if (elt != null) |
132 |
{ |
{ |
133 |
mainIdentity += "_" + elt.defaultType; |
mainIdentity += "_" + elt.defaultType; |
134 |
elt = (Element)table.get("ldml.identity.variant"); |
elt = (Element) table.get("ldml.identity.variant"); |
135 |
if (elt != null) |
if (elt != null) |
136 |
mainIdentity += "_" + elt.defaultType; |
mainIdentity += "_" + elt.defaultType; |
137 |
} |
} |
138 |
|
elt = (Element) table.get("ldml.identity.script"); |
|
elt = (Element)table.get("ldml.identity.script"); |
|
139 |
if (elt != null) |
if (elt != null) |
140 |
mainIdentity += "_" + elt.defaultType; |
mainIdentity += "_" + elt.defaultType; |
|
|
|
141 |
locales.add(mainIdentity); |
locales.add(mainIdentity); |
|
|
|
142 |
// Process ldml/collations@validSublocales |
// Process ldml/collations@validSublocales |
143 |
ListDataElement collations = |
ListDataElement collations = (ListDataElement) table.get("ldml.collations"); |
|
(ListDataElement) table.get("ldml.collations"); |
|
144 |
if (collations != null) |
if (collations != null) |
145 |
{ |
{ |
146 |
String vsl = (String) collations.listData.get("validSubLocales"); |
String vsl = (String) collations.listData.get("validSubLocales"); |
154 |
} |
} |
155 |
is_collation = true; |
is_collation = true; |
156 |
} |
} |
157 |
|
for (Iterator i = locales.iterator(); i.hasNext();) |
|
for (Iterator i = locales.iterator(); i.hasNext(); ) |
|
158 |
{ |
{ |
159 |
String locale = (String) i.next(); |
String locale = (String) i.next(); |
160 |
parserTable.put(locale, parser); |
parserTable.put(locale, parser); |
161 |
} |
} |
|
|
|
162 |
return parser; |
return parser; |
163 |
} |
} |
164 |
|
|
166 |
{ |
{ |
167 |
if (p.getParentElement() == null) |
if (p.getParentElement() == null) |
168 |
return; |
return; |
|
|
|
169 |
ArrayList stack = new ArrayList(); |
ArrayList stack = new ArrayList(); |
|
|
|
170 |
stack.add(p.getParentElement()); |
stack.add(p.getParentElement()); |
171 |
while (stack.size() != 0) |
while (stack.size() != 0) |
172 |
{ |
{ |
173 |
int sz = stack.size(); |
int sz = stack.size(); |
174 |
for (int i=0;i<sz;i++) |
for (int i = 0; i < sz; i++) |
175 |
{ |
{ |
176 |
Element e = (Element)stack.get(i); |
Element e = (Element) stack.get(i); |
177 |
|
if (e instanceof AliasElement) |
178 |
if (e instanceof AliasElement) |
alist.add(e); |
179 |
alist.add(e); |
else |
180 |
else |
stack.addAll(e.children); |
181 |
stack.addAll(e.children); |
} |
182 |
} |
stack.subList(0, sz).clear(); |
|
stack.subList(0, sz).clear(); |
|
183 |
} |
} |
184 |
} |
} |
185 |
|
|
186 |
private Element fetchResource(AliasElement alias) throws IOException, ParseException |
private Element fetchResource(AliasElement alias) throws IOException, |
187 |
|
ParseException |
188 |
{ |
{ |
189 |
Parser p = null; |
Parser p = null; |
190 |
String resName = alias.aliasing; |
String resName = alias.aliasing; |
|
|
|
191 |
/* |
/* |
192 |
* First, we look for the resource file. |
* First, we look for the resource file. The names are of the XXX_YYY |
193 |
* The names are of the XXX_YYY (recursively on XXX). If we fail on |
* (recursively on XXX). If we fail on this file and there is no parse |
194 |
* this file and there is no parse exceptions, then we try XXX. |
* exceptions, then we try XXX. |
195 |
*/ |
*/ |
196 |
while (resName.length() != 0) |
while (resName.length() != 0) |
197 |
{ |
{ |
198 |
|
p = (Parser) parserTable.get(resName); |
199 |
p = (Parser) parserTable.get(resName); |
if (p == null) |
200 |
|
{ |
201 |
if (p == null) |
try |
202 |
{ |
{ |
203 |
try |
p = addResourceFile(new URL(alias.parentParser.getURL(), |
204 |
{ |
resName + ".xml")); |
205 |
p = addResourceFile(new URL(alias.parentParser.getURL(), resName + ".xml")); |
} |
206 |
} |
catch (ParseException e) |
207 |
catch (ParseException e) |
{ |
208 |
{ |
throw e; |
209 |
throw e; |
} |
210 |
} |
catch (IOException e) |
211 |
catch (IOException e) |
{ |
212 |
{ |
continue; |
213 |
continue; |
} |
214 |
} |
break; |
215 |
break; |
} |
216 |
} |
int idx = resName.lastIndexOf('_'); |
217 |
|
if (idx < 0) |
218 |
int idx = resName.lastIndexOf('_'); |
idx = 0; |
219 |
if (idx < 0) |
resName = resName.substring(0, idx); |
|
idx = 0; |
|
|
|
|
|
resName = resName.substring(0, idx); |
|
220 |
} |
} |
|
|
|
221 |
/* |
/* |
222 |
* Now we have parsed the good resource file. We must go in the tree |
* Now we have parsed the good resource file. We must go in the tree and |
223 |
* and find the right element specified by the position and the argument |
* find the right element specified by the position and the argument of |
224 |
* of AliasElement. |
* AliasElement. |
225 |
*/ |
*/ |
|
|
|
226 |
Hashtable table = flattenBranch(p.rootElement); |
Hashtable table = flattenBranch(p.rootElement); |
227 |
String elementName = alias.superElement.getFullName(); |
String elementName = alias.superElement.getFullName(); |
228 |
while (elementName.length() != 0) |
while (elementName.length() != 0) |
229 |
{ |
{ |
230 |
Element e = (Element)table.get(elementName); |
Element e = (Element) table.get(elementName); |
231 |
|
if (e == null) |
232 |
if (e == null) |
{ |
233 |
{ |
int idx = elementName.lastIndexOf('.'); |
234 |
int idx = elementName.lastIndexOf('.'); |
if (idx < 0) |
235 |
|
elementName = ""; |
236 |
if (idx < 0) |
else |
237 |
elementName = ""; |
elementName = elementName.substring(0, idx); |
238 |
else |
continue; |
239 |
elementName = elementName.substring(0, idx); |
} |
240 |
continue; |
/* We have found a candidate. Check if it is a list */ |
241 |
} |
if (!(e instanceof ListDataElement)) |
|
|
|
|
/* We have found a candidate. Check if it is a list */ |
|
|
if (!(e instanceof ListDataElement)) |
|
242 |
{ |
{ |
243 |
System.err.println("Incorrect aliasing element in " + |
System.err.println("Incorrect aliasing element in " |
244 |
alias.parentParser.getName() + |
+ alias.parentParser.getName() |
245 |
" while looking in " + p.getName()); |
+ " while looking in " + p.getName()); |
246 |
return null; |
return null; |
247 |
} |
} |
248 |
|
/* It is a list element, look for the right sub-tree */ |
249 |
/* It is a list element, look for the right sub-tree */ |
ListDataElement lst = (ListDataElement) e; |
250 |
ListDataElement lst = (ListDataElement)e; |
e = (Element) lst.listData.get(resName); |
251 |
e = (Element) lst.listData.get(resName); |
if (e == null) |
252 |
if (e == null) |
throw new ParseException("Unknown aliasing element " + resName |
253 |
throw new ParseException("Unknown aliasing element " + resName + " in " + p.getName()); |
+ " in " + p.getName()); |
254 |
return e; |
return e; |
255 |
} |
} |
|
|
|
256 |
return null; |
return null; |
257 |
} |
} |
258 |
|
|
259 |
|
public Hashtable flattenTree() |
260 |
|
{ |
261 |
|
if (treeFlattened != null) |
262 |
|
return treeFlattened; |
263 |
|
treeFlattened = flattenBranch(mainParser.rootElement); |
264 |
|
return treeFlattened; |
265 |
|
} |
266 |
|
|
267 |
|
public Collection getLocales() |
268 |
|
{ |
269 |
|
return locales; |
270 |
|
} |
271 |
|
|
272 |
|
public boolean isCollation() |
273 |
|
{ |
274 |
|
return is_collation; |
275 |
|
} |
276 |
|
|
277 |
private void resolveDependencies() throws IOException, ParseException |
private void resolveDependencies() throws IOException, ParseException |
278 |
{ |
{ |
279 |
/* |
/* |
280 |
* Here we look for alias elements in the tree. |
* Here we look for alias elements in the tree. We resolve dependencies |
281 |
* We resolve dependencies relatively to the main file. |
* relatively to the main file. |
282 |
*/ |
*/ |
283 |
Iterator i = parserTable.values().iterator(); |
Iterator i = parserTable.values().iterator(); |
284 |
ArrayList aliasList = new ArrayList(); |
ArrayList aliasList = new ArrayList(); |
285 |
HashMap pm = new HashMap(); |
HashMap pm = new HashMap(); |
|
|
|
286 |
while (i.hasNext()) |
while (i.hasNext()) |
287 |
{ |
{ |
288 |
Parser p = (Parser)i.next(); |
Parser p = (Parser) i.next(); |
289 |
|
pm.put(p.getName(), p); |
290 |
pm.put(p.getName(), p); |
buildAliasList(aliasList, p); |
|
buildAliasList(aliasList, p); |
|
291 |
} |
} |
|
|
|
292 |
Iterator aliasIter = aliasList.iterator(); |
Iterator aliasIter = aliasList.iterator(); |
293 |
while (aliasIter.hasNext()) |
while (aliasIter.hasNext()) |
294 |
{ |
{ |
295 |
AliasElement alias = (AliasElement)aliasIter.next(); |
AliasElement alias = (AliasElement) aliasIter.next(); |
296 |
Parser aliasedParser; |
Parser aliasedParser; |
297 |
Element elt; |
Element elt; |
298 |
|
elt = fetchResource(alias); |
|
elt = fetchResource(alias); |
|
|
|
|
|
|
|
299 |
} |
} |
300 |
} |
} |
301 |
} |
} |