| /* |
| ******************************************************************************* |
| * Copyright (C) 2004-2012, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| * |
| * Created on Jul 28, 2004 |
| * |
| */ |
| package org.unicode.cldr.util; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.transform.OutputKeys; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.dom.DOMSource; |
| import javax.xml.transform.stream.StreamResult; |
| import javax.xml.xpath.XPath; |
| import javax.xml.xpath.XPathConstants; |
| import javax.xml.xpath.XPathExpression; |
| import javax.xml.xpath.XPathExpressionException; |
| import javax.xml.xpath.XPathFactory; |
| |
| import org.unicode.cldr.icu.LDMLConstants; |
| import org.unicode.cldr.util.XMLFileReader.SimpleHandler; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| |
| /** |
| * @author ram |
| * |
| * TODO To change the template for this generated type comment go to |
| * Window - Preferences - Java - Code Generation - Code and Comments |
| */ |
| public class LDMLUtilities { |
| |
| public static final int XML = 0, |
| TXT = 1; |
| private static final boolean DEBUG = false; |
| |
| /** |
| * Creates a fully resolved locale starting with root and |
| * |
| * @param sourceDir |
| * @param locale |
| * @return |
| */ |
| public static Document getFullyResolvedLDML(String sourceDir, String locale, |
| boolean ignoreRoot, boolean ignoreUnavailable, |
| boolean ignoreIfNoneAvailable, boolean ignoreDraft) { |
| return getFullyResolvedLDML(sourceDir, locale, ignoreRoot, ignoreUnavailable, ignoreIfNoneAvailable, |
| ignoreDraft, null); |
| } |
| |
| private static Document getFullyResolvedLDML(String sourceDir, String locale, |
| boolean ignoreRoot, boolean ignoreUnavailable, |
| boolean ignoreIfNoneAvailable, boolean ignoreDraft, Map<String, String> stack) { |
| Document full = null; |
| if (stack != null) { |
| // For guarding against cicular references |
| String key = "SRC:" + sourceDir + File.separator + locale + ".xml"; |
| if (stack.get(key) != null) { |
| System.err.println("Found circular aliases! " + key); |
| System.exit(-1); |
| } |
| stack.put(key, ""); |
| } |
| // System.err.println("In getFullyResolvedLDML "+sourceDir + " " + locale); |
| try { |
| full = parse(sourceDir + File.separator + "root.xml", ignoreRoot); |
| /* |
| * Debugging |
| * |
| * Node[] list = getNodeArray(full, LDMLConstants.ALIAS); |
| * if(list.length>0){ |
| * System.err.println("Aliases not resolved!. list.getLength() returned "+ list.length); |
| * } |
| */ |
| |
| if (DEBUG) { |
| try { |
| java.io.OutputStreamWriter writer = new java.io.OutputStreamWriter( |
| new java.io.FileOutputStream("./" + File.separator |
| + "root_debug.xml"), "UTF-8"); |
| LDMLUtilities.printDOMTree(full, new PrintWriter(writer), |
| "http://www.unicode.org/cldr/dtd/1.3/ldml.dtd", null); |
| writer.flush(); |
| } catch (IOException e) { |
| // throw the exceptionaway .. this is for debugging |
| } |
| } |
| } catch (RuntimeException ex) { |
| if (!ignoreRoot) { |
| throw ex; |
| } |
| } |
| int index = locale.indexOf(".xml"); |
| if (index > -1) { |
| locale = locale.substring(0, index); |
| } |
| if (locale.equals("root")) { |
| full = resolveAliases(full, sourceDir, locale, ignoreDraft, stack); |
| return full; |
| } |
| String[] constituents = locale.split("_"); |
| String loc = null; |
| boolean isAvailable = false; |
| // String lastLoc = "root"; |
| for (int i = 0; i < constituents.length; i++) { |
| if (loc == null) { |
| loc = constituents[i]; |
| } else { |
| loc = loc + "_" + constituents[i]; |
| } |
| Document doc = null; |
| |
| // Try cache |
| // doc = readMergeCache(sourceDir, lastLoc, loc); |
| // if(doc == null) { .. |
| String fileName = sourceDir + File.separator + loc + ".xml"; |
| File file = new File(fileName); |
| if (file.exists()) { |
| isAvailable = true; |
| doc = parseAndResolveAlias(fileName, loc, ignoreUnavailable); |
| |
| /* |
| * Debugging |
| * |
| * Node[] list = getNodeArray(doc, LDMLConstants.ALIAS); |
| * if(list.length>0){ |
| * System.err.println("Aliases not resolved!. list.getLength() returned "+ list.length); |
| * } |
| */ |
| if (full == null) { |
| full = doc; |
| } else { |
| StringBuffer xpath = new StringBuffer(); |
| mergeLDMLDocuments(full, doc, xpath, loc, sourceDir, ignoreDraft, false); |
| if (DEBUG) { |
| try { |
| java.io.OutputStreamWriter writer = new java.io.OutputStreamWriter( |
| new java.io.FileOutputStream("./" + File.separator + loc |
| + "_debug.xml"), "UTF-8"); |
| LDMLUtilities.printDOMTree(full, new PrintWriter(writer), |
| "http://www.unicode.org/cldr/dtd/1.3/ldml.dtd", null); |
| writer.flush(); |
| } catch (IOException e) { |
| // throw the exceptionaway .. this is for debugging |
| } |
| } |
| } |
| /* |
| * debugging |
| * |
| * Node ec = getNode(full, "//ldml/characters/exemplarCharacters"); |
| * if(ec==null){ |
| * System.err.println("Could not find exemplarCharacters"); |
| * }else{ |
| * System.out.println("The chars are: "+ getNodeValue(ec)); |
| * } |
| */ |
| |
| // writeMergeCache(sourceDir, lastLoc, loc, full); |
| // lastLoc = loc; |
| } else { |
| if (!ignoreUnavailable) { |
| throw new RuntimeException("Could not find: " + fileName); |
| } |
| } |
| // TODO: investigate if we really need to revalidate the DOM tree! |
| // full = revalidate(full, locale); |
| } |
| |
| if (ignoreIfNoneAvailable == true && isAvailable == false) { |
| return null; |
| } |
| |
| if (DEBUG) { |
| try { |
| java.io.OutputStreamWriter writer = new java.io.OutputStreamWriter( |
| new java.io.FileOutputStream("./" + File.separator + locale |
| + "_ba_debug.xml"), "UTF-8"); |
| LDMLUtilities.printDOMTree(full, new PrintWriter(writer), |
| "http://www.unicode.org/cldr/dtd/1.3/ldml.dtd", null); |
| writer.flush(); |
| } catch (IOException e) { |
| // throw the exceptionaway .. this is for debugging |
| } |
| } |
| // get the real locale name |
| locale = getLocaleName(full); |
| // Resolve the aliases once the data is built |
| full = resolveAliases(full, sourceDir, locale, ignoreDraft, stack); |
| |
| if (DEBUG) { |
| try { |
| java.io.OutputStreamWriter writer = new java.io.OutputStreamWriter( |
| new java.io.FileOutputStream("./" + File.separator + locale |
| + "_aa_debug.xml"), "UTF-8"); |
| LDMLUtilities.printDOMTree(full, new PrintWriter(writer), |
| "http://www.unicode.org/cldr/dtd/1.3/ldml.dtd", null); |
| writer.flush(); |
| } catch (IOException e) { |
| // throw the exceptionaway .. this is for debugging |
| } |
| } |
| return full; |
| } |
| |
| public static String getLocaleName(Document doc) { |
| |
| Node ln = LDMLUtilities.getNode(doc, "//ldml/identity/language"); |
| Node tn = LDMLUtilities.getNode(doc, "//ldml/identity/territory"); |
| Node sn = LDMLUtilities.getNode(doc, "//ldml/identity/script"); |
| Node vn = LDMLUtilities.getNode(doc, "//ldml/identity/variant"); |
| |
| StringBuffer locName = new StringBuffer(); |
| String lang = LDMLUtilities.getAttributeValue(ln, LDMLConstants.TYPE); |
| if (lang != null) { |
| locName.append(lang); |
| } else { |
| throw new IllegalArgumentException("Did not get any value for language node from identity."); |
| } |
| if (sn != null) { |
| String script = LDMLUtilities.getAttributeValue(sn, LDMLConstants.TYPE); |
| if (script != null) { |
| locName.append("_"); |
| locName.append(script); |
| } |
| } |
| if (tn != null) { |
| String terr = LDMLUtilities.getAttributeValue(tn, LDMLConstants.TYPE); |
| if (terr != null) { |
| locName.append("_"); |
| locName.append(terr); |
| } |
| } |
| if (vn != null) { |
| String variant = LDMLUtilities.getAttributeValue(vn, LDMLConstants.TYPE); |
| if (variant != null && tn != null) { |
| locName.append("_"); |
| locName.append(variant); |
| } |
| } |
| return locName.toString(); |
| } |
| |
| // revalidate wasn't called anywhere. |
| // TODO: if needed, reimplement using DOM level 3 |
| /* |
| * public static Document revalidate(Document doc, String fileName){ |
| * // what a waste!! |
| * // to revalidate an in-memory DOM tree we need to first |
| * // serialize it to byte array and read it back again. |
| * // in DOM level 3 implementation there is API to validate |
| * // in-memory DOM trees but the latest implementation of Xerces |
| * // can only validate against schemas not DTDs!!! |
| * try{ |
| * // revalidate the document |
| * Serializer serializer = SerializerFactory.getSerializer(OutputProperties.getDefaultMethodProperties("xml")); |
| * ByteArrayOutputStream os = new ByteArrayOutputStream(); |
| * serializer.setOutputStream(os); |
| * DOMSerializer ds = serializer.asDOMSerializer(); |
| * //ds.serialize(doc); |
| * os.flush(); |
| * ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); |
| * doc = parse(new InputSource(is),"Fully resolved: "+fileName, false); |
| * return doc; |
| * }catch(IOException ex){ |
| * throw new RuntimeException(ex); |
| * } |
| * } |
| */ |
| @Deprecated |
| public static String convertXPath2ICU(Node alias, Node namespaceNode, StringBuffer fullPath) |
| throws TransformerException { |
| StringBuilder sb = new StringBuilder(fullPath.toString()); |
| return convertXPath2ICU(alias, namespaceNode, sb); |
| } |
| |
| public static String convertXPath2ICU(Node alias, Node namespaceNode, StringBuilder fullPath) |
| throws TransformerException { |
| Node context = alias.getParentNode(); |
| StringBuffer icu = new StringBuffer(); |
| String source = getAttributeValue(alias, LDMLConstants.SOURCE); |
| String xpath = getAttributeValue(alias, LDMLConstants.PATH); |
| |
| // make sure that the xpaths are valid |
| if (namespaceNode == null) { |
| XPathAPI_eval(context, fullPath.toString()); |
| if (xpath != null) { |
| XPathAPI_eval(context, xpath); |
| } |
| } else { |
| XPathAPI_eval(context, fullPath.toString(), namespaceNode); |
| if (xpath != null) { |
| XPathAPI_eval(context, xpath, namespaceNode); |
| } |
| } |
| if (source.equals(LDMLConstants.LOCALE)) { |
| icu.append("/"); |
| icu.append(source.toUpperCase()); |
| } else { |
| icu.append(source); |
| } |
| if (xpath != null) { |
| StringBuilder resolved = XPathTokenizer.relativeToAbsolute(xpath, fullPath); |
| // make sure that fullPath is not corrupted! |
| XPathAPI_eval(context, fullPath.toString()); |
| |
| // TODO .. do the conversion |
| XPathTokenizer tokenizer = new XPathTokenizer(resolved.toString()); |
| |
| String token = tokenizer.nextToken(); |
| while (token != null) { |
| if (!token.equals("ldml")) { |
| String equiv = getICUEquivalent(token); |
| if (equiv == null) { |
| throw new IllegalArgumentException("Could not find ICU equivalent for token: " + token); |
| } |
| if (equiv.length() > 0) { |
| icu.append("/"); |
| icu.append(equiv); |
| } |
| } |
| token = tokenizer.nextToken(); |
| } |
| } |
| return icu.toString(); |
| } |
| |
| public static String convertXPath2ICU(String source, String xpath, String basePath, String fullPath) |
| throws TransformerException { |
| // Node context = alias.getParentNode(); |
| StringBuffer icu = new StringBuffer(); |
| |
| // TODO: make sure that the xpaths are valid. How? |
| |
| if (source.equals(LDMLConstants.LOCALE)) { |
| icu.append("/"); |
| icu.append(source.toUpperCase()); |
| } else { |
| icu.append(source); |
| } |
| |
| if (xpath != null) { |
| StringBuilder fullPathBuffer = new StringBuilder(fullPath); |
| StringBuilder resolved = XPathTokenizer.relativeToAbsolute(xpath, fullPathBuffer); |
| // TODO: make sure that fullPath is not corrupted! How? |
| // XPathAPI.eval(context, fullPath.toString()); |
| |
| // TODO .. do the conversion |
| XPathTokenizer tokenizer = new XPathTokenizer(resolved); |
| |
| String token = tokenizer.nextToken(); |
| while (token != null) { |
| if (!token.equals("ldml")) { |
| String equiv = getICUEquivalent(token); |
| if (equiv == null) { |
| throw new IllegalArgumentException("Could not find ICU equivalent for token: " + token); |
| } |
| if (equiv.length() > 0) { |
| icu.append("/"); |
| icu.append(equiv); |
| } |
| } |
| token = tokenizer.nextToken(); |
| } |
| } |
| return icu.toString(); |
| } |
| |
| public static String getDayIndexAsString(String type) { |
| if (type.equals("sun")) { |
| return "0"; |
| } else if (type.equals("mon")) { |
| return "1"; |
| } else if (type.equals("tue")) { |
| return "2"; |
| } else if (type.equals("wed")) { |
| return "3"; |
| } else if (type.equals("thu")) { |
| return "4"; |
| } else if (type.equals("fri")) { |
| return "5"; |
| } else if (type.equals("sat")) { |
| return "6"; |
| } else { |
| throw new IllegalArgumentException("Unknown type: " + type); |
| } |
| } |
| |
| public static String getMonthIndexAsString(String type) { |
| return Integer.toString(Integer.parseInt(type) - 1); |
| } |
| |
| private static String getICUEquivalent(String token) { |
| int index = 0; |
| if (token.indexOf(LDMLConstants.LDN) > -1) { |
| return ""; |
| } else if (token.indexOf(LDMLConstants.LANGUAGES) > -1) { |
| return "Languages"; |
| } else if (token.indexOf(LDMLConstants.LANGUAGE) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.TERRITORIES) > -1) { |
| return "Countries"; |
| } else if (token.indexOf(LDMLConstants.TERRITORY) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.SCRIPTS) > -1) { |
| return "Scripts"; |
| } else if (token.indexOf(LDMLConstants.SCRIPT) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.VARIANTS) > -1) { |
| return "Variants"; |
| } else if (token.indexOf(LDMLConstants.VARIANT) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.KEYS) > -1) { |
| return "Keys"; |
| } else if (token.indexOf(LDMLConstants.KEY) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.TYPES) > -1) { |
| return "Types"; |
| } else if ((index = token.indexOf(LDMLConstants.TYPE)) > -1 && token.charAt(index - 1) != '@') { |
| String type = getAttributeValue(token, LDMLConstants.TYPE); |
| String key = getAttributeValue(token, LDMLConstants.KEY); |
| return type + "/" + key; |
| } else if (token.indexOf(LDMLConstants.LAYOUT) > -1) { |
| return "Layout"; |
| } else if (token.indexOf(LDMLConstants.ORIENTATION) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.CONTEXT_TRANSFORMS) > -1) { |
| return "contextTransforms"; |
| } else if (token.indexOf(LDMLConstants.CONTEXT_TRANSFORM_USAGE) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.CHARACTERS) > -1) { |
| return ""; |
| } else if (token.indexOf(LDMLConstants.EXEMPLAR_CHARACTERS) > -1) { |
| return "ExemplarCharacters"; |
| } else if (token.indexOf(LDMLConstants.MEASUREMENT) > -1) { |
| return ""; |
| } else if (token.indexOf(LDMLConstants.MS) > -1) { |
| return "MeasurementSystem"; |
| } else if (token.indexOf(LDMLConstants.PAPER_SIZE) > -1) { |
| return "PaperSize"; |
| } else if (token.indexOf(LDMLConstants.HEIGHT) > -1) { |
| return "0"; |
| } else if (token.indexOf(LDMLConstants.WIDTH) > -1) { |
| return "1"; |
| } else if (token.indexOf(LDMLConstants.DATES) > -1) { |
| return ""; |
| } else if (token.indexOf(LDMLConstants.LPC) > -1) { |
| return "localPatternCharacters"; |
| } else if (token.indexOf(LDMLConstants.CALENDARS) > -1) { |
| return "calendar"; |
| } else if (token.indexOf(LDMLConstants.DEFAULT) > -1) { |
| return "default"; |
| } else if (token.indexOf(LDMLConstants.CALENDAR) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.ERAS) > -1) { |
| return "eras"; |
| } else if (token.indexOf(LDMLConstants.ERAABBR) > -1) { |
| return "abbreviated"; |
| } else if (token.indexOf(LDMLConstants.ERA) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.NUMBERS) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.SYMBOLS) > -1) { |
| return "NumberElements"; |
| } else if (token.indexOf(LDMLConstants.DATE_FORMATS) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.DFL) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.DATE_FORMAT) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.TIME_FORMATS) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.TFL) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.TIME_FORMAT) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.DATE_TIME_FORMATS) > -1) { |
| // TODO fix this |
| return "DateTimePatterns"; |
| } else if (token.indexOf(LDMLConstants.INTVL_FMTS) > -1) { |
| return "intervalFormats"; |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.DTFL) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.DATE_TIME_FORMAT) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.INTVL_FMTS) > -1) { |
| // TODO fix this |
| } else if (token.indexOf(LDMLConstants.CYCLIC_NAME_SETS) > -1) { |
| return "cyclicNameSets"; |
| } else if (token.indexOf(LDMLConstants.CYCLIC_NAME_SET) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.CYCLIC_NAME_CONTEXT) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.CYCLIC_NAME_WIDTH) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.CYCLIC_NAME) > -1) { |
| String valStr = getAttributeValue(token, LDMLConstants.TYPE); |
| return getMonthIndexAsString(valStr); |
| } else if (token.indexOf(LDMLConstants.MONTHS) > -1) { |
| return "monthNames"; |
| } else if (token.indexOf(LDMLConstants.MONTH_PATTERNS) > -1) { |
| return "monthPatterns"; |
| } else if (token.indexOf(LDMLConstants.MONTH_PATTERN_CONTEXT) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.MONTH_PATTERN_WIDTH) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.MONTH_PATTERN) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.MONTH_CONTEXT) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.MONTH_WIDTH) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.MONTH) > -1) { |
| String valStr = getAttributeValue(token, LDMLConstants.TYPE); |
| return getMonthIndexAsString(valStr); |
| } else if (token.indexOf(LDMLConstants.DAYPERIODS) > -1) { |
| return "dayPeriods"; |
| } else if (token.indexOf(LDMLConstants.DAYS) > -1) { |
| return "dayNames"; |
| } else if (token.indexOf(LDMLConstants.DAY_CONTEXT) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.DAY_WIDTH) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.DAY) > -1) { |
| String dayName = getAttributeValue(token, LDMLConstants.TYPE); |
| return getDayIndexAsString(dayName); |
| } else if (token.indexOf(LDMLConstants.QUARTER_WIDTH) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.QUARTER_CONTEXT) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } else if (token.indexOf(LDMLConstants.QUARTERS) > -1) { |
| return "quarters"; |
| } else if (token.indexOf(LDMLConstants.QUARTER) > -1) { |
| String valStr = getAttributeValue(token, LDMLConstants.TYPE); |
| return getMonthIndexAsString(valStr); |
| } else if (token.indexOf(LDMLConstants.COLLATIONS) > -1) { |
| return "collations"; |
| } else if (token.indexOf(LDMLConstants.COLLATION) > -1) { |
| return getAttributeValue(token, LDMLConstants.TYPE); |
| } |
| |
| // TODO: this method is not finished yet |
| // the conversion of Xpath to ICU alias path |
| // is not as straight forward as I thought |
| // need to cater to idiosynchracies of each |
| // element node :( |
| throw new IllegalArgumentException("Unknown Xpath fragment: " + token); |
| } |
| |
| /** |
| * |
| * @param token |
| * XPath token fragment |
| * @param attrib |
| * attribute whose value must be fetched |
| * @return |
| */ |
| private static String getAttributeValue(String token, String attrib) { |
| int attribStart = token.indexOf(attrib); |
| int valStart = token.indexOf('=', attribStart) + 1/* skip past the separtor */; |
| int valEnd = token.indexOf('@', valStart); |
| if (valEnd < 0) { |
| valEnd = valStart + (token.length() - valStart - 1); |
| } else { |
| valEnd = token.length() - 1 /* valEnd should be index */; |
| } |
| String value = token.substring(valStart, valEnd); |
| int s = value.indexOf('\''); |
| if (s > -1) { |
| s++; |
| int e = value.lastIndexOf('\''); |
| return value.substring(s, e); |
| } else { |
| // also handle "" |
| s = value.indexOf('"'); |
| if (s > -1) { |
| s++; |
| int e = value.lastIndexOf('"'); |
| return value.substring(s, e); |
| } |
| } |
| return value; |
| } |
| |
| @Deprecated |
| public static Node mergeLDMLDocuments(Document source, Node override, StringBuffer xpath, |
| String thisName, String sourceDir, boolean ignoreDraft, |
| boolean ignoreVersion) { |
| StringBuilder sb = new StringBuilder(xpath.toString()); |
| return mergeLDMLDocuments(source, override, sb, thisName, sourceDir, ignoreDraft, ignoreVersion); |
| } |
| |
| /** |
| * Resolved Data File |
| * <p> |
| * To produce fully resolved locale data file from CLDR for a locale ID L, you start with root, and replace/add |
| * items from the child locales until you get down to L. More formally, this can be expressed as the following |
| * procedure. |
| * </p> |
| * <ol> |
| * <li>Let Result be an empty LDML file.</li> |
| * |
| * <li>For each Li in the locale chain for L |
| * <ol> |
| * <li>For each element pair P in the LDML file for Li: |
| * <ol> |
| * <li>If Result has an element pair Q with an equivalent element chain, remove Q.</li> |
| * <li>Add P to Result.</li> |
| * </ol> |
| * </li> |
| * </ol> |
| * |
| * </li> |
| * </ol> |
| * <p> |
| * Note: when adding an element pair to a result, it has to go in the right order for it to be valid according to |
| * the DTD. |
| * </p> |
| * |
| * @param source |
| * @param override |
| * @return the merged document |
| */ |
| public static Node mergeLDMLDocuments(Document source, Node override, StringBuilder xpath, |
| String thisName, String sourceDir, boolean ignoreDraft, |
| boolean ignoreVersion) { |
| if (source == null) { |
| return override; |
| } |
| if (xpath.length() == 0) { |
| xpath.append("/"); |
| } |
| |
| // boolean gotcha = false; |
| // String oldx = new String(xpath); |
| // if(override.getNodeName().equals("week")) { |
| // gotcha = true; |
| // System.out.println("SRC: " + getNode(source, xpath.toString()).toString()); |
| // System.out.println("OVR: " + override.toString()); |
| // } |
| |
| // we know that every child xml file either adds or |
| // overrides the elements in parent |
| // so we traverse the child, at every node check if |
| // if the node is present in the source, |
| // if (present) |
| // recurse to replace any nodes that need to be overridded |
| // else |
| // import the node into source |
| Node child = override.getFirstChild(); |
| while (child != null) { |
| // we are only concerned with element nodes |
| if (child.getNodeType() != Node.ELEMENT_NODE) { |
| child = child.getNextSibling(); |
| continue; |
| } |
| String childName = child.getNodeName(); |
| |
| int savedLength = xpath.length(); |
| xpath.append("/"); |
| xpath.append(childName); |
| appendXPathAttribute(child, xpath, false, false); |
| Node nodeInSource = null; |
| |
| if (childName.indexOf(":") > -1) { |
| nodeInSource = getNode(source, xpath.toString(), child); |
| } else { |
| nodeInSource = getNode(source, xpath.toString()); |
| } |
| |
| Node parentNodeInSource = null; |
| if (nodeInSource == null) { |
| // the child xml has a new node |
| // that should be added to parent |
| String parentXpath = xpath.substring(0, savedLength); |
| |
| if (childName.indexOf(":") > -1) { |
| parentNodeInSource = getNode(source, parentXpath, child); |
| } else { |
| parentNodeInSource = getNode(source, parentXpath); |
| } |
| if (parentNodeInSource == null) { |
| throw new RuntimeException("Internal Error"); |
| } |
| |
| Node childToImport = source.importNode(child, true); |
| parentNodeInSource.appendChild(childToImport); |
| } else if (childName.equals(LDMLConstants.IDENTITY)) { |
| if (!ignoreVersion) { |
| // replace the source doc |
| // none of the elements under collations are inherited |
| // only the node as a whole!! |
| parentNodeInSource = nodeInSource.getParentNode(); |
| Node childToImport = source.importNode(child, true); |
| parentNodeInSource.replaceChild(childToImport, nodeInSource); |
| } |
| } else if (childName.equals(LDMLConstants.COLLATION)) { |
| // replace the source doc |
| // none of the elements under collations are inherited |
| // only the node as a whole!! |
| parentNodeInSource = nodeInSource.getParentNode(); |
| Node childToImport = source.importNode(child, true); |
| parentNodeInSource.replaceChild(childToImport, nodeInSource); |
| // override the validSubLocales attribute |
| String val = LDMLUtilities.getAttributeValue(child.getParentNode(), LDMLConstants.VALID_SUBLOCALE); |
| NamedNodeMap map = parentNodeInSource.getAttributes(); |
| Node vs = map.getNamedItem(LDMLConstants.VALID_SUBLOCALE); |
| vs.setNodeValue(val); |
| } else { |
| boolean childElementNodes = areChildrenElementNodes(child); |
| boolean sourceElementNodes = areChildrenElementNodes(nodeInSource); |
| // System.out.println(childName + ":" + childElementNodes + "/" + sourceElementNodes); |
| if (childElementNodes && sourceElementNodes) { |
| // recurse to pickup any children! |
| mergeLDMLDocuments(source, child, xpath, thisName, sourceDir, ignoreDraft, ignoreVersion); |
| } else { |
| // we have reached a leaf node now get the |
| // replace to the source doc |
| parentNodeInSource = nodeInSource.getParentNode(); |
| Node childToImport = source.importNode(child, true); |
| parentNodeInSource.replaceChild(childToImport, nodeInSource); |
| } |
| } |
| xpath.delete(savedLength, xpath.length()); |
| child = child.getNextSibling(); |
| } |
| // if(gotcha==true) { |
| // System.out.println("Final: " + getNode(source, oldx).toString()); |
| // } |
| return source; |
| } |
| |
| private static Node[] getNodeArray(Document doc, String tagName) { |
| NodeList list = doc.getElementsByTagName(tagName); |
| // node list is dynamic .. if a node is deleted, then |
| // list is immidiately updated. |
| // so first cache the nodes returned and do stuff |
| Node[] array = new Node[list.getLength()]; |
| for (int i = 0; i < list.getLength(); i++) { |
| array[i] = list.item(i); |
| } |
| return array; |
| } |
| |
| /** |
| * Utility to create abosolute Xpath from 1.1 style alias element |
| * |
| * @param node |
| * @param type |
| * @return |
| */ |
| public static String getAbsoluteXPath(Node node, String type) { |
| StringBuffer xpath = new StringBuffer(); |
| StringBuffer xpathFragment = new StringBuffer(); |
| node = node.getParentNode(); // the node is alias node .. get its parent |
| if (node == null) { |
| throw new IllegalArgumentException("Alias node's parent is null!"); |
| } |
| xpath.append(node.getNodeName()); |
| if (type != null) { |
| xpath.append("[@type='" + type + "']"); // TODO: double quotes? |
| } |
| Node parent = node; |
| while ((parent = parent.getParentNode()) != null) { |
| xpathFragment.setLength(0); |
| xpathFragment.append(parent.getNodeName()); |
| if (parent.getNodeType() != Node.DOCUMENT_NODE) { |
| appendXPathAttribute(parent, xpathFragment); |
| xpath.insert(0, "/"); |
| xpath.insert(0, xpathFragment); |
| } |
| } |
| xpath.insert(0, "//"); |
| return xpath.toString(); |
| } |
| |
| /** |
| * |
| * @param n1 |
| * @param n2 |
| * preferred list |
| * @param xpath |
| * @return |
| */ |
| private static Node[] mergeNodeLists(Object[] n1, Object[] n2) { |
| StringBuffer xp1 = new StringBuffer(); |
| StringBuffer xp2 = new StringBuffer(); |
| int l1 = xp1.length(), l2 = xp2.length(); |
| Map<String, Object> map = new HashMap<String, Object>(); |
| if (n2 == null || n2.length == 0) { |
| Node[] na = new Node[n1.length]; |
| for (int i = 0; i < n1.length; i++) { |
| na[i] = (Node) n1[i]; |
| } |
| return na; |
| } |
| for (int i = 0; i < n1.length; i++) { |
| xp1.append(((Node) n1[i]).getNodeName()); |
| appendXPathAttribute((Node) n1[i], xp1); |
| map.put(xp1.toString(), n1[i]); |
| xp1.setLength(l1); |
| } |
| for (int i = 0; i < n2.length; i++) { |
| xp2.append(((Node) n2[i]).getNodeName()); |
| appendXPathAttribute((Node) n2[i], xp2); |
| map.put(xp2.toString(), n2[i]); |
| xp2.setLength(l2); |
| } |
| Object[] arr = map.values().toArray(); |
| Node[] na = new Node[arr.length]; |
| for (int i = 0; i < arr.length; i++) { |
| na[i] = (Node) arr[i]; |
| } |
| return na; |
| } |
| |
| /** |
| * |
| * @param fullyResolvedDoc |
| * @param sourceDir |
| * @param thisLocale |
| */ |
| // TODO guard against circular aliases |
| public static Document resolveAliases(Document fullyResolvedDoc, String sourceDir, String thisLocale, |
| boolean ignoreDraft, Map<String, String> stack) { |
| Node[] array = getNodeArray(fullyResolvedDoc, LDMLConstants.ALIAS); |
| |
| // resolve all the aliases by iterating over |
| // the list of nodes |
| Node[] replacementList = null; |
| Node parent = null; |
| String source = null; |
| String path = null; |
| String type = null; |
| for (int i = 0; i < array.length; i++) { |
| Node node = array[i]; |
| /* |
| * //stop inherited aliases from overwriting valid locale data |
| * //ldml.dtd does not allow alias to have any sibling elements |
| * boolean bFoundSibling = false; |
| * Node n = node.getNextSibling(); |
| * while (n != null) |
| * { |
| * if (n.getNodeType() == Node.ELEMENT_NODE) |
| * { |
| * // System.err.println ("it's an element node " + n.getNodeName () + " " + n.getNodeValue()); |
| * bFoundSibling = true; |
| * break; |
| * } |
| * n = n.getNextSibling(); |
| * } |
| * if (bFoundSibling == true) |
| * continue; |
| */ |
| // initialize the stack for every alias! |
| stack = new HashMap<String, String>(); |
| if (node == null) { |
| System.err.println("list.item(" + i + ") returned null!. The list reports it's length as: " |
| + array.length); |
| continue; |
| } |
| parent = node.getParentNode(); |
| // boolean isDraft = isNodeDraft(node); |
| source = getAttributeValue(node, LDMLConstants.SOURCE); |
| path = getAttributeValue(node, LDMLConstants.PATH); |
| type = getAttributeValue(parent, LDMLConstants.TYPE); |
| if (parent.getParentNode() == null) { |
| // some of the nodes were orphaned by the previous alias resolution .. just continue |
| continue; |
| } |
| if (source != null && path == null) { |
| // this LDML 1.1 style alias parse it |
| path = getAbsoluteXPath(node, type); |
| } |
| String key = "SRC:" + thisLocale + ";XPATH:" + getAbsoluteXPath(node, type); |
| if (stack.get(key) != null) { |
| throw new IllegalStateException("Found circular aliases! " + key); |
| |
| } |
| stack.put(key, ""); |
| if (source.equals(LDMLConstants.LOCALE)) { |
| |
| Object[] aliasList = getChildNodeListAsArray(getNode(parent, path), false); |
| Object[] childList = getChildNodeListAsArray(parent, true); |
| replacementList = mergeNodeLists(aliasList, childList); |
| } else if (source != null && !source.equals(thisLocale)) { |
| // if source is defined then path should not be |
| // relative |
| if (path.indexOf("..") > 0) { |
| throw new IllegalArgumentException("Cannot parse relative xpath: " + path + |
| " in locale: " + source + |
| " from source locale: " + thisLocale); |
| } |
| // this is a is an absolute XPath |
| Document newDoc = getFullyResolvedLDML(sourceDir, source, false, true, false, ignoreDraft, stack); |
| replacementList = getNodeListAsArray(newDoc, path); |
| } else { |
| // path attribute is referencing another node in this DOM tree |
| replacementList = getNodeListAsArray(parent, path); |
| } |
| if (replacementList != null) { |
| parent.removeChild(node); |
| int listLen = replacementList.length; |
| if (listLen > 1) { |
| // check if the whole locale is aliased |
| // if yes then remove the identity from |
| // the current document! |
| if (path != null && path.equals("//ldml/*")) { |
| Node[] identity = getNodeArray(fullyResolvedDoc, LDMLConstants.IDENTICAL); |
| for (int j = 0; j < identity.length; j++) { |
| parent.removeChild(node); |
| } |
| } else { |
| // remove all the children of the parent node |
| removeChildNodes(parent); |
| } |
| for (int j = 0; j < listLen; j++) { |
| // found an element node in the aliased resource |
| // add to the source |
| Node child = replacementList[j]; |
| Node childToImport = fullyResolvedDoc.importNode(child, true); |
| // if(isDraft==true && childToImport.getNodeType() == Node.ELEMENT_NODE){ |
| // ((Element)childToImport).setAttribute("draft", "true"); |
| // } |
| parent.appendChild(childToImport); |
| } |
| } else { |
| Node replacement = replacementList[0]; |
| // remove all the children of the parent node |
| removeChildNodes(parent); |
| for (Node child = replacement.getFirstChild(); child != null; child = child.getNextSibling()) { |
| // found an element node in the aliased resource |
| // add to the source |
| Node childToImport = fullyResolvedDoc.importNode(child, true); |
| // if(isDraft==true && childToImport.getNodeType() == Node.ELEMENT_NODE){ |
| // ((Element)childToImport).setAttribute("draft", "true"); |
| // } |
| parent.appendChild(childToImport); |
| } |
| } |
| |
| } else { |
| throw new IllegalArgumentException("Could not find node for xpath: " + path + |
| " in locale: " + source + |
| " from source locale: " + thisLocale); |
| |
| } |
| } |
| return fullyResolvedDoc; |
| } |
| |
| private static void removeChildNodes(Node parent) { |
| Node[] children = toNodeArray(parent.getChildNodes()); |
| for (int j = 0; j < children.length; j++) { |
| parent.removeChild(children[j]); |
| } |
| } |
| |
| // TODO add funtions for fetching legitimate children |
| // for ICU |
| public boolean isParentDraft(Document fullyResolved, String xpath) { |
| Node node = getNode(fullyResolved, xpath); |
| Node parentNode; |
| while ((parentNode = node.getParentNode()) != null) { |
| String draft = getAttributeValue(parentNode, LDMLConstants.DRAFT); |
| if (draft != null) { |
| if (draft.equals("true") || draft.equals("provisional") || draft.equals("unconfirmed")) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| } |
| // the default value is false if none specified |
| return false; |
| } |
| |
| public static boolean isNodeDraft(Node node) { |
| String draft = getAttributeValue(node, LDMLConstants.DRAFT); |
| if (draft != null) { |
| if (draft.equals("true") || draft.equals("provisional") || draft.equals("unconfirmed")) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| return false; |
| } |
| |
| public static boolean isDraft(Node fullyResolved, StringBuffer xpath) { |
| Node current = getNode(fullyResolved, xpath.toString()); |
| String draft = null; |
| while (current != null && current.getNodeType() == Node.ELEMENT_NODE) { |
| draft = getAttributeValue(current, LDMLConstants.DRAFT); |
| if (draft != null) { |
| if (draft.equals("true") || draft.equals("provisional") || draft.equals("unconfirmed")) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| current = current.getParentNode(); |
| } |
| return false; |
| } |
| |
| public static boolean isSiblingDraft(Node root) { |
| Node current = root; |
| String draft = null; |
| while (current != null && current.getNodeType() == Node.ELEMENT_NODE) { |
| draft = getAttributeValue(current, LDMLConstants.DRAFT); |
| if (draft != null) { |
| if (draft.equals("true") || draft.equals("provisional") || draft.equals("unconfirmed")) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| current = current.getNextSibling(); |
| } |
| return false; |
| } |
| |
| public static void appendAllAttributes(Node node, StringBuffer xpath) { |
| NamedNodeMap attr = node.getAttributes(); |
| int len = attr.getLength(); |
| if (len > 0) { |
| for (int i = 0; i < len; i++) { |
| Node item = attr.item(i); |
| xpath.append("[@"); |
| xpath.append(item.getNodeName()); |
| xpath.append("='"); |
| xpath.append(item.getNodeValue()); |
| xpath.append("']"); |
| } |
| } |
| } |
| |
| private static boolean areChildNodesElements(Node node) { |
| NodeList list = node.getChildNodes(); |
| for (int i = 0; i < list.getLength(); i++) { |
| if (list.item(i).getNodeType() == Node.ELEMENT_NODE) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static boolean areSiblingsOfNodeElements(Node node) { |
| NodeList list = node.getParentNode().getChildNodes(); |
| int count = 0; |
| for (int i = 0; i < list.getLength(); i++) { |
| Node item = list.item(i); |
| if (item.getNodeType() == Node.ELEMENT_NODE) { |
| count++; |
| } |
| // the first child node of type element of <ldml> should be <identity> |
| // here we figure out if any additional elements are there |
| if (count > 1) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public static boolean isLocaleAlias(Document doc) { |
| return (getAliasNode(doc) != null); |
| } |
| |
| private static Node getAliasNode(Document doc) { |
| NodeList elements = doc.getElementsByTagName(LDMLConstants.IDENTITY); |
| if (elements.getLength() == 1) { |
| Node id = elements.item(0); |
| Node sib = id; |
| while ((sib = sib.getNextSibling()) != null) { |
| if (sib.getNodeType() != Node.ELEMENT_NODE) { |
| continue; |
| } |
| if (sib.getNodeName().equals(LDMLConstants.ALIAS)) { |
| return sib; |
| } |
| } |
| } else { |
| System.out.println("Error: elements returned more than 1 identity element!"); |
| } |
| return null; |
| } |
| |
| /** |
| * Determines if the whole locale is marked draft. To accomplish this |
| * the method traverses all leaf nodes to determine if all nodes are marked draft |
| */ |
| private static boolean seenElementsOtherThanIdentity = false; |
| |
| public static final boolean isLocaleDraft(Node node) { |
| boolean isDraft = true; |
| // fast path to check if <ldml> element is draft |
| if (isNodeDraft(node) == true) { |
| return true; |
| } |
| for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { |
| if (child.getNodeType() != Node.ELEMENT_NODE) { |
| continue; |
| } |
| String name = child.getNodeName(); |
| // fast path to check if <ldml> element is draft |
| if (name.equals(LDMLConstants.LDML) && isNodeDraft(child) == true) { |
| return true; |
| } |
| if (name.equals(LDMLConstants.IDENTITY)) { |
| seenElementsOtherThanIdentity = areSiblingsOfNodeElements(child); |
| continue; |
| } |
| |
| if (child.hasChildNodes() && areChildNodesElements(child)) { |
| isDraft = isLocaleDraft(child); |
| } else { |
| if (isNodeDraft(child) == false) { |
| isDraft = false; |
| } |
| } |
| if (isDraft == false) { |
| break; |
| } |
| } |
| if (!seenElementsOtherThanIdentity) { |
| return false; |
| } |
| return isDraft; |
| } |
| |
| /** |
| * Appends the attribute values that make differentiate 2 siblings |
| * in LDML |
| * |
| * @param node |
| * @param xpath |
| * @deprecated - use version that takes StringBuilder instead |
| */ |
| @Deprecated |
| public static final void appendXPathAttribute(Node node, StringBuffer xpath) { |
| appendXPathAttribute(node, xpath, false, false); |
| } |
| |
| /** |
| * @deprecated |
| */ |
| @Deprecated |
| public static void appendXPathAttribute(Node node, StringBuffer xpath, boolean ignoreAlt, boolean ignoreDraft) { |
| StringBuilder sb = new StringBuilder(xpath.toString()); |
| appendXPathAttribute(node, sb, ignoreAlt, ignoreDraft); |
| } |
| |
| public static final void appendXPathAttribute(Node node, StringBuilder xpath) { |
| appendXPathAttribute(node, xpath, false, false); |
| } |
| |
| public static void appendXPathAttribute(Node node, StringBuilder xpath, boolean ignoreAlt, boolean ignoreDraft) { |
| boolean terminate = false; |
| String val = getAttributeValue(node, LDMLConstants.TYPE); |
| String and = "][";// " and "; |
| boolean isStart = true; |
| String name = node.getNodeName(); |
| if (val != null && !name.equals(LDMLConstants.DEFAULT) && !name.equals(LDMLConstants.MS)) { |
| if (!(val.equals("standard") && name.equals(LDMLConstants.PATTERN))) { |
| |
| if (isStart) { |
| xpath.append("["); |
| isStart = false; |
| } |
| xpath.append("@type='"); |
| xpath.append(val); |
| xpath.append("'"); |
| terminate = true; |
| } |
| } |
| if (!ignoreAlt) { |
| val = getAttributeValue(node, LDMLConstants.ALT); |
| if (val != null) { |
| if (isStart) { |
| xpath.append("["); |
| isStart = false; |
| } else { |
| xpath.append(and); |
| } |
| xpath.append("@alt='"); |
| xpath.append(val); |
| xpath.append("'"); |
| terminate = true; |
| } |
| |
| } |
| |
| if (!ignoreDraft) { |
| val = getAttributeValue(node, LDMLConstants.DRAFT); |
| if (val != null && !name.equals(LDMLConstants.LDML)) { |
| if (isStart) { |
| xpath.append("["); |
| isStart = false; |
| } else { |
| xpath.append(and); |
| } |
| xpath.append("@draft='"); |
| xpath.append(val); |
| xpath.append("'"); |
| terminate = true; |
| } |
| |
| } |
| |
| val = getAttributeValue(node, LDMLConstants.KEY); |
| if (val != null) { |
| if (isStart) { |
| xpath.append("["); |
| isStart = false; |
| } else { |
| xpath.append(and); |
| } |
| xpath.append("@key='"); |
| xpath.append(val); |
| xpath.append("'"); |
| terminate = true; |
| } |
| val = getAttributeValue(node, LDMLConstants.REGISTRY); |
| if (val != null) { |
| if (isStart) { |
| xpath.append("["); |
| isStart = false; |
| } else { |
| xpath.append(and); |
| } |
| xpath.append("@registry='"); |
| xpath.append(val); |
| xpath.append("'"); |
| terminate = true; |
| } |
| val = getAttributeValue(node, LDMLConstants.ID); |
| if (val != null) { |
| if (isStart) { |
| xpath.append("["); |
| isStart = false; |
| } else { |
| xpath.append(and); |
| } |
| xpath.append("@id='"); |
| xpath.append(val); |
| xpath.append("'"); |
| terminate = true; |
| } |
| if (terminate) { |
| xpath.append("]"); |
| } |
| } |
| |
| /** |
| * Ascertains if the children of the given node are element |
| * nodes. |
| * |
| * @param node |
| * @return |
| */ |
| public static boolean areChildrenElementNodes(Node node) { |
| NodeList list = node.getChildNodes(); |
| for (int i = 0; i < list.getLength(); i++) { |
| if (list.item(i).getNodeType() == Node.ELEMENT_NODE) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public static Node[] getNodeListAsArray(Node doc, String xpath) { |
| try { |
| NodeList list = XPathAPI_selectNodeList(doc, xpath); |
| int length = list.getLength(); |
| if (length > 0) { |
| Node[] array = new Node[length]; |
| for (int i = 0; i < length; i++) { |
| array[i] = list.item(i); |
| } |
| return array; |
| } |
| return null; |
| } catch (TransformerException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| private static Object[] getChildNodeListAsArray(Node parent, boolean exceptAlias) { |
| |
| NodeList list = parent.getChildNodes(); |
| int length = list.getLength(); |
| |
| List<Node> al = new ArrayList<Node>(); |
| for (int i = 0; i < length; i++) { |
| Node item = list.item(i); |
| if (item.getNodeType() != Node.ELEMENT_NODE) { |
| continue; |
| } |
| if (exceptAlias && item.getNodeName().equals(LDMLConstants.ALIAS)) { |
| continue; |
| } |
| al.add(item); |
| } |
| return al.toArray(); |
| |
| } |
| |
| public static Node[] toNodeArray(NodeList list) { |
| int length = list.getLength(); |
| if (length > 0) { |
| Node[] array = new Node[length]; |
| for (int i = 0; i < length; i++) { |
| array[i] = list.item(i); |
| } |
| return array; |
| } |
| return null; |
| } |
| |
| public static Node[] getElementsByTagName(Document doc, String tagName) { |
| try { |
| NodeList list = doc.getElementsByTagName(tagName); |
| int length = list.getLength(); |
| if (length > 0) { |
| Node[] array = new Node[length]; |
| for (int i = 0; i < length; i++) { |
| array[i] = list.item(i); |
| } |
| return array; |
| } |
| return null; |
| } catch (Exception ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| /** |
| * Fetches the list of nodes that match the given xpath |
| * |
| * @param doc |
| * @param xpath |
| * @return |
| */ |
| public static NodeList getNodeList(Document doc, String xpath) { |
| try { |
| return XPathAPI_selectNodeList(doc, xpath); |
| |
| } catch (TransformerException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| public static final boolean isAlternate(Node node) { |
| NamedNodeMap attributes = node.getAttributes(); |
| Node attr = attributes.getNamedItem(LDMLConstants.ALT); |
| if (attr != null) { |
| return true; |
| } |
| return false; |
| } |
| |
| private static final Node getNonAltNodeIfPossible(NodeList list) |
| { |
| // A nonalt node is one which .. does not have alternate |
| // attribute set |
| Node node = null; |
| for (int i = 0; i < list.getLength(); i++) |
| { |
| node = list.item(i); |
| if (/* !isDraft(node, xpath)&& */!isAlternate(node)) |
| { |
| return node; |
| } |
| } |
| if (list.getLength() > 0) |
| return list.item(0); // if all have alt=.... then return the first one |
| return null; |
| } |
| |
| public static Node getNonAltNodeLike(Node parent, Node child) { |
| StringBuffer childXpath = new StringBuffer(child.getNodeName()); |
| appendXPathAttribute(child, childXpath, true/* ignore alt */, true/* ignore draft */); |
| String childXPathString = childXpath.toString(); |
| for (Node other = parent.getFirstChild(); other != null; other = other.getNextSibling()) { |
| if ((other.getNodeType() != Node.ELEMENT_NODE) || (other == child)) { |
| continue; |
| } |
| StringBuffer otherXpath = new StringBuffer(other.getNodeName()); |
| appendXPathAttribute(other, otherXpath); |
| // System.out.println("Compare: " + childXpath + " to " + otherXpath); |
| if (childXPathString.equals(otherXpath.toString())) { |
| // System.out.println("Match!"); |
| return other; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Fetches the node from the document that matches the given xpath. |
| * The context namespace node is required if the xpath contains |
| * namespace elments |
| * |
| * @param doc |
| * @param xpath |
| * @param namespaceNode |
| * @return |
| */ |
| public static Node getNode(Document doc, String xpath, Node namespaceNode) { |
| try { |
| NodeList nl = XPathAPI_selectNodeList(doc, xpath, namespaceNode); |
| int len = nl.getLength(); |
| // TODO watch for attribute "alt" |
| if (len > 1) { |
| throw new IllegalArgumentException("The XPATH returned more than 1 node!. Check XPATH: " + xpath); |
| } |
| if (len == 0) { |
| return null; |
| } |
| return nl.item(0); |
| |
| } catch (TransformerException ex) { |
| ex.printStackTrace(); |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| public static Node getNode(Node context, String resToFetch, Node namespaceNode) { |
| try { |
| NodeList nl = XPathAPI_selectNodeList(context, "./" + resToFetch, namespaceNode); |
| int len = nl.getLength(); |
| // TODO watch for attribute "alt" |
| if (len > 1) { |
| throw new IllegalArgumentException("The XPATH returned more than 1 node!. Check XPATH: " + resToFetch); |
| } |
| if (len == 0) { |
| return null; |
| } |
| return nl.item(0); |
| |
| } catch (TransformerException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| /** |
| * Fetches the node from the document which matches the xpath |
| * |
| * @param node |
| * @param xpath |
| * @return |
| */ |
| public static Node getNode(Node node, String xpath) { |
| try { |
| NodeList nl = XPathAPI_selectNodeList(node, xpath); |
| int len = nl.getLength(); |
| // TODO watch for attribute "alt" |
| if (len > 1) { |
| // PN Node best = getNonAltNode(nl); |
| Node best = getNonAltNodeIfPossible(nl); // PN |
| if (best != null) { |
| // System.err.println("Chose best node from " + xpath); |
| return best; |
| } |
| /* else complain */ |
| String all = ""; |
| int i; |
| for (i = 0; i < len; i++) { |
| all = all + ", " + nl.item(i); |
| } |
| throw new IllegalArgumentException("The XPATH returned more than 1 node!. Check XPATH: " + xpath |
| + " = " + all); |
| } |
| if (len == 0) { |
| return null; |
| } |
| return nl.item(0); |
| |
| } catch (TransformerException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| public static Node getNode(Node node, String xpath, boolean preferDraft, boolean preferAlt) { |
| try { |
| NodeList nl = XPathAPI_selectNodeList(node, xpath); |
| return getNode(nl, xpath, preferDraft, preferAlt); |
| |
| } catch (TransformerException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| private static Node getVettedNode(NodeList list, StringBuffer xpath, boolean ignoreDraft) { |
| // A vetted node is one which is not draft and does not have alternate |
| // attribute set |
| Node node = null; |
| for (int i = 0; i < list.getLength(); i++) { |
| node = list.item(i); |
| if (isDraft(node, xpath) && !ignoreDraft) { |
| continue; |
| } |
| if (isAlternate(node)) { |
| continue; |
| } |
| return node; |
| } |
| return null; |
| } |
| |
| public static Node getVettedNode(Document fullyResolvedDoc, Node parent, String childName, StringBuffer xpath, |
| boolean ignoreDraft) { |
| NodeList list = getNodeList(parent, childName, fullyResolvedDoc, xpath.toString()); |
| int oldLength = xpath.length(); |
| Node ret = null; |
| |
| if (list != null && list.getLength() > 0) { |
| xpath.append("/"); |
| xpath.append(childName); |
| ret = getVettedNode(list, xpath, ignoreDraft); |
| } |
| xpath.setLength(oldLength); |
| return ret; |
| } |
| |
| public static Node getNode(NodeList nl, String xpath, boolean preferDraft, boolean preferAlt) { |
| int len = nl.getLength(); |
| // TODO watch for attribute "alt" |
| if (len > 1) { |
| Node best = null; |
| for (int i = 0; i < len; i++) { |
| Node current = nl.item(i); |
| if (!preferDraft && !preferAlt) { |
| if (!isNodeDraft(current) && !isAlternate(current)) { |
| best = current; |
| break; |
| } |
| continue; |
| } else if (preferDraft && !preferAlt) { |
| if (isNodeDraft(current) && !isAlternate(current)) { |
| best = current; |
| break; |
| } |
| continue; |
| } else if (!preferDraft && preferAlt) { |
| if (!isNodeDraft(current) && isAlternate(current)) { |
| best = current; |
| break; |
| } |
| continue; |
| } else { |
| if (isNodeDraft(current) || isAlternate(current)) { |
| best = current; |
| break; |
| } |
| continue; |
| } |
| } |
| if (best == null && preferDraft == true) { |
| best = getVettedNode(nl, new StringBuffer(xpath), false); |
| } |
| if (best != null) { |
| return best; |
| } |
| /* else complain */ |
| String all = ""; |
| int i; |
| for (i = 0; i < len; i++) { |
| all = all + ", " + nl.item(i); |
| } |
| throw new IllegalArgumentException("The XPATH returned more than 1 node!. Check XPATH: " + xpath + " = " |
| + all); |
| } |
| if (len == 0) { |
| return null; |
| } |
| return nl.item(0); |
| |
| } |
| |
| /** |
| * |
| * @param context |
| * @param resToFetch |
| * @param fullyResolved |
| * @param xpath |
| * @return |
| */ |
| public static Node getNode(Node context, String resToFetch, Document fullyResolved, String xpath) { |
| String ctx = "./" + resToFetch; |
| Node node = getNode(context, ctx); |
| if (node == null && fullyResolved != null) { |
| // try from fully resolved |
| String path = xpath + "/" + resToFetch; |
| node = getNode(fullyResolved, path); |
| } |
| return node; |
| } |
| |
| /** |
| * |
| * @param context |
| * @param resToFetch |
| * @return |
| */ |
| public static NodeList getChildNodes(Node context, String resToFetch) { |
| String ctx = "./" + resToFetch; |
| NodeList list = getNodeList(context, ctx); |
| return list; |
| } |
| |
| /** |
| * Fetches the node from the document that matches the given xpath. |
| * The context namespace node is required if the xpath contains |
| * namespace elments |
| * |
| * @param doc |
| * @param xpath |
| * @param namespaceNode |
| * @return |
| */ |
| public static NodeList getNodeList(Document doc, String xpath, Node namespaceNode) { |
| try { |
| NodeList nl = XPathAPI_selectNodeList(doc, xpath, namespaceNode); |
| if (nl.getLength() == 0) { |
| return null; |
| } |
| return nl; |
| |
| } catch (TransformerException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| /** |
| * Fetches the node from the document which matches the xpath |
| * |
| * @param node |
| * @param xpath |
| * @return |
| */ |
| public static NodeList getNodeList(Node node, String xpath) { |
| try { |
| NodeList nl = XPathAPI_selectNodeList(node, xpath); |
| int len = nl.getLength(); |
| if (len == 0) { |
| return null; |
| } |
| return nl; |
| } catch (TransformerException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| /** |
| * Fetches node list from the children of the context node. |
| * |
| * @param context |
| * @param resToFetch |
| * @param fullyResolved |
| * @param xpath |
| * @return |
| */ |
| public static NodeList getNodeList(Node context, String resToFetch, Document fullyResolved, String xpath) { |
| String ctx = "./" + resToFetch; |
| NodeList list = getNodeList(context, ctx); |
| if ((list == null || list.getLength() > 0) && fullyResolved != null) { |
| // try from fully resolved |
| String path = xpath + "/" + resToFetch; |
| list = getNodeList(fullyResolved, path); |
| } |
| return list; |
| } |
| |
| /** |
| * Decide if the node is text, and so must be handled specially |
| * |
| * @param n |
| * @return |
| */ |
| public static Node getAttributeNode(Node sNode, String attribName) { |
| NamedNodeMap attrs = sNode.getAttributes(); |
| if (attrs != null) { |
| return attrs.getNamedItem(attribName); |
| } |
| return null; |
| } |
| |
| /** |
| * Utility method to fetch the attribute value from the given |
| * element node |
| * |
| * @param sNode |
| * @param attribName |
| * @return |
| */ |
| public static String getAttributeValue(Node sNode, String attribName) { |
| String value = null; |
| NamedNodeMap attrs = sNode.getAttributes(); |
| if (attrs != null) { |
| Node attr = attrs.getNamedItem(attribName); |
| if (attr != null) { |
| value = attr.getNodeValue(); |
| } |
| } |
| return value; |
| } |
| |
| /** |
| * Utility method to set the attribute value on the given |
| * element node |
| * |
| * @param sNode |
| * @param attribName |
| * @param val |
| */ |
| public static void setAttributeValue(Node sNode, String attribName, String val) { |
| |
| Node attr = sNode.getAttributes().getNamedItem(attribName); |
| if (attr != null) { |
| attr.setNodeValue(val); |
| } else { |
| attr = sNode.getOwnerDocument().createAttribute(attribName); |
| attr.setNodeValue(val); |
| sNode.getAttributes().setNamedItem(attr); |
| } |
| } |
| |
| /** |
| * Utility method to fetch the value of the element node |
| * |
| * @param node |
| * @return |
| */ |
| public static String getNodeValue(Node node) { |
| for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { |
| if (child.getNodeType() == Node.TEXT_NODE) { |
| return child.getNodeValue(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Parse & resolve file level alias |
| */ |
| public static Document parseAndResolveAlias(String filename, String locale, boolean ignoreError) |
| throws RuntimeException { |
| // Force filerefs to be URI's if needed: note this is independent of any other files |
| String docURI = filenameToURL(filename); |
| Document doc = parse(new InputSource(docURI), filename, ignoreError); |
| NodeList elements = doc.getElementsByTagName(LDMLConstants.IDENTITY); |
| if (elements.getLength() == 1) { |
| Node id = elements.item(0); |
| Node sib = id; |
| while ((sib = sib.getNextSibling()) != null) { |
| if (sib.getNodeType() != Node.ELEMENT_NODE) { |
| continue; |
| } |
| if (sib.getNodeName().equals(LDMLConstants.ALIAS)) { |
| resolveAliases(doc, filename.substring(0, filename.lastIndexOf(File.separator) + 1), locale, false, |
| null); |
| } |
| } |
| } else { |
| System.out.println("Error: elements returned more than 1 identity element!"); |
| } |
| if (DEBUG) { |
| try { |
| java.io.OutputStreamWriter writer = new java.io.OutputStreamWriter( |
| new java.io.FileOutputStream("./" + File.separator + locale |
| + "_debug_1.xml"), "UTF-8"); |
| LDMLUtilities.printDOMTree(doc, new PrintWriter(writer), |
| "http://www.unicode.org/cldr/dtd/1.3/ldml.dtd", null); |
| writer.flush(); |
| } catch (IOException e) { |
| // throw the exceptionaway .. this is for debugging |
| } |
| } |
| return doc; |
| } |
| |
| /** |
| * Simple worker method to parse filename to a Document. |
| * |
| * Attempts XML parse, then HTML parse (when parser available), |
| * then just parses as text and sticks into a text node. |
| * |
| * @param filename |
| * to parse as a local path |
| * |
| * @return Document object with contents of the file; |
| * otherwise throws an unchecked RuntimeException if there |
| * is any fatal problem |
| */ |
| public static Document parse(String filename, boolean ignoreError) throws RuntimeException { |
| // Force filerefs to be URI's if needed: note this is independent of any other files |
| String docURI = filenameToURL(filename); |
| return parse(new InputSource(docURI), filename, ignoreError); |
| } |
| |
| public static Document parseAndResolveAliases(String locale, String sourceDir, boolean ignoreError, |
| boolean ignoreDraft) { |
| try { |
| Document full = parse(sourceDir + File.separator + locale, ignoreError); |
| if (full != null) { |
| full = resolveAliases(full, sourceDir, locale, ignoreDraft, null); |
| } |
| /* |
| * Debugging |
| * |
| * Node[] list = getNodeArray(full, LDMLConstants.ALIAS); |
| * if(list.length>0){ |
| * System.err.println("Aliases not resolved!. list.getLength() returned "+ list.length); |
| * } |
| */ |
| return full; |
| } catch (Exception ex) { |
| if (!ignoreError) { |
| ex.printStackTrace(); |
| throw new RuntimeException(ex); |
| } |
| } |
| return null; |
| |
| } |
| |
| private static ErrorHandler getNullErrorHandler(final String filename2, final boolean ignoreError) { |
| // Local class: cheap non-printing ErrorHandler |
| // This is used to suppress validation warnings |
| ErrorHandler nullHandler = new ErrorHandler() { |
| public void warning(SAXParseException e) throws SAXException { |
| int col = e.getColumnNumber(); |
| String msg = (filename2 + ":" + e.getLineNumber() |
| + (col >= 0 ? ":" + col : "") + ": WARNING: " |
| + e.getMessage()); |
| |
| System.err.println(msg); |
| if (!ignoreError) { |
| throw new RuntimeException(msg); |
| } |
| } |
| |
| public void error(SAXParseException e) throws SAXException { |
| int col = e.getColumnNumber(); |
| String msg = (filename2 + ":" + e.getLineNumber() |
| + (col >= 0 ? ":" + col : "") + ": ERROR: " |
| + e.getMessage()); |
| System.err.println(msg); |
| if (!ignoreError) { |
| throw new RuntimeException(msg); |
| } |
| } |
| |
| public void fatalError(SAXParseException e) throws SAXException { |
| throw e; |
| } |
| }; |
| return nullHandler; |
| } |
| |
| public static Document newDocument() { |
| return newDocumentBuilder(false).newDocument(); |
| } |
| |
| private static DocumentBuilder newDocumentBuilder(boolean validating) { |
| try |
| { |
| DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); |
| // Always set namespaces on |
| dfactory.setNamespaceAware(true); |
| dfactory.setValidating(validating); |
| dfactory.setIgnoringComments(false); |
| dfactory.setExpandEntityReferences(true); |
| // Set other attributes here as needed |
| // applyAttributes(dfactory, attributes); |
| |
| DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); |
| docBuilder.setEntityResolver(new CachingEntityResolver()); |
| return docBuilder; |
| } catch (Throwable se) { |
| System.err.println(": ERROR : trying to create documentBuilder: " + se.getMessage()); |
| se.printStackTrace(); |
| throw new RuntimeException(se); |
| } |
| } |
| |
| public static Document parse(InputSource docSrc, String filename, boolean ignoreError) { |
| Document doc = null; |
| try |
| { |
| // First, attempt to parse as XML (preferred)... |
| DocumentBuilder docBuilder = newDocumentBuilder(true); |
| docBuilder.setErrorHandler(getNullErrorHandler(filename, ignoreError)); |
| doc = docBuilder.parse(docSrc); |
| } catch (Throwable se) |
| { |
| // ... if we couldn't parse as XML, attempt parse as HTML... |
| System.err.println(filename + ": ERROR :" + se.getMessage()); |
| se.printStackTrace(); |
| if (!ignoreError) { |
| throw new RuntimeException(se); |
| } |
| } |
| return doc; |
| } // end of parse() |
| |
| /* |
| * Utility method to translate a String filename to URL. |
| * |
| * Note: This method is not necessarily proven to get the |
| * correct URL for every possible kind of filename; it should |
| * be improved. It handles the most common cases that we've |
| * encountered when running Conformance tests on Xalan. |
| * Also note, this method does not handle other non-file: |
| * flavors of URLs at all. |
| * |
| * If the name is null, return null. |
| * If the name starts with a common URI scheme (namely the ones |
| * found in the examples of RFC2396), then simply return the |
| * name as-is (the assumption is that it's already a URL) |
| * Otherwise we attempt (cheaply) to convert to a file:/// URL. |
| */ |
| public static String filenameToURL(String filename) { |
| // null begets null - something like the commutative property |
| if (null == filename) { |
| return null; |
| } |
| |
| // Don't translate a string that already looks like a URL |
| if (filename.startsWith("file:") |
| || filename.startsWith("http:") |
| || filename.startsWith("ftp:") |
| || filename.startsWith("gopher:") |
| || filename.startsWith("mailto:") |
| || filename.startsWith("news:") |
| || filename.startsWith("telnet:")) { |
| return filename; |
| } |
| |
| File f = new File(filename); |
| String tmp = null; |
| try { |
| // This normally gives a better path |
| tmp = f.getCanonicalPath(); |
| } catch (IOException ioe) { |
| // But this can be used as a backup, for cases |
| // where the file does not exist, etc. |
| tmp = f.getAbsolutePath(); |
| } |
| |
| // URLs must explicitly use only forward slashes |
| if (File.separatorChar == '\\') { |
| tmp = tmp.replace('\\', '/'); |
| } |
| // Note the presumption that it's a file reference |
| // Ensure we have the correct number of slashes at the |
| // start: we always want 3 /// if it's absolute |
| // (which we should have forced above) |
| if (tmp.startsWith("/")) { |
| return "file://" + tmp; |
| } |
| else { |
| return "file:///" + tmp; |
| } |
| } |
| |
| /** |
| * Debugging method for printing out the DOM Tree |
| * Prints the specified node, recursively. |
| * |
| * @param node |
| * @param out |
| * @throws IOException |
| */ |
| public static void printDOMTree(Node node, PrintWriter out, String docType, String copyright) throws IOException |
| { |
| try { |
| Transformer transformer = TransformerFactory.newInstance().newTransformer(); |
| transformer.setOutputProperty(OutputKeys.INDENT, "yes"); |
| transformer.setOutputProperty(OutputKeys.METHOD, "xml"); |
| transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); |
| |
| transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); |
| out.print("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); |
| if (copyright != null) { |
| out.print(copyright); |
| } |
| if (docType != null) { |
| out.print(docType); |
| } |
| |
| // transformer.setParameter(entityName, entityRef ); |
| // transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, XLIFF_PUBLIC_NAME); |
| transformer.transform(new DOMSource(node), new StreamResult(out)); |
| } catch (TransformerException te) { |
| throw new IOException(te.getMessage()); |
| } |
| |
| // out.close(); |
| } // printDOMTree(Node, PrintWriter) |
| |
| // Utility functions, HTML and such. |
| public static String CVSBASE = "http://www.unicode.org/cldr/trac/browser/trunk"; |
| |
| public static final String getCVSLink(String locale) |
| { |
| return "<a href=\"" + CVSBASE + "/common/main/" + locale + ".xml\">"; |
| } |
| |
| public static final String getCVSLink(String locale, String version) |
| { |
| return "<a href=\"" + CVSBASE + "/common/main/" + locale + ".xml?rev=" + |
| version + "\">"; |
| |
| } |
| |
| /** |
| * Load the revision from CVS or from the Identity element. |
| * |
| * @param fileName |
| * @return |
| */ |
| static public String loadFileRevision(String fileName) |
| { |
| int index = fileName.lastIndexOf(File.separatorChar); |
| if (index == -1) { |
| return null; |
| } |
| String sourceDir = fileName.substring(0, index); |
| return loadFileRevision(sourceDir, new File(fileName).getName()); |
| } |
| |
| // //ldml[@version="1.7"]/identity/version[@number="$Revision: 12133 $"] |
| // private static Pattern VERSION_PATTERN = |
| // PatternCache.get("//ldml[^/]*/identity/version\\[@number=\"[^0-9]*\\([0-9.]+\\).*"); |
| private static Pattern VERSION_PATTERN = PatternCache.get(".*identity/version.*Revision[: ]*([0-9.]*).*"); |
| |
| /** |
| * Load the revision from CVS or from the Identity element. |
| * |
| * @param sourceDir |
| * @param fileName |
| * @return |
| */ |
| static public String loadFileRevision(String sourceDir, String fileName) { |
| String aVersion = null; |
| File entriesFile = new File(sourceDir + File.separatorChar + "CVS", "Entries"); |
| if (entriesFile.exists() && entriesFile.canRead()) { |
| try { |
| BufferedReader r = new BufferedReader(new FileReader(entriesFile.getPath())); |
| String s; |
| while ((s = r.readLine()) != null) { |
| String lookFor = "/" + fileName + "/"; |
| if (s.startsWith(lookFor)) { |
| String ver = s.substring(lookFor.length()); |
| ver = ver.substring(0, ver.indexOf('/')); |
| aVersion = ver; |
| } |
| } |
| r.close(); |
| } catch (Throwable th) { |
| System.err.println(th.toString() + " trying to read CVS Entries file " + entriesFile.getPath()); |
| return null; |
| } |
| } else { |
| // no CVS, use file ident. |
| File xmlFile = new File(sourceDir, fileName); |
| if (!xmlFile.exists()) return null; |
| final String bVersion[] = { "unknown" }; |
| try { |
| XMLFileReader xfr = new XMLFileReader().setHandler(new SimpleHandler() { |
| private boolean done = false; |
| |
| // public void handleAttributeDecl(String eName, String aName, String type, String mode, String |
| // value) { |
| public void handlePathValue(String p, String v) { |
| if (!done) { |
| Matcher m = VERSION_PATTERN.matcher(p); |
| if (m.matches()) { |
| // System.err.println("Matches! "+p+" = "+m.group(1)); |
| bVersion[0] = m.group(1); |
| done = true; |
| } |
| } |
| } |
| }); |
| xfr.read(xmlFile.getPath(), -1, true); |
| aVersion = bVersion[0]; // copy from input param |
| } catch (Throwable t) { |
| t.printStackTrace(); |
| aVersion = "err"; |
| System.err.println("Error reading version of " + xmlFile.getAbsolutePath() + ": " + t.toString()); |
| } |
| } |
| // System.err.println("v="+aVersion); |
| return aVersion; |
| } |
| |
| // // Caching Resolution |
| // private static File getCacheName(String sourceDir, String last, String loc) |
| // { |
| // //File xCacheDir = new |
| // File((CachingEntityResolver.getCacheDir()!=null)?CachingEntityResolver.getCacheDir():"/tmp/cldrres"); |
| // return new File(sourceDir).getName() + "_" + last + "." + loc; |
| // } |
| |
| // Document readMergeCache(String sourceDir, String last, String loc) |
| // { |
| // File cacheName = getCacheName(String sourceDir, last, loc); |
| // System.out.println(" M: " + cacheName); |
| // File cacheFile = new File(xCacheDir, cacheName + ".xml"); |
| // if(cacheFile.exists()) { // && is newer than last, loc |
| // doc = parse(cacheFile.getPath(),ignoreUnavailable); |
| // } |
| // if(doc!=null) { |
| // System.out.println("Cache hit for " + cacheName); |
| // } |
| // return doc; |
| // } |
| |
| // void writeMergeCache(String sourceDir, String last, String loc, Document full) |
| // { |
| // try { |
| // OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(cacheFile),"UTF-8"); |
| // PrintWriter pw = new PrintWriter(writer); |
| // printDOMTree(full,pw); |
| // long stop = System.currentTimeMillis(); |
| // long total = (stop-start); |
| // double s = total/1000.; |
| // System.out.println(" " + cacheName + " parse time: " + s + "s"); |
| // pw.println("<!-- " + cacheName + " parse time: " + s + "s -->"); |
| // writer.close(); |
| // } catch (Throwable t) { |
| // System.err.println(t.toString() + " while trying to write cache file " + cacheName); |
| // } |
| // } |
| |
| public static String getFullPath(int fileType, String fName, String dir) { |
| String str = null; |
| int lastIndex1 = fName.lastIndexOf(File.separator, fName.length()) + 1/* add 1 to skip past the separator */; |
| int lastIndex2 = fName.lastIndexOf('.', fName.length()); |
| if (fileType == TXT) { |
| if (lastIndex2 == -1) { |
| fName = fName.trim() + ".txt"; |
| } else { |
| if (!fName.substring(lastIndex2).equalsIgnoreCase(".txt")) { |
| fName = fName.substring(lastIndex1, lastIndex2) + ".txt"; |
| } |
| } |
| if (dir != null && fName != null) { |
| str = dir + "/" + fName.trim(); |
| } else { |
| str = System.getProperty("user.dir") + "/" + fName.trim(); |
| } |
| } else if (fileType == XML) { |
| if (lastIndex2 == -1) { |
| fName = fName.trim() + ".xml"; |
| } else { |
| if (!fName.substring(lastIndex2).equalsIgnoreCase(".xml") |
| && fName.substring(lastIndex2).equalsIgnoreCase(".xlf")) { |
| fName = fName.substring(lastIndex1, lastIndex2) + ".xml"; |
| } |
| } |
| if (dir != null && fName != null) { |
| str = dir + "/" + fName; |
| } else if (lastIndex1 > 0) { |
| str = fName; |
| } else { |
| str = System.getProperty("user.dir") + "/" + fName; |
| } |
| } else { |
| System.err.println("Invalid file type."); |
| System.exit(-1); |
| } |
| return str; |
| } |
| |
| /** |
| * split an alt= tag into pieces. Any piece can be missing (== null) |
| * Piece 0: 'alt type'. null means this is the normal (non-alt) item. Possible values are 'alternate', 'colloquial', |
| * etc. |
| * Piece 1: 'proposed type'. If non-null, this is a string beginning with 'proposed' and containing arbitrary other |
| * text. |
| * |
| * STRING 0 1 |
| * ------------------------------- |
| * ""/null null null |
| * something something null |
| * something-proposed something proposed |
| * something-proposed3 something proposed3 |
| * proposed null proposed |
| * somethingproposed somethingproposed null |
| * |
| * |
| * @param alt |
| * the alt tag to parse |
| * @return a 2-element array containing piece 0 and piece 1 |
| * @see formatAlt |
| */ |
| public static String[] parseAlt(String alt) { |
| String[] ret = new String[2]; |
| if (alt == null) { |
| ret[0] = null; |
| ret[1] = null; |
| } else { |
| int l = alt.indexOf(LDMLConstants.PROPOSED); |
| if (l == -1) { /* no PROPOSED */ |
| ret[0] = alt; // all alt, |
| ret[1] = null; // no kind |
| } else if (l == 0) { /* begins with */ |
| ret[0] = null; // all properties |
| ret[1] = alt; |
| } else { |
| if (alt.charAt(l - 1) != '-') { |
| throw new InternalError("Expected '-' before " + LDMLConstants.PROPOSED + " in " + alt); |
| } |
| ret[0] = alt.substring(0, l - 1); |
| ret[1] = alt.substring(l); |
| |
| if (ret[0].length() == 0) { |
| ret[0] = null; |
| } |
| if (ret[1].length() == 0) { |
| ret[1] = null; |
| } |
| } |
| } |
| return ret; |
| } |
| |
| /** |
| * Format aan alt string from components. |
| * |
| * @param altType |
| * optional alternate type (i.e. 'alternate' or 'colloquial'). |
| * @param proposedType |
| * @see parseAlt |
| */ |
| public static String formatAlt(String altType, String proposedType) { |
| |
| if (((altType == null) || (altType.length() == 0)) && |
| ((proposedType == null) || (proposedType.length() == 0))) { |
| return null; |
| } |
| |
| if ((proposedType == null) || (proposedType.length() == 0)) { |
| return altType; // no proposed type: 'alternate' |
| } else if (!proposedType.startsWith(LDMLConstants.PROPOSED)) { |
| throw new InternalError("proposedType must begin with " + LDMLConstants.PROPOSED); |
| } |
| |
| if ((altType == null) || (altType.length() == 0)) { |
| return proposedType; // Just a proposed type: "proposed" or "proposed-3" |
| } else { |
| return altType + "-" + proposedType; // 'alternate-proposed' |
| } |
| } |
| |
| /** |
| * Compatibility. |
| * |
| * @param node |
| * @param xpath |
| * @return |
| * @throws TransformerException |
| */ |
| private static NodeList XPathAPI_selectNodeList(Node node, String xpath) throws TransformerException { |
| XPathFactory factory = XPathFactory.newInstance(); |
| XPath xPath = factory.newXPath(); |
| setNamespace(xPath, xpath); |
| try { |
| XPathExpression xPathExpression = |
| xPath.compile(xpath); |
| return (NodeList) xPathExpression.evaluate(node, XPathConstants.NODESET); |
| } catch (XPathExpressionException e) { |
| throw new TransformerException("Exception in XPathAPI_selectNodeList: " + xpath, e); |
| } |
| } |
| |
| private static NodeList XPathAPI_selectNodeList(Document doc, String xpath, |
| Node namespaceNode) throws TransformerException { |
| XPathFactory factory = XPathFactory.newInstance(); |
| XPath xPath = factory.newXPath(); |
| setNamespace(xPath, xpath); |
| try { |
| XPathExpression xPathExpression = |
| xPath.compile(xpath); |
| return (NodeList) xPathExpression.evaluate(doc, XPathConstants.NODESET); |
| } catch (XPathExpressionException e) { |
| throw new TransformerException("Exception in XPathAPI_selectNodeList: " + xpath, e); |
| } |
| } |
| |
| private static NodeList XPathAPI_selectNodeList(Node context, String xpath, |
| Node namespaceNode) throws TransformerException { |
| XPathFactory factory = XPathFactory.newInstance(); |
| XPath xPath = factory.newXPath(); |
| setNamespace(xPath, xpath); |
| try { |
| XPathExpression xPathExpression = |
| xPath.compile(xpath); |
| return (NodeList) xPathExpression.evaluate(context, XPathConstants.NODESET); |
| } catch (XPathExpressionException e) { |
| throw new TransformerException("Exception in XPathAPI_selectNodeList: " + xpath, e); |
| } |
| } |
| |
| private static void XPathAPI_eval(Node context, String string, |
| Node namespaceNode) throws TransformerException { |
| XPathAPI_selectNodeList(context, string, namespaceNode); |
| } |
| |
| private static void XPathAPI_eval(Node context, String string) throws TransformerException { |
| XPathAPI_selectNodeList(context, string); |
| } |
| |
| private static void setNamespace(XPath xpath, String string) { |
| if (string.contains("special/icu:")) { |
| xpath.setNamespaceContext(new javax.xml.namespace.NamespaceContext() { |
| public String getNamespaceURI(String prefix) { |
| if (prefix.equals("icu")) { |
| return "http://www.icu-project.org"; |
| } |
| return null; |
| } |
| |
| public String getPrefix(String namespaceURI) { |
| return null; |
| } |
| |
| public Iterator<Object> getPrefixes(String namespaceURI) { |
| return null; |
| } |
| }); |
| } |
| } |
| } |